From 11e1312e3a6c831b35745b2e8aef657048fd470a Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Date: Fri, 18 Mar 2022 14:42:42 +0100 Subject: [PATCH 001/658] feat: inital commit --- .gitignore | 4 + README.md | 1 + next-env.d.ts | 5 + package.json | 27 ++++++ src/pages/api/auth/[...nextauth].ts | 33 +++++++ src/pages/api/jwt.ts | 12 +++ src/pages/api/protected.ts | 18 ++++ src/pages/api/session.ts | 8 ++ tsconfig.json | 23 +++++ yarn.lock | 137 ++++++++++++++++++++++++++++ 10 files changed, 268 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 next-env.d.ts create mode 100644 package.json create mode 100644 src/pages/api/auth/[...nextauth].ts create mode 100644 src/pages/api/jwt.ts create mode 100644 src/pages/api/protected.ts create mode 100644 src/pages/api/session.ts create mode 100644 tsconfig.json create mode 100644 yarn.lock diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..2c84f790ce --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +dist +node_modules/ +.env +.next diff --git a/README.md b/README.md new file mode 100644 index 0000000000..32514baf22 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# Cal.com Public API (Enterprise Only) diff --git a/next-env.d.ts b/next-env.d.ts new file mode 100644 index 0000000000..4f11a03dc6 --- /dev/null +++ b/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/package.json b/package.json new file mode 100644 index 0000000000..297108c12e --- /dev/null +++ b/package.json @@ -0,0 +1,27 @@ +{ + "name": "@calcom/api", + "version": "1.0.0", + "description": "Public API for Cal.com", + "main": "index.ts", + "repository": "git@github.com:calcom/api.git", + "author": "Cal.com Inc.", + "private": true, + "scripts": { + "dev": "PORT=3002 next", + "start": "next start", + "build": "next build", + "lint": "next lint", + "type-check": "tsc --pretty --noEmit", + "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist" + }, + "devDependencies": { + "@calcom/prisma": "*", + "@calcom/tsconfig": "*", + "scripts": "*", + "typescript": "^4.5.3" + }, + "dependencies": { + "@next-auth/prisma-adapter": "^1.0.1", + "next": "^12.1.0" + } +} \ No newline at end of file diff --git a/src/pages/api/auth/[...nextauth].ts b/src/pages/api/auth/[...nextauth].ts new file mode 100644 index 0000000000..543d94f7d1 --- /dev/null +++ b/src/pages/api/auth/[...nextauth].ts @@ -0,0 +1,33 @@ +import { PrismaAdapter } from "@next-auth/prisma-adapter"; +import NextAuth from "next-auth"; +import EmailProvider from "next-auth/providers/email"; + +import { defaultCookies } from "@calcom/lib/default-cookies"; +import { serverConfig } from "@calcom/lib/serverConfig"; +import prisma from "@calcom/prisma"; + +const WEBSITE_BASE_URL = process.env.WEBSITE_BASE_URL || ""; + + +export default NextAuth({ + adapter: PrismaAdapter(prisma), + providers: [ + EmailProvider({ + maxAge: 10 * 60 * 60, // Magic links are valid for 10 min only + // sendVerificationRequest, + }), + ], + secret: process.env.SECRET, + cookies: defaultCookies(WEBSITE_BASE_URL?.startsWith("https://")), + session: { + strategy: "jwt", + }, + jwt: { + // A secret to use for key generation (you should set this explicitly) + secret: process.env.SECRET, + // Set to true to use encryption (default: false) + // encryption: true, + }, + // Enable debug messages in the console if you are having problems + debug: true, +}); diff --git a/src/pages/api/jwt.ts b/src/pages/api/jwt.ts new file mode 100644 index 0000000000..f33002aad6 --- /dev/null +++ b/src/pages/api/jwt.ts @@ -0,0 +1,12 @@ +import type { NextApiRequest, NextApiResponse } from "next" +import { getToken } from "next-auth/jwt"; + +const secret = process.env.NEXTAUTH_SECRET; + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + // if using `NEXTAUTH_SECRET` env variable, we detect it, and you won't actually need to `secret` + // const token = await getToken({ req }) + const token = await getToken({ req, secret, raw: true }); + console.log("JSON Web Token", token); + res.end() +} \ No newline at end of file diff --git a/src/pages/api/protected.ts b/src/pages/api/protected.ts new file mode 100644 index 0000000000..27e06b9ea0 --- /dev/null +++ b/src/pages/api/protected.ts @@ -0,0 +1,18 @@ +// This is an example of to protect an API route +import { getSession } from "next-auth/react" +import type { NextApiRequest, NextApiResponse } from "next" + +export default async (req: NextApiRequest, res: NextApiResponse) => { + const session = await getSession({ req }) + + if (session) { + res.send({ + content: + "This is protected content. You can access this content because you are signed in.", + }) + } else { + res.send({ + error: "You must be signed in to view the protected content on this page.", + }) + } +}; diff --git a/src/pages/api/session.ts b/src/pages/api/session.ts new file mode 100644 index 0000000000..2a1551dd0e --- /dev/null +++ b/src/pages/api/session.ts @@ -0,0 +1,8 @@ +// This is an example of how to access a session from an API route +import { getSession } from "next-auth/react" +import type { NextApiRequest, NextApiResponse } from "next" + +export default async (req: NextApiRequest, res: NextApiResponse) => { + const session = await getSession({ req }) + res.send(JSON.stringify(session, null, 2)) +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000000..fd9c2c4aee --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,23 @@ +{ + "extends": "@calcom/tsconfig/base.json", + "compilerOptions": { + "lib": [ + "ES2015" + ], + "module": "CommonJS", + "outDir": "./dist", + "rootDir": "./src", + "target": "es5", + "allowJs": true, + "noEmit": true, + "incremental": true, + "resolveJsonModule": true, + "jsx": "preserve" + }, + "exclude": [ + "node_modules" + ], + "include": [ + "src" + ] +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000000..bc4aae706e --- /dev/null +++ b/yarn.lock @@ -0,0 +1,137 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@next/env@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/env/-/env-12.1.0.tgz#73713399399b34aa5a01771fb73272b55b22c314" + integrity sha512-nrIgY6t17FQ9xxwH3jj0a6EOiQ/WDHUos35Hghtr+SWN/ntHIQ7UpuvSi0vaLzZVHQWaDupKI+liO5vANcDeTQ== + +"@next/swc-android-arm64@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.1.0.tgz#865ba3a9afc204ff2bdeea49dd64d58705007a39" + integrity sha512-/280MLdZe0W03stA69iL+v6I+J1ascrQ6FrXBlXGCsGzrfMaGr7fskMa0T5AhQIVQD4nA/46QQWxG//DYuFBcA== + +"@next/swc-darwin-arm64@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.0.tgz#08e8b411b8accd095009ed12efbc2f1d4d547135" + integrity sha512-R8vcXE2/iONJ1Unf5Ptqjk6LRW3bggH+8drNkkzH4FLEQkHtELhvcmJwkXcuipyQCsIakldAXhRbZmm3YN1vXg== + +"@next/swc-darwin-x64@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.0.tgz#fcd684497a76e8feaca88db3c394480ff0b007cd" + integrity sha512-ieAz0/J0PhmbZBB8+EA/JGdhRHBogF8BWaeqR7hwveb6SYEIJaDNQy0I+ZN8gF8hLj63bEDxJAs/cEhdnTq+ug== + +"@next/swc-linux-arm-gnueabihf@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.0.tgz#9ec6380a27938a5799aaa6035c205b3c478468a7" + integrity sha512-njUd9hpl6o6A5d08dC0cKAgXKCzm5fFtgGe6i0eko8IAdtAPbtHxtpre3VeSxdZvuGFh+hb0REySQP9T1ttkog== + +"@next/swc-linux-arm64-gnu@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.0.tgz#7f4196dff1049cea479607c75b81033ae2dbd093" + integrity sha512-OqangJLkRxVxMhDtcb7Qn1xjzFA3s50EIxY7mljbSCLybU+sByPaWAHY4px97ieOlr2y4S0xdPKkQ3BCAwyo6Q== + +"@next/swc-linux-arm64-musl@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.0.tgz#b445f767569cdc2dddee785ca495e1a88c025566" + integrity sha512-hB8cLSt4GdmOpcwRe2UzI5UWn6HHO/vLkr5OTuNvCJ5xGDwpPXelVkYW/0+C3g5axbDW2Tym4S+MQCkkH9QfWA== + +"@next/swc-linux-x64-gnu@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.0.tgz#67610e9be4fbc987de7535f1bcb17e45fe12f90e" + integrity sha512-OKO4R/digvrVuweSw/uBM4nSdyzsBV5EwkUeeG4KVpkIZEe64ZwRpnFB65bC6hGwxIBnTv5NMSnJ+0K/WmG78A== + +"@next/swc-linux-x64-musl@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.0.tgz#ea19a23db08a9f2e34ac30401f774cf7d1669d31" + integrity sha512-JohhgAHZvOD3rQY7tlp7NlmvtvYHBYgY0x5ZCecUT6eCCcl9lv6iV3nfu82ErkxNk1H893fqH0FUpznZ/H3pSw== + +"@next/swc-win32-arm64-msvc@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.0.tgz#eadf054fc412085659b98e145435bbba200b5283" + integrity sha512-T/3gIE6QEfKIJ4dmJk75v9hhNiYZhQYAoYm4iVo1TgcsuaKLFa+zMPh4056AHiG6n9tn2UQ1CFE8EoybEsqsSw== + +"@next/swc-win32-ia32-msvc@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.0.tgz#68faeae10c89f698bf9d28759172b74c9c21bda1" + integrity sha512-iwnKgHJdqhIW19H9PRPM9j55V6RdcOo6rX+5imx832BCWzkDbyomWnlzBfr6ByUYfhohb8QuH4hSGEikpPqI0Q== + +"@next/swc-win32-x64-msvc@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.0.tgz#d27e7e76c87a460a4da99c5bfdb1618dcd6cd064" + integrity sha512-aBvcbMwuanDH4EMrL2TthNJy+4nP59Bimn8egqv6GHMVj0a44cU6Au4PjOhLNqEh9l+IpRGBqMTzec94UdC5xg== + +"@types/node@^17.0.21": + version "17.0.21" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.21.tgz#864b987c0c68d07b4345845c3e63b75edd143644" + integrity sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ== + +caniuse-lite@^1.0.30001283: + version "1.0.30001317" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001317.tgz#0548fb28fd5bc259a70b8c1ffdbe598037666a1b" + integrity sha512-xIZLh8gBm4dqNX0gkzrBeyI86J2eCjWzYAs40q88smG844YIrN4tVQl/RhquHvKEKImWWFIVh1Lxe5n1G/N+GQ== + +nanoid@^3.1.30: + version "3.3.1" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" + integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== + +next@^12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/next/-/next-12.1.0.tgz#c33d753b644be92fc58e06e5a214f143da61dd5d" + integrity sha512-s885kWvnIlxsUFHq9UGyIyLiuD0G3BUC/xrH0CEnH5lHEWkwQcHOORgbDF0hbrW9vr/7am4ETfX4A7M6DjrE7Q== + dependencies: + "@next/env" "12.1.0" + caniuse-lite "^1.0.30001283" + postcss "8.4.5" + styled-jsx "5.0.0" + use-subscription "1.5.1" + optionalDependencies: + "@next/swc-android-arm64" "12.1.0" + "@next/swc-darwin-arm64" "12.1.0" + "@next/swc-darwin-x64" "12.1.0" + "@next/swc-linux-arm-gnueabihf" "12.1.0" + "@next/swc-linux-arm64-gnu" "12.1.0" + "@next/swc-linux-arm64-musl" "12.1.0" + "@next/swc-linux-x64-gnu" "12.1.0" + "@next/swc-linux-x64-musl" "12.1.0" + "@next/swc-win32-arm64-msvc" "12.1.0" + "@next/swc-win32-ia32-msvc" "12.1.0" + "@next/swc-win32-x64-msvc" "12.1.0" + +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +postcss@8.4.5: + version "8.4.5" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95" + integrity sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg== + dependencies: + nanoid "^3.1.30" + picocolors "^1.0.0" + source-map-js "^1.0.1" + +source-map-js@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +styled-jsx@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.0.tgz#816b4b92e07b1786c6b7111821750e0ba4d26e77" + integrity sha512-qUqsWoBquEdERe10EW8vLp3jT25s/ssG1/qX5gZ4wu15OZpmSMFI2v+fWlRhLfykA5rFtlJ1ME8A8pm/peV4WA== + +use-subscription@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.5.1.tgz#73501107f02fad84c6dd57965beb0b75c68c42d1" + integrity sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA== + dependencies: + object-assign "^4.1.1" From 9a5c3f96ec957595a3a32f751ef1daa9806c76b2 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 23 Mar 2022 22:22:57 +0100 Subject: [PATCH 002/658] rebase fixing conflicts --- .env.local.example | 6 + .gitignore | 6 + README.md | 105 +++++++++++++++++ __tests__/event-types.test.ts | 22 ++++ babel.config.js | 3 + jest.config.ts | 194 ++++++++++++++++++++++++++++++++ next.config.js | 16 +++ package.json | 16 ++- pages/api/_middleware.ts | 20 ++++ pages/api/auth/[...nextauth].ts | 82 ++++++++++++++ pages/api/event-types/[id].ts | 19 ++++ pages/api/event-types/index.ts | 20 ++++ pages/api/event-types/new.ts | 85 ++++++++++++++ pages/api/jwt.ts | 8 ++ pages/api/me/index.ts | 36 ++++++ pages/api/protected.ts | 19 ++++ pages/api/session.ts | 14 +++ pages/api/users/[id].ts | 21 ++++ src/pages/api/jwt.ts | 12 -- src/pages/api/protected.ts | 18 --- src/pages/api/session.ts | 8 -- tsconfig.json | 20 +--- 22 files changed, 694 insertions(+), 56 deletions(-) create mode 100644 .env.local.example create mode 100644 __tests__/event-types.test.ts create mode 100644 babel.config.js create mode 100644 jest.config.ts create mode 100644 next.config.js create mode 100644 pages/api/_middleware.ts create mode 100644 pages/api/auth/[...nextauth].ts create mode 100644 pages/api/event-types/[id].ts create mode 100644 pages/api/event-types/index.ts create mode 100644 pages/api/event-types/new.ts create mode 100644 pages/api/jwt.ts create mode 100644 pages/api/me/index.ts create mode 100644 pages/api/protected.ts create mode 100644 pages/api/session.ts create mode 100644 pages/api/users/[id].ts delete mode 100644 src/pages/api/jwt.ts delete mode 100644 src/pages/api/protected.ts delete mode 100644 src/pages/api/session.ts diff --git a/.env.local.example b/.env.local.example new file mode 100644 index 0000000000..fb2e751932 --- /dev/null +++ b/.env.local.example @@ -0,0 +1,6 @@ +NEXTAUTH_URL=http://localhost:3000 // This requires you run also app.cal.com in localhost:3000 to re-use it's Next-Auth api endpoints. +NEXTAUTH_SECRET=hello +EMAIL_SERVER='smtp://localhost:587' +EMAIL_FROM=Cal.com + +DATABASE_URL="postgresql://postgres:@localhost:5450/calendso" diff --git a/.gitignore b/.gitignore index 2c84f790ce..0ab8183430 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,10 @@ dist node_modules/ .env +<<<<<<< HEAD .next +======= +.next/ +.turbo/ +.tsconfig.tsbuildinfo +>>>>>>> 5a71055 (feat: Initial work on event-types, add jest for testing w node-http-mocks) diff --git a/README.md b/README.md index 32514baf22..ead6c04623 100644 --- a/README.md +++ b/README.md @@ -1 +1,106 @@ +<<<<<<< HEAD # Cal.com Public API (Enterprise Only) +======= +# Public API for Cal.com + +## This will be the new public enterprise-only API + +It will be a REST API for now, we might want to look into adding a GraphQL endpoint way down the roadmap if it makes sense. For now we think REST should cover what developers need. + +## NextJS + TypeScript + +It's a barebones **NextJS** + **TypeScript** project leveraging the nextJS API with a pages/api folder. + +## NextAuth + +Using the new next-auth middleware getToken and getSession for our API auth and any other middleware check we might want to do like user role. enterprise status, api req limit, etc. + +The idea is to leverage current `Session` accessToken. next-auth reads the Authorization Header and if it contains a valid JWT Bearer Token, it decodes it. + +We'll also need the EmailProvider (to expose VerificationTokens generation) and prisma adapter (to connect with the database) +We will extend it to also be valids PAT's with longer than web auth sessions expiryDates (maybe never expire). + +## No react + +It doesn't have react or react-dom as a dependency, and will only be used by a redirect as a folder or subdomain on cal.com with maybe a v1 tag like: + +- `v1.api.cal.com` +- `api.cal.com/v1` +- `app.cal.com/api/v1/` + +## Example + +HTTP Request (Use Paw.app/postman/postwoman/hoppscotch) + +``` +POST /api/jwt HTTP/1.1 +authorization: Bearer eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..ik9ibWdgN2Mq-WYH.7qsAwcOtOQyqwjIQ03EkEHy4kpy4GAndbqqQlhczc9xRgn_ycqXn4RbmwWA9LGm2LIXp_MQXMNm-i5vvc7piGZYyTPIGTieLspCYG4CKnZIawjcXmBEiwG9-PafNSUOGJB1O41l-9WbOEZNnIIAlfBTxdM3T13fUP4ese348tbn755Vi27Q_hOKulOfJ-Z-IQCd1OMsmTbuBo537IUkpj979.y288909Yt7mEYWJUAJRqdQ +``` + +or with cURL + +``` +curl -X "POST" "http://localhost:3002/api/jwt" \ + -H 'authorization: Bearer eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..ik9ibWdgN2Mq-WYH.7qsAwcOtOQyqwjIQ03EkEHy4kpy4GAndbqqQlhczc9xRgn_ycqXn4RbmwWA9LGm2LIXp_MQXMNm-i5vvc7piGZYyTPIGTieLspCYG4CKnZIawjcXmBEiwG9-PafNSUOGJB1O41l-9WbOEZNnIIAlfBTxdM3T13fUP4ese348tbn755Vi27Q_hOKulOfJ-Z-IQCd1OMsmTbuBo537IUkpj979.y288909Yt7mEYWJUAJRqdQ' +``` + +Returns: + +```{ + "name": null, + "email": "m@n.es", + "sub": "cl032mhik0006w4ylrtay2t3f", + "iat": 1645894473, + "exp": 1648486473, + "jti": "af1c04f2-09a8-45b5-a6f0-c35eea9efa9b", + "userRole": "admin" +} +``` + + + +## API Endpoint Validation + +The API uses `zod` library like our main web repo. It validates that either GET query parameters or POST body content's are valid and up to our spec. It gives appropiate errors when parsing result's with schemas. + + +## Testing + + + + +/event-types +GET +/teams +teams/join + +GET / PATCH / PUT /users/:id + +/users/new +POST +/event-types +/bookings +/availabilties +/schedules + +## Users + +GET /users : Get all users you're an owner / team manager of. Requires Auth. +POST /users : Create a new user +GET /users/{id} : Get the user information identified by "id" +PUT /users/{id} : Update the user information identified by "id" +DELETE /users/{id} : Delete user by "id" + +## Event Types + +/event-types +GET /event-types : Get all event-types +POST /event-types : Create a new user +GET /event-types/{id} : Get the user information identified by "id" +PUT /event-types/{id} : Update the user information identified by "id" +DELETE /event-types/{id} : Delete user by "id" + +## Bookings + +/bookings +>>>>>>> 5a71055 (feat: Initial work on event-types, add jest for testing w node-http-mocks) diff --git a/__tests__/event-types.test.ts b/__tests__/event-types.test.ts new file mode 100644 index 0000000000..f4c46be3ed --- /dev/null +++ b/__tests__/event-types.test.ts @@ -0,0 +1,22 @@ +import { createMocks } from "node-mocks-http"; + +import prisma from "@calcom/prisma"; +import { EventType } from "@calcom/prisma/client"; + +import handleEvent from "../pages/api/event-types/[id]"; + +describe("/api/event-types/[id]", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "GET", + query: { + id: 1, + }, + }); + prisma.eventType.findUnique({ where: { id: 1 } }).then(async (data: EventType) => { + await handleEvent(req, res); + expect(res._getStatusCode()).toBe(200); + expect(JSON.parse(res._getData())).toStrictEqual({ event: data }); + }); + }); +}); diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000000..2afcfd2404 --- /dev/null +++ b/babel.config.js @@ -0,0 +1,3 @@ +module.exports = { + presets: [["@babel/preset-env", { targets: { node: "current" } }], "@babel/preset-typescript"], +}; diff --git a/jest.config.ts b/jest.config.ts new file mode 100644 index 0000000000..6045b4fa45 --- /dev/null +++ b/jest.config.ts @@ -0,0 +1,194 @@ +/* + * For a detailed explanation regarding each configuration property and type check, visit: + * https://jestjs.io/docs/en/configuration.html + */ + +export default { + // All imported modules in your tests should be mocked automatically + // automock: false, + + // Stop running tests after `n` failures + // bail: 0, + + // The directory where Jest should store its cached dependency information + // cacheDirectory: "/private/var/folders/fl/sw088bcs0dx4zyy0f_ghzvwc0000gn/T/jest_dx", + + // Automatically clear mock calls and instances between every test + clearMocks: true, + + // Indicates whether the coverage information should be collected while executing the test + // collectCoverage: false, + + // An array of glob patterns indicating a set of files for which coverage information should be collected + // collectCoverageFrom: undefined, + + // The directory where Jest should output its coverage files + coverageDirectory: "coverage", + + // An array of regexp pattern strings used to skip coverage collection + // coveragePathIgnorePatterns: [ + // "/node_modules/" + // ], + + // Indicates which provider should be used to instrument code for coverage + // coverageProvider: "babel", + + // A list of reporter names that Jest uses when writing coverage reports + // coverageReporters: [ + // "json", + // "text", + // "lcov", + // "clover" + // ], + + // An object that configures minimum threshold enforcement for coverage results + // coverageThreshold: undefined, + + // A path to a custom dependency extractor + // dependencyExtractor: undefined, + + // Make calling deprecated APIs throw helpful error messages + // errorOnDeprecated: false, + + // Force coverage collection from ignored files using an array of glob patterns + // forceCoverageMatch: [], + + // A path to a module which exports an async function that is triggered once before all test suites + // globalSetup: undefined, + + // A path to a module which exports an async function that is triggered once after all test suites + // globalTeardown: undefined, + + // A set of global variables that need to be available in all test environments + // globals: {}, + + // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. + // maxWorkers: "50%", + + // An array of directory names to be searched recursively up from the requiring module's location + // moduleDirectories: [ + // "node_modules" + // ], + + // An array of file extensions your modules use + // moduleFileExtensions: [ + // "js", + // "json", + // "jsx", + // "ts", + // "tsx", + // "node" + // ], + + // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module + // moduleNameMapper: {}, + + // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader + // modulePathIgnorePatterns: [], + + // Activates notifications for test results + // notify: false, + + // An enum that specifies notification mode. Requires { notify: true } + // notifyMode: "failure-change", + + // A preset that is used as a base for Jest's configuration + // preset: undefined, + + // Run tests from one or more projects + // projects: undefined, + + // Use this configuration option to add custom reporters to Jest + // reporters: undefined, + + // Automatically reset mock state between every test + // resetMocks: false, + + // Reset the module registry before running each individual test + // resetModules: false, + + // A path to a custom resolver + // resolver: undefined, + + // Automatically restore mock state between every test + // restoreMocks: false, + + // The root directory that Jest should scan for tests and modules within + // rootDir: undefined, + + // A list of paths to directories that Jest should use to search for files in + // roots: [ + // "" + // ], + + // Allows you to use a custom runner instead of Jest's default test runner + // runner: "jest-runner", + + // The paths to modules that run some code to configure or set up the testing environment before each test + // setupFiles: [], + + // A list of paths to modules that run some code to configure or set up the testing framework before each test + // setupFilesAfterEnv: [], + + // The number of seconds after which a test is considered as slow and reported as such in the results. + // slowTestThreshold: 5, + + // A list of paths to snapshot serializer modules Jest should use for snapshot testing + // snapshotSerializers: [], + + // The test environment that will be used for testing + testEnvironment: "node", + + // Options that will be passed to the testEnvironment + // testEnvironmentOptions: {}, + + // Adds a location field to test results + // testLocationInResults: false, + + // The glob patterns Jest uses to detect test files + // testMatch: [ + // "**/__tests__/**/*.[jt]s?(x)", + // "**/?(*.)+(spec|test).[tj]s?(x)" + // ], + + // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped + // testPathIgnorePatterns: [ + // "/node_modules/" + // ], + + // The regexp pattern or array of patterns that Jest uses to detect test files + // testRegex: [], + + // This option allows the use of a custom results processor + // testResultsProcessor: undefined, + + // This option allows use of a custom test runner + // testRunner: "jasmine2", + + // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href + // testURL: "http://localhost", + + // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" + // timers: "real", + + // A map from regular expressions to paths to transformers + // transform: undefined, + + // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation + // transformIgnorePatterns: [ + // "/node_modules/", + // "\\.pnp\\.[^\\/]+$" + // ], + + // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them + // unmockedModulePathPatterns: undefined, + + // Indicates whether each individual test should be reported during the run + // verbose: undefined, + + // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode + // watchPathIgnorePatterns: [], + + // Whether to use watchman for file crawling + // watchman: true, +}; diff --git a/next.config.js b/next.config.js new file mode 100644 index 0000000000..1e6d5beae6 --- /dev/null +++ b/next.config.js @@ -0,0 +1,16 @@ +module.exports = { + async rewrites() { + return [ + // This redirects requests recieved at / the root to the /api/ folder. + { + source: "/:rest*", + destination: "/api/:rest*", + }, + // This redirects requests to api/v*/ to /api/ passing version as a query parameter. + { + source: "/api/v:version/:rest*", + destination: "/api/:rest*?version=:version", + }, + ]; + }, +}; diff --git a/package.json b/package.json index 297108c12e..9d55c5bcd3 100644 --- a/package.json +++ b/package.json @@ -11,17 +11,27 @@ "start": "next start", "build": "next build", "lint": "next lint", + "test": "jest", "type-check": "tsc --pretty --noEmit", "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist" }, "devDependencies": { + "@babel/core": "^7.17.8", + "@babel/preset-env": "^7.16.11", + "@babel/preset-typescript": "^7.16.7", "@calcom/prisma": "*", "@calcom/tsconfig": "*", - "scripts": "*", - "typescript": "^4.5.3" + "babel-jest": "^27.5.1", + "install": "^0.13.0", + "jest": "^27.5.1", + "node-mocks-http": "^1.11.0", + "npm": "^8.5.5", + "typescript": "^4.5.3", + "zod": "^3.14.2" }, "dependencies": { "@next-auth/prisma-adapter": "^1.0.1", - "next": "^12.1.0" + "next": "^12.1.0", + "next-auth": "^4.3.1" } } \ No newline at end of file diff --git a/pages/api/_middleware.ts b/pages/api/_middleware.ts new file mode 100644 index 0000000000..b7524ad529 --- /dev/null +++ b/pages/api/_middleware.ts @@ -0,0 +1,20 @@ +import type { NextApiRequest, NextApiResponse } from "next"; +import { getToken } from "next-auth/jwt"; +import { NextRequest, NextResponse } from "next/server"; + +export async function middleware(req: NextApiRequest) { + // return early if url isn't supposed to be protected + // if (!req.url.includes("/protected-url")) { + // return NextResponse.next() + // } + console.log(req.headers); + const session = await getToken({ req, secret: process.env.SECRET }); + // You could also check for any property on the session object, + // like role === "admin" or name === "John Doe", etc. + if (!session) { + return NextResponse.redirect("https://localhost:3002/unauthorized"); + } + + // If user is authenticated, continue. + return NextResponse.next(); +} diff --git a/pages/api/auth/[...nextauth].ts b/pages/api/auth/[...nextauth].ts new file mode 100644 index 0000000000..d3d2886b06 --- /dev/null +++ b/pages/api/auth/[...nextauth].ts @@ -0,0 +1,82 @@ +import { PrismaAdapter } from "@next-auth/prisma-adapter"; +import { PrismaClient } from "@prisma/client"; +import NextAuth, { NextAuthOptions } from "next-auth"; +import EmailProvider from "next-auth/providers/email"; + +// FIXME: not working when importing prisma directly from our project +// import prisma from "@calcom/prisma"; +const prisma = new PrismaClient(); + +// TODO: get rid of this and do it in it's own auth.cal.com project with a custom Next.js app + +export const authOptions: NextAuthOptions = { + // For more information on each option (and a full list of options) go to + // https://next-auth.js.org/configuration/options + adapter: PrismaAdapter(prisma), + // https://next-auth.js.org/configuration/providers + providers: [ + EmailProvider({ + maxAge: 10 * 60 * 60, // Magic links are valid for 10 min only + // sendVerificationRequest, + }), + ], + secret: process.env.NEXTAUTH_SECRET, + session: { + // Use JSON Web Tokens for session instead of database sessions. + // This option can be used with or without a database for users/accounts. + // Note: `strategy` should be set to 'jwt' if no database is used. + + // TODO: Do we want to move 'database' sessions at some point? + strategy: "jwt", + // Seconds - How long until an idle session expires and is no longer valid. + // maxAge: 30 * 24 * 60 * 60, // 30 days + + // Seconds - Throttle how frequently to write to database to extend a session. + // Use it to limit write operations. Set to 0 to always update the database. + // Note: This option is ignored if using JSON Web Tokens + // updateAge: 24 * 60 * 60, // 24 hours + }, + + // JSON Web tokens are only used for sessions if the `strategy: 'jwt'` session + // option is set - or by default if no database is specified. + // https://next-auth.js.org/configuration/options#jwt + jwt: { + // A secret to use for key generation (you should set this explicitly) + secret: process.env.SECRET, + // Set to true to use encryption (default: false) + // encryption: true, + // You can define your own encode/decode functions for signing and encryption + // if you want to override the default behaviour. + // encode: async ({ secret, token, maxAge }) => {}, + // decode: async ({ secret, token, maxAge }) => {}, + }, + // https://next-auth.js.org/configuration/pages + // NOTE: We don't want to enable these, only the API endpoints for auth. We will get rid of this when we do auth.cal.com + pages: { + signIn: "/", // Displays signin buttons + signOut: "/", // Displays form with sign out button + error: "/", // Error code passed in query string as ?error= + verifyRequest: "/", // Used for check email page + newUser: "/", // If set, new users will be directed here on first sign in + }, + + // Callbacks are asynchronous functions you can use to control what happens + // when an action is performed. + // https://next-auth.js.org/configuration/callbacks + + callbacks: { + // async signIn({ user, account, profile, email, credentials }) { return true }, + // async redirect({ url, baseUrl }) { return baseUrl }, + // async session({ session, token, user }) { return session }, + // FIXME: add a custom jwt callback, that is stored outside next-auth + // and can be reused to generate valid Personal Access Tokens for the API. + // async jwt({ token, user, account, profile, isNewUser }) { return token } + }, + + // Events are useful for logging + // https://next-auth.js.org/configuration/events + + // Enable debug messages in the console if you are having problems + debug: false, +}; +export default NextAuth(authOptions); diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts new file mode 100644 index 0000000000..5fc6352723 --- /dev/null +++ b/pages/api/event-types/[id].ts @@ -0,0 +1,19 @@ +import { EventType } from "@prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +type EventIdData = { + event?: EventType; + error?: any; +}; + +export default async function eventType(req: NextApiRequest, res: NextApiResponse) { + try { + const event = await prisma.eventType.findUnique({ where: { id: Number(req.query.id) } }); + res.status(200).json({ event }); + } catch (error) { + console.log(error); + res.status(400).json({ error: error }); + } +} diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts new file mode 100644 index 0000000000..864d657c40 --- /dev/null +++ b/pages/api/event-types/index.ts @@ -0,0 +1,20 @@ +import { PrismaClient, EventType } from "@prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +type EventTypeIdData = { + events?: EventType[]; + error?: any; +}; + +const prisma = new PrismaClient(); + +export default async function eventType(req: NextApiRequest, res: NextApiResponse) { + try { + const eventTypes = await prisma.eventType.findMany({ where: { id: Number(req.query.eventTypeId) } }); + res.status(200).json({ events: { ...eventTypes } }); + } catch (error) { + console.log(error); + // FIXME: Add zod for validation/error handling + res.status(400).json({ error: error }); + } +} diff --git a/pages/api/event-types/new.ts b/pages/api/event-types/new.ts new file mode 100644 index 0000000000..b4b56ba303 --- /dev/null +++ b/pages/api/event-types/new.ts @@ -0,0 +1,85 @@ +import { PrismaClient, EventType } from "@prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +const prisma = new PrismaClient(); +interface Body { + userId: string; + + newOrganization: { + name: string; + users: string[]; + }; +} +type EventsData = { + event?: EventType; + error?: string; +}; + +export default async function createEventLink(req: NextApiRequest, res: NextApiResponse) { + const { + body: { + title, + slug, + description, + position, + locations, + hidden, + teamId, + eventName, + timeZone, + periodType, + periodStartDate, + periodEndDate, + periodDays, + periodCountCalendarDays, + requiresConfirmation, + disableGuests, + minimumBookingNotice, + beforeEventBuffer, + afterEventBuffer, + schedulingType, + price, + currency, + slotInterval, + metadata, + length, + }, + method, + } = req; + if (method === "POST") { + // Process a POST request + const newEvent = await prisma.eventType.create({ + data: { + title: `${title}`, + slug: `${slug}`, + length: Number(length), + // description: description as string, + // position: Number(position), + // locations: locations, + // hidden: Boolean(hidden) as boolean, + // teamId: Number.isInteger(teamId) ? Number(teamId) : null, + // eventName: eventName, + // timeZone: timeZone, + // periodType: periodType, + // periodStartDate: periodStartDate, + // periodEndDate: periodEndDate, + // periodDays: periodDays, + // periodCountCalendarDays: periodCountCalendarDays, + // requiresConfirmation: requiresConfirmation, + // disableGuests: disableGuests, + // minimumBookingNotice: minimumBookingNotice, + // beforeEventBuffer: beforeEventBuffer, + // afterEventBuffer: afterEventBuffer, + // schedulingType: schedulingType, + // price: price, + // currency: currency, + // slotInterval: slotInterval, + // metadata: metadata, + }, + }); + res.status(201).json({ event: newEvent }); + } else { + // Handle any other HTTP method + res.status(405).json({ error: "Only POST Method allowed" }); + } +} diff --git a/pages/api/jwt.ts b/pages/api/jwt.ts new file mode 100644 index 0000000000..c480ea6947 --- /dev/null +++ b/pages/api/jwt.ts @@ -0,0 +1,8 @@ +import type { NextApiRequest, NextApiResponse } from "next" +import { getToken } from "next-auth/jwt"; + +const secret = process.env.NEXTAUTH_SECRET; +export default async function jwt(req: NextApiRequest, res: NextApiResponse) { + const token = await getToken({ req, secret }); + res.send(JSON.stringify(token, null, 2)); +} diff --git a/pages/api/me/index.ts b/pages/api/me/index.ts new file mode 100644 index 0000000000..86010001e5 --- /dev/null +++ b/pages/api/me/index.ts @@ -0,0 +1,36 @@ +import { PrismaClient } from "@prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { getToken } from "next-auth/jwt"; + +// This local import doesn't work +// import { PrismaClient } from "@calcom/prisma"; +const prisma = new PrismaClient(); +const secret = process.env.NEXTAUTH_SECRET; + +type Data = { + message: string; +}; + +export default async function me(req: NextApiRequest, res: NextApiResponse) { + const token = await getToken({ req, secret, raw: false }); + console.log("token", token); + if (!token) + return res.status(404).json({ + message: `You're not authenticated. Provide a valid Session JWT as Authorization: 'Bearer {your_token_here}'`, + }); + if (!token.email) + return res.status(404).json({ + message: `Your token doesn't have a valid email`, + }); + const email: string | undefined = token?.email; + const user = await prisma.user.findUnique({ + where: { + email: email, + }, + }); + return res.json({ + message: `Hello ${user?.name}, your email is ${user?.email}, and your email is ${ + user?.emailVerified ? "verified" : "unverified" + }`, + }); +} diff --git a/pages/api/protected.ts b/pages/api/protected.ts new file mode 100644 index 0000000000..e4c71db792 --- /dev/null +++ b/pages/api/protected.ts @@ -0,0 +1,19 @@ +// This is an example of how to read a JSON Web Token from an API route +import type { NextApiRequest, NextApiResponse } from "next"; +import { getToken } from "next-auth/jwt"; + +const secret = process.env.NEXTAUTH_SECRET; + +export default async function jwt(req: NextApiRequest, res: NextApiResponse) { + const token = await getToken({ req, secret, raw: false }); + if (token) { + res.send({ + content: "This is protected content. You can access this content because you are signed in.", + token, + }); + } else { + res.send({ + error: "You must be signed in to view the protected content on this page.", + }); + } +} diff --git a/pages/api/session.ts b/pages/api/session.ts new file mode 100644 index 0000000000..cd3df045ec --- /dev/null +++ b/pages/api/session.ts @@ -0,0 +1,14 @@ +import type { NextApiRequest, NextApiResponse } from "next"; +import { getServerSession } from "next-auth"; + +import { authOptions } from "./auth/[...nextauth]"; + +export default async function session(req: NextApiRequest, res: NextApiResponse) { + const session = await getServerSession({ req, res }, authOptions); + /* ... */ + if (session) { + res.send(JSON.stringify(session, null, 2)); + } else { + res.end(); + } +} diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts new file mode 100644 index 0000000000..07618f8dc4 --- /dev/null +++ b/pages/api/users/[id].ts @@ -0,0 +1,21 @@ +import { PrismaClient } from "@prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +// This local import doesn't work +// import { PrismaClient } from "@calcom/prisma"; +const prisma = new PrismaClient(); + +type Data = { + message: string; +}; + +export default async function userId(req: NextApiRequest, res: NextApiResponse) { + const { id }: { id?: string } = req.query; + if (!id) return res.status(404).json({ message: `User not found` }); + const user = await prisma.user.findUnique({ + where: { + id: parseInt(id), + }, + }); + return res.json({ message: `Hello ${user?.name}` }); +} diff --git a/src/pages/api/jwt.ts b/src/pages/api/jwt.ts deleted file mode 100644 index f33002aad6..0000000000 --- a/src/pages/api/jwt.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next" -import { getToken } from "next-auth/jwt"; - -const secret = process.env.NEXTAUTH_SECRET; - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - // if using `NEXTAUTH_SECRET` env variable, we detect it, and you won't actually need to `secret` - // const token = await getToken({ req }) - const token = await getToken({ req, secret, raw: true }); - console.log("JSON Web Token", token); - res.end() -} \ No newline at end of file diff --git a/src/pages/api/protected.ts b/src/pages/api/protected.ts deleted file mode 100644 index 27e06b9ea0..0000000000 --- a/src/pages/api/protected.ts +++ /dev/null @@ -1,18 +0,0 @@ -// This is an example of to protect an API route -import { getSession } from "next-auth/react" -import type { NextApiRequest, NextApiResponse } from "next" - -export default async (req: NextApiRequest, res: NextApiResponse) => { - const session = await getSession({ req }) - - if (session) { - res.send({ - content: - "This is protected content. You can access this content because you are signed in.", - }) - } else { - res.send({ - error: "You must be signed in to view the protected content on this page.", - }) - } -}; diff --git a/src/pages/api/session.ts b/src/pages/api/session.ts deleted file mode 100644 index 2a1551dd0e..0000000000 --- a/src/pages/api/session.ts +++ /dev/null @@ -1,8 +0,0 @@ -// This is an example of how to access a session from an API route -import { getSession } from "next-auth/react" -import type { NextApiRequest, NextApiResponse } from "next" - -export default async (req: NextApiRequest, res: NextApiResponse) => { - const session = await getSession({ req }) - res.send(JSON.stringify(session, null, 2)) -} diff --git a/tsconfig.json b/tsconfig.json index fd9c2c4aee..b93f1e08a5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,23 +1,13 @@ { "extends": "@calcom/tsconfig/base.json", - "compilerOptions": { - "lib": [ - "ES2015" - ], - "module": "CommonJS", - "outDir": "./dist", - "rootDir": "./src", - "target": "es5", - "allowJs": true, - "noEmit": true, - "incremental": true, - "resolveJsonModule": true, - "jsx": "preserve" - }, "exclude": [ "node_modules" ], + "compilerOptions": { + "strictNullChecks": true, + "baseUrl": "./", + }, "include": [ - "src" + "./pages/api/*.ts" ] } From c46a899c1bb71352c982945afa8eb136734355cd Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 23 Mar 2022 22:27:03 +0100 Subject: [PATCH 003/658] remove all next-auth related stuff --- README.md | 85 +---------------------------- pages/api/_middleware.ts | 20 ------- pages/api/auth/[...nextauth].ts | 82 ---------------------------- pages/api/jwt.ts | 8 --- pages/api/protected.ts | 19 ------- pages/api/session.ts | 14 ----- src/pages/api/auth/[...nextauth].ts | 33 ----------- 7 files changed, 2 insertions(+), 259 deletions(-) delete mode 100644 pages/api/_middleware.ts delete mode 100644 pages/api/auth/[...nextauth].ts delete mode 100644 pages/api/jwt.ts delete mode 100644 pages/api/protected.ts delete mode 100644 pages/api/session.ts delete mode 100644 src/pages/api/auth/[...nextauth].ts diff --git a/README.md b/README.md index ead6c04623..8a01433f90 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,13 @@ -<<<<<<< HEAD # Cal.com Public API (Enterprise Only) -======= -# Public API for Cal.com ## This will be the new public enterprise-only API -It will be a REST API for now, we might want to look into adding a GraphQL endpoint way down the roadmap if it makes sense. For now we think REST should cover what developers need. +This is the public REST api for cal.com. ## NextJS + TypeScript It's a barebones **NextJS** + **TypeScript** project leveraging the nextJS API with a pages/api folder. -## NextAuth - -Using the new next-auth middleware getToken and getSession for our API auth and any other middleware check we might want to do like user role. enterprise status, api req limit, etc. - -The idea is to leverage current `Session` accessToken. next-auth reads the Authorization Header and if it contains a valid JWT Bearer Token, it decodes it. - -We'll also need the EmailProvider (to expose VerificationTokens generation) and prisma adapter (to connect with the database) -We will extend it to also be valids PAT's with longer than web auth sessions expiryDates (maybe never expire). - ## No react It doesn't have react or react-dom as a dependency, and will only be used by a redirect as a folder or subdomain on cal.com with maybe a v1 tag like: @@ -28,79 +16,10 @@ It doesn't have react or react-dom as a dependency, and will only be used by a r - `api.cal.com/v1` - `app.cal.com/api/v1/` -## Example - -HTTP Request (Use Paw.app/postman/postwoman/hoppscotch) - -``` -POST /api/jwt HTTP/1.1 -authorization: Bearer eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..ik9ibWdgN2Mq-WYH.7qsAwcOtOQyqwjIQ03EkEHy4kpy4GAndbqqQlhczc9xRgn_ycqXn4RbmwWA9LGm2LIXp_MQXMNm-i5vvc7piGZYyTPIGTieLspCYG4CKnZIawjcXmBEiwG9-PafNSUOGJB1O41l-9WbOEZNnIIAlfBTxdM3T13fUP4ese348tbn755Vi27Q_hOKulOfJ-Z-IQCd1OMsmTbuBo537IUkpj979.y288909Yt7mEYWJUAJRqdQ -``` - -or with cURL - -``` -curl -X "POST" "http://localhost:3002/api/jwt" \ - -H 'authorization: Bearer eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIn0..ik9ibWdgN2Mq-WYH.7qsAwcOtOQyqwjIQ03EkEHy4kpy4GAndbqqQlhczc9xRgn_ycqXn4RbmwWA9LGm2LIXp_MQXMNm-i5vvc7piGZYyTPIGTieLspCYG4CKnZIawjcXmBEiwG9-PafNSUOGJB1O41l-9WbOEZNnIIAlfBTxdM3T13fUP4ese348tbn755Vi27Q_hOKulOfJ-Z-IQCd1OMsmTbuBo537IUkpj979.y288909Yt7mEYWJUAJRqdQ' -``` - -Returns: - -```{ - "name": null, - "email": "m@n.es", - "sub": "cl032mhik0006w4ylrtay2t3f", - "iat": 1645894473, - "exp": 1648486473, - "jti": "af1c04f2-09a8-45b5-a6f0-c35eea9efa9b", - "userRole": "admin" -} -``` - ## API Endpoint Validation The API uses `zod` library like our main web repo. It validates that either GET query parameters or POST body content's are valid and up to our spec. It gives appropiate errors when parsing result's with schemas. - -## Testing - - - - -/event-types -GET -/teams -teams/join - -GET / PATCH / PUT /users/:id - -/users/new -POST -/event-types -/bookings -/availabilties -/schedules - -## Users - -GET /users : Get all users you're an owner / team manager of. Requires Auth. -POST /users : Create a new user -GET /users/{id} : Get the user information identified by "id" -PUT /users/{id} : Update the user information identified by "id" -DELETE /users/{id} : Delete user by "id" - -## Event Types - -/event-types -GET /event-types : Get all event-types -POST /event-types : Create a new user -GET /event-types/{id} : Get the user information identified by "id" -PUT /event-types/{id} : Update the user information identified by "id" -DELETE /event-types/{id} : Delete user by "id" - -## Bookings - -/bookings ->>>>>>> 5a71055 (feat: Initial work on event-types, add jest for testing w node-http-mocks) +## Testing with Jest + node-mocks-http \ No newline at end of file diff --git a/pages/api/_middleware.ts b/pages/api/_middleware.ts deleted file mode 100644 index b7524ad529..0000000000 --- a/pages/api/_middleware.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; -import { getToken } from "next-auth/jwt"; -import { NextRequest, NextResponse } from "next/server"; - -export async function middleware(req: NextApiRequest) { - // return early if url isn't supposed to be protected - // if (!req.url.includes("/protected-url")) { - // return NextResponse.next() - // } - console.log(req.headers); - const session = await getToken({ req, secret: process.env.SECRET }); - // You could also check for any property on the session object, - // like role === "admin" or name === "John Doe", etc. - if (!session) { - return NextResponse.redirect("https://localhost:3002/unauthorized"); - } - - // If user is authenticated, continue. - return NextResponse.next(); -} diff --git a/pages/api/auth/[...nextauth].ts b/pages/api/auth/[...nextauth].ts deleted file mode 100644 index d3d2886b06..0000000000 --- a/pages/api/auth/[...nextauth].ts +++ /dev/null @@ -1,82 +0,0 @@ -import { PrismaAdapter } from "@next-auth/prisma-adapter"; -import { PrismaClient } from "@prisma/client"; -import NextAuth, { NextAuthOptions } from "next-auth"; -import EmailProvider from "next-auth/providers/email"; - -// FIXME: not working when importing prisma directly from our project -// import prisma from "@calcom/prisma"; -const prisma = new PrismaClient(); - -// TODO: get rid of this and do it in it's own auth.cal.com project with a custom Next.js app - -export const authOptions: NextAuthOptions = { - // For more information on each option (and a full list of options) go to - // https://next-auth.js.org/configuration/options - adapter: PrismaAdapter(prisma), - // https://next-auth.js.org/configuration/providers - providers: [ - EmailProvider({ - maxAge: 10 * 60 * 60, // Magic links are valid for 10 min only - // sendVerificationRequest, - }), - ], - secret: process.env.NEXTAUTH_SECRET, - session: { - // Use JSON Web Tokens for session instead of database sessions. - // This option can be used with or without a database for users/accounts. - // Note: `strategy` should be set to 'jwt' if no database is used. - - // TODO: Do we want to move 'database' sessions at some point? - strategy: "jwt", - // Seconds - How long until an idle session expires and is no longer valid. - // maxAge: 30 * 24 * 60 * 60, // 30 days - - // Seconds - Throttle how frequently to write to database to extend a session. - // Use it to limit write operations. Set to 0 to always update the database. - // Note: This option is ignored if using JSON Web Tokens - // updateAge: 24 * 60 * 60, // 24 hours - }, - - // JSON Web tokens are only used for sessions if the `strategy: 'jwt'` session - // option is set - or by default if no database is specified. - // https://next-auth.js.org/configuration/options#jwt - jwt: { - // A secret to use for key generation (you should set this explicitly) - secret: process.env.SECRET, - // Set to true to use encryption (default: false) - // encryption: true, - // You can define your own encode/decode functions for signing and encryption - // if you want to override the default behaviour. - // encode: async ({ secret, token, maxAge }) => {}, - // decode: async ({ secret, token, maxAge }) => {}, - }, - // https://next-auth.js.org/configuration/pages - // NOTE: We don't want to enable these, only the API endpoints for auth. We will get rid of this when we do auth.cal.com - pages: { - signIn: "/", // Displays signin buttons - signOut: "/", // Displays form with sign out button - error: "/", // Error code passed in query string as ?error= - verifyRequest: "/", // Used for check email page - newUser: "/", // If set, new users will be directed here on first sign in - }, - - // Callbacks are asynchronous functions you can use to control what happens - // when an action is performed. - // https://next-auth.js.org/configuration/callbacks - - callbacks: { - // async signIn({ user, account, profile, email, credentials }) { return true }, - // async redirect({ url, baseUrl }) { return baseUrl }, - // async session({ session, token, user }) { return session }, - // FIXME: add a custom jwt callback, that is stored outside next-auth - // and can be reused to generate valid Personal Access Tokens for the API. - // async jwt({ token, user, account, profile, isNewUser }) { return token } - }, - - // Events are useful for logging - // https://next-auth.js.org/configuration/events - - // Enable debug messages in the console if you are having problems - debug: false, -}; -export default NextAuth(authOptions); diff --git a/pages/api/jwt.ts b/pages/api/jwt.ts deleted file mode 100644 index c480ea6947..0000000000 --- a/pages/api/jwt.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next" -import { getToken } from "next-auth/jwt"; - -const secret = process.env.NEXTAUTH_SECRET; -export default async function jwt(req: NextApiRequest, res: NextApiResponse) { - const token = await getToken({ req, secret }); - res.send(JSON.stringify(token, null, 2)); -} diff --git a/pages/api/protected.ts b/pages/api/protected.ts deleted file mode 100644 index e4c71db792..0000000000 --- a/pages/api/protected.ts +++ /dev/null @@ -1,19 +0,0 @@ -// This is an example of how to read a JSON Web Token from an API route -import type { NextApiRequest, NextApiResponse } from "next"; -import { getToken } from "next-auth/jwt"; - -const secret = process.env.NEXTAUTH_SECRET; - -export default async function jwt(req: NextApiRequest, res: NextApiResponse) { - const token = await getToken({ req, secret, raw: false }); - if (token) { - res.send({ - content: "This is protected content. You can access this content because you are signed in.", - token, - }); - } else { - res.send({ - error: "You must be signed in to view the protected content on this page.", - }); - } -} diff --git a/pages/api/session.ts b/pages/api/session.ts deleted file mode 100644 index cd3df045ec..0000000000 --- a/pages/api/session.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; -import { getServerSession } from "next-auth"; - -import { authOptions } from "./auth/[...nextauth]"; - -export default async function session(req: NextApiRequest, res: NextApiResponse) { - const session = await getServerSession({ req, res }, authOptions); - /* ... */ - if (session) { - res.send(JSON.stringify(session, null, 2)); - } else { - res.end(); - } -} diff --git a/src/pages/api/auth/[...nextauth].ts b/src/pages/api/auth/[...nextauth].ts deleted file mode 100644 index 543d94f7d1..0000000000 --- a/src/pages/api/auth/[...nextauth].ts +++ /dev/null @@ -1,33 +0,0 @@ -import { PrismaAdapter } from "@next-auth/prisma-adapter"; -import NextAuth from "next-auth"; -import EmailProvider from "next-auth/providers/email"; - -import { defaultCookies } from "@calcom/lib/default-cookies"; -import { serverConfig } from "@calcom/lib/serverConfig"; -import prisma from "@calcom/prisma"; - -const WEBSITE_BASE_URL = process.env.WEBSITE_BASE_URL || ""; - - -export default NextAuth({ - adapter: PrismaAdapter(prisma), - providers: [ - EmailProvider({ - maxAge: 10 * 60 * 60, // Magic links are valid for 10 min only - // sendVerificationRequest, - }), - ], - secret: process.env.SECRET, - cookies: defaultCookies(WEBSITE_BASE_URL?.startsWith("https://")), - session: { - strategy: "jwt", - }, - jwt: { - // A secret to use for key generation (you should set this explicitly) - secret: process.env.SECRET, - // Set to true to use encryption (default: false) - // encryption: true, - }, - // Enable debug messages in the console if you are having problems - debug: true, -}); From b6dca78d64dddae4a953168286bbdae95b5810c5 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 23 Mar 2022 22:29:00 +0100 Subject: [PATCH 004/658] remove unneeded jest config and deps --- jest.config.ts | 194 ------------------------------------------------- package.json | 6 +- 2 files changed, 1 insertion(+), 199 deletions(-) delete mode 100644 jest.config.ts diff --git a/jest.config.ts b/jest.config.ts deleted file mode 100644 index 6045b4fa45..0000000000 --- a/jest.config.ts +++ /dev/null @@ -1,194 +0,0 @@ -/* - * For a detailed explanation regarding each configuration property and type check, visit: - * https://jestjs.io/docs/en/configuration.html - */ - -export default { - // All imported modules in your tests should be mocked automatically - // automock: false, - - // Stop running tests after `n` failures - // bail: 0, - - // The directory where Jest should store its cached dependency information - // cacheDirectory: "/private/var/folders/fl/sw088bcs0dx4zyy0f_ghzvwc0000gn/T/jest_dx", - - // Automatically clear mock calls and instances between every test - clearMocks: true, - - // Indicates whether the coverage information should be collected while executing the test - // collectCoverage: false, - - // An array of glob patterns indicating a set of files for which coverage information should be collected - // collectCoverageFrom: undefined, - - // The directory where Jest should output its coverage files - coverageDirectory: "coverage", - - // An array of regexp pattern strings used to skip coverage collection - // coveragePathIgnorePatterns: [ - // "/node_modules/" - // ], - - // Indicates which provider should be used to instrument code for coverage - // coverageProvider: "babel", - - // A list of reporter names that Jest uses when writing coverage reports - // coverageReporters: [ - // "json", - // "text", - // "lcov", - // "clover" - // ], - - // An object that configures minimum threshold enforcement for coverage results - // coverageThreshold: undefined, - - // A path to a custom dependency extractor - // dependencyExtractor: undefined, - - // Make calling deprecated APIs throw helpful error messages - // errorOnDeprecated: false, - - // Force coverage collection from ignored files using an array of glob patterns - // forceCoverageMatch: [], - - // A path to a module which exports an async function that is triggered once before all test suites - // globalSetup: undefined, - - // A path to a module which exports an async function that is triggered once after all test suites - // globalTeardown: undefined, - - // A set of global variables that need to be available in all test environments - // globals: {}, - - // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. - // maxWorkers: "50%", - - // An array of directory names to be searched recursively up from the requiring module's location - // moduleDirectories: [ - // "node_modules" - // ], - - // An array of file extensions your modules use - // moduleFileExtensions: [ - // "js", - // "json", - // "jsx", - // "ts", - // "tsx", - // "node" - // ], - - // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module - // moduleNameMapper: {}, - - // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader - // modulePathIgnorePatterns: [], - - // Activates notifications for test results - // notify: false, - - // An enum that specifies notification mode. Requires { notify: true } - // notifyMode: "failure-change", - - // A preset that is used as a base for Jest's configuration - // preset: undefined, - - // Run tests from one or more projects - // projects: undefined, - - // Use this configuration option to add custom reporters to Jest - // reporters: undefined, - - // Automatically reset mock state between every test - // resetMocks: false, - - // Reset the module registry before running each individual test - // resetModules: false, - - // A path to a custom resolver - // resolver: undefined, - - // Automatically restore mock state between every test - // restoreMocks: false, - - // The root directory that Jest should scan for tests and modules within - // rootDir: undefined, - - // A list of paths to directories that Jest should use to search for files in - // roots: [ - // "" - // ], - - // Allows you to use a custom runner instead of Jest's default test runner - // runner: "jest-runner", - - // The paths to modules that run some code to configure or set up the testing environment before each test - // setupFiles: [], - - // A list of paths to modules that run some code to configure or set up the testing framework before each test - // setupFilesAfterEnv: [], - - // The number of seconds after which a test is considered as slow and reported as such in the results. - // slowTestThreshold: 5, - - // A list of paths to snapshot serializer modules Jest should use for snapshot testing - // snapshotSerializers: [], - - // The test environment that will be used for testing - testEnvironment: "node", - - // Options that will be passed to the testEnvironment - // testEnvironmentOptions: {}, - - // Adds a location field to test results - // testLocationInResults: false, - - // The glob patterns Jest uses to detect test files - // testMatch: [ - // "**/__tests__/**/*.[jt]s?(x)", - // "**/?(*.)+(spec|test).[tj]s?(x)" - // ], - - // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped - // testPathIgnorePatterns: [ - // "/node_modules/" - // ], - - // The regexp pattern or array of patterns that Jest uses to detect test files - // testRegex: [], - - // This option allows the use of a custom results processor - // testResultsProcessor: undefined, - - // This option allows use of a custom test runner - // testRunner: "jasmine2", - - // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href - // testURL: "http://localhost", - - // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" - // timers: "real", - - // A map from regular expressions to paths to transformers - // transform: undefined, - - // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation - // transformIgnorePatterns: [ - // "/node_modules/", - // "\\.pnp\\.[^\\/]+$" - // ], - - // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them - // unmockedModulePathPatterns: undefined, - - // Indicates whether each individual test should be reported during the run - // verbose: undefined, - - // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode - // watchPathIgnorePatterns: [], - - // Whether to use watchman for file crawling - // watchman: true, -}; diff --git a/package.json b/package.json index 9d55c5bcd3..c3b05cc09e 100644 --- a/package.json +++ b/package.json @@ -22,16 +22,12 @@ "@calcom/prisma": "*", "@calcom/tsconfig": "*", "babel-jest": "^27.5.1", - "install": "^0.13.0", "jest": "^27.5.1", "node-mocks-http": "^1.11.0", - "npm": "^8.5.5", "typescript": "^4.5.3", "zod": "^3.14.2" }, "dependencies": { - "@next-auth/prisma-adapter": "^1.0.1", - "next": "^12.1.0", - "next-auth": "^4.3.1" + "next": "^12.1.0" } } \ No newline at end of file From 3856d0768cca98c0664ff9568941326b0cfa9d6d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 23 Mar 2022 22:30:47 +0100 Subject: [PATCH 005/658] remove unneede env --- .env.local.example | 6 ------ .gitignore | 6 +----- 2 files changed, 1 insertion(+), 11 deletions(-) delete mode 100644 .env.local.example diff --git a/.env.local.example b/.env.local.example deleted file mode 100644 index fb2e751932..0000000000 --- a/.env.local.example +++ /dev/null @@ -1,6 +0,0 @@ -NEXTAUTH_URL=http://localhost:3000 // This requires you run also app.cal.com in localhost:3000 to re-use it's Next-Auth api endpoints. -NEXTAUTH_SECRET=hello -EMAIL_SERVER='smtp://localhost:587' -EMAIL_FROM=Cal.com - -DATABASE_URL="postgresql://postgres:@localhost:5450/calendso" diff --git a/.gitignore b/.gitignore index 0ab8183430..f1476ef06a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,6 @@ dist node_modules/ .env -<<<<<<< HEAD -.next -======= .next/ .turbo/ -.tsconfig.tsbuildinfo ->>>>>>> 5a71055 (feat: Initial work on event-types, add jest for testing w node-http-mocks) +*.tsbuildinfo From 9a8e63b729d3126bd0ec76c5f606d27e92aca82f Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 23 Mar 2022 22:32:46 +0100 Subject: [PATCH 006/658] resolve conflict w main --- .gitignore | 2 +- README.md | 2 +- jest.config.ts | 194 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 jest.config.ts diff --git a/.gitignore b/.gitignore index f1476ef06a..0d8832421a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ node_modules/ .env .next/ .turbo/ -*.tsbuildinfo +*.tsbuildinfo \ No newline at end of file diff --git a/README.md b/README.md index 8a01433f90..bb162f312a 100644 --- a/README.md +++ b/README.md @@ -22,4 +22,4 @@ It doesn't have react or react-dom as a dependency, and will only be used by a r The API uses `zod` library like our main web repo. It validates that either GET query parameters or POST body content's are valid and up to our spec. It gives appropiate errors when parsing result's with schemas. -## Testing with Jest + node-mocks-http \ No newline at end of file +## Testing with Jest + node-mocks-http diff --git a/jest.config.ts b/jest.config.ts new file mode 100644 index 0000000000..6045b4fa45 --- /dev/null +++ b/jest.config.ts @@ -0,0 +1,194 @@ +/* + * For a detailed explanation regarding each configuration property and type check, visit: + * https://jestjs.io/docs/en/configuration.html + */ + +export default { + // All imported modules in your tests should be mocked automatically + // automock: false, + + // Stop running tests after `n` failures + // bail: 0, + + // The directory where Jest should store its cached dependency information + // cacheDirectory: "/private/var/folders/fl/sw088bcs0dx4zyy0f_ghzvwc0000gn/T/jest_dx", + + // Automatically clear mock calls and instances between every test + clearMocks: true, + + // Indicates whether the coverage information should be collected while executing the test + // collectCoverage: false, + + // An array of glob patterns indicating a set of files for which coverage information should be collected + // collectCoverageFrom: undefined, + + // The directory where Jest should output its coverage files + coverageDirectory: "coverage", + + // An array of regexp pattern strings used to skip coverage collection + // coveragePathIgnorePatterns: [ + // "/node_modules/" + // ], + + // Indicates which provider should be used to instrument code for coverage + // coverageProvider: "babel", + + // A list of reporter names that Jest uses when writing coverage reports + // coverageReporters: [ + // "json", + // "text", + // "lcov", + // "clover" + // ], + + // An object that configures minimum threshold enforcement for coverage results + // coverageThreshold: undefined, + + // A path to a custom dependency extractor + // dependencyExtractor: undefined, + + // Make calling deprecated APIs throw helpful error messages + // errorOnDeprecated: false, + + // Force coverage collection from ignored files using an array of glob patterns + // forceCoverageMatch: [], + + // A path to a module which exports an async function that is triggered once before all test suites + // globalSetup: undefined, + + // A path to a module which exports an async function that is triggered once after all test suites + // globalTeardown: undefined, + + // A set of global variables that need to be available in all test environments + // globals: {}, + + // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. + // maxWorkers: "50%", + + // An array of directory names to be searched recursively up from the requiring module's location + // moduleDirectories: [ + // "node_modules" + // ], + + // An array of file extensions your modules use + // moduleFileExtensions: [ + // "js", + // "json", + // "jsx", + // "ts", + // "tsx", + // "node" + // ], + + // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module + // moduleNameMapper: {}, + + // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader + // modulePathIgnorePatterns: [], + + // Activates notifications for test results + // notify: false, + + // An enum that specifies notification mode. Requires { notify: true } + // notifyMode: "failure-change", + + // A preset that is used as a base for Jest's configuration + // preset: undefined, + + // Run tests from one or more projects + // projects: undefined, + + // Use this configuration option to add custom reporters to Jest + // reporters: undefined, + + // Automatically reset mock state between every test + // resetMocks: false, + + // Reset the module registry before running each individual test + // resetModules: false, + + // A path to a custom resolver + // resolver: undefined, + + // Automatically restore mock state between every test + // restoreMocks: false, + + // The root directory that Jest should scan for tests and modules within + // rootDir: undefined, + + // A list of paths to directories that Jest should use to search for files in + // roots: [ + // "" + // ], + + // Allows you to use a custom runner instead of Jest's default test runner + // runner: "jest-runner", + + // The paths to modules that run some code to configure or set up the testing environment before each test + // setupFiles: [], + + // A list of paths to modules that run some code to configure or set up the testing framework before each test + // setupFilesAfterEnv: [], + + // The number of seconds after which a test is considered as slow and reported as such in the results. + // slowTestThreshold: 5, + + // A list of paths to snapshot serializer modules Jest should use for snapshot testing + // snapshotSerializers: [], + + // The test environment that will be used for testing + testEnvironment: "node", + + // Options that will be passed to the testEnvironment + // testEnvironmentOptions: {}, + + // Adds a location field to test results + // testLocationInResults: false, + + // The glob patterns Jest uses to detect test files + // testMatch: [ + // "**/__tests__/**/*.[jt]s?(x)", + // "**/?(*.)+(spec|test).[tj]s?(x)" + // ], + + // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped + // testPathIgnorePatterns: [ + // "/node_modules/" + // ], + + // The regexp pattern or array of patterns that Jest uses to detect test files + // testRegex: [], + + // This option allows the use of a custom results processor + // testResultsProcessor: undefined, + + // This option allows use of a custom test runner + // testRunner: "jasmine2", + + // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href + // testURL: "http://localhost", + + // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" + // timers: "real", + + // A map from regular expressions to paths to transformers + // transform: undefined, + + // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation + // transformIgnorePatterns: [ + // "/node_modules/", + // "\\.pnp\\.[^\\/]+$" + // ], + + // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them + // unmockedModulePathPatterns: undefined, + + // Indicates whether each individual test should be reported during the run + // verbose: undefined, + + // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode + // watchPathIgnorePatterns: [], + + // Whether to use watchman for file crawling + // watchman: true, +}; From 60d2b81c29968ce6597a95e24b15c940b37a0d53 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 23 Mar 2022 18:56:31 +0100 Subject: [PATCH 007/658] feat: Initial work on event-types, add jest for testing w node-http-mocks --- .gitignore | 2 +- pages/api/auth/[...nextauth].ts | 82 +++++++++++++++++++++++++++++++++ 2 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 pages/api/auth/[...nextauth].ts diff --git a/.gitignore b/.gitignore index 0d8832421a..f1476ef06a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ node_modules/ .env .next/ .turbo/ -*.tsbuildinfo \ No newline at end of file +*.tsbuildinfo diff --git a/pages/api/auth/[...nextauth].ts b/pages/api/auth/[...nextauth].ts new file mode 100644 index 0000000000..d3d2886b06 --- /dev/null +++ b/pages/api/auth/[...nextauth].ts @@ -0,0 +1,82 @@ +import { PrismaAdapter } from "@next-auth/prisma-adapter"; +import { PrismaClient } from "@prisma/client"; +import NextAuth, { NextAuthOptions } from "next-auth"; +import EmailProvider from "next-auth/providers/email"; + +// FIXME: not working when importing prisma directly from our project +// import prisma from "@calcom/prisma"; +const prisma = new PrismaClient(); + +// TODO: get rid of this and do it in it's own auth.cal.com project with a custom Next.js app + +export const authOptions: NextAuthOptions = { + // For more information on each option (and a full list of options) go to + // https://next-auth.js.org/configuration/options + adapter: PrismaAdapter(prisma), + // https://next-auth.js.org/configuration/providers + providers: [ + EmailProvider({ + maxAge: 10 * 60 * 60, // Magic links are valid for 10 min only + // sendVerificationRequest, + }), + ], + secret: process.env.NEXTAUTH_SECRET, + session: { + // Use JSON Web Tokens for session instead of database sessions. + // This option can be used with or without a database for users/accounts. + // Note: `strategy` should be set to 'jwt' if no database is used. + + // TODO: Do we want to move 'database' sessions at some point? + strategy: "jwt", + // Seconds - How long until an idle session expires and is no longer valid. + // maxAge: 30 * 24 * 60 * 60, // 30 days + + // Seconds - Throttle how frequently to write to database to extend a session. + // Use it to limit write operations. Set to 0 to always update the database. + // Note: This option is ignored if using JSON Web Tokens + // updateAge: 24 * 60 * 60, // 24 hours + }, + + // JSON Web tokens are only used for sessions if the `strategy: 'jwt'` session + // option is set - or by default if no database is specified. + // https://next-auth.js.org/configuration/options#jwt + jwt: { + // A secret to use for key generation (you should set this explicitly) + secret: process.env.SECRET, + // Set to true to use encryption (default: false) + // encryption: true, + // You can define your own encode/decode functions for signing and encryption + // if you want to override the default behaviour. + // encode: async ({ secret, token, maxAge }) => {}, + // decode: async ({ secret, token, maxAge }) => {}, + }, + // https://next-auth.js.org/configuration/pages + // NOTE: We don't want to enable these, only the API endpoints for auth. We will get rid of this when we do auth.cal.com + pages: { + signIn: "/", // Displays signin buttons + signOut: "/", // Displays form with sign out button + error: "/", // Error code passed in query string as ?error= + verifyRequest: "/", // Used for check email page + newUser: "/", // If set, new users will be directed here on first sign in + }, + + // Callbacks are asynchronous functions you can use to control what happens + // when an action is performed. + // https://next-auth.js.org/configuration/callbacks + + callbacks: { + // async signIn({ user, account, profile, email, credentials }) { return true }, + // async redirect({ url, baseUrl }) { return baseUrl }, + // async session({ session, token, user }) { return session }, + // FIXME: add a custom jwt callback, that is stored outside next-auth + // and can be reused to generate valid Personal Access Tokens for the API. + // async jwt({ token, user, account, profile, isNewUser }) { return token } + }, + + // Events are useful for logging + // https://next-auth.js.org/configuration/events + + // Enable debug messages in the console if you are having problems + debug: false, +}; +export default NextAuth(authOptions); From b753466bda4cdd0a556f3144813124c2d6ec7b2a Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 24 Mar 2022 17:02:33 +0100 Subject: [PATCH 008/658] moving to nextjs/api --- .eslintrc.js | 1 + __tests__/event-types.test.ts | 5 ++ package.json | 4 +- pages/api/auth/[...nextauth].ts | 82 --------------------------------- pages/api/me/index.ts | 36 --------------- tsconfig.json | 4 ++ 6 files changed, 12 insertions(+), 120 deletions(-) create mode 100644 .eslintrc.js delete mode 100644 pages/api/auth/[...nextauth].ts delete mode 100644 pages/api/me/index.ts diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000000..0e71ec1eae --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require("@calcom/config/eslint-preset"); diff --git a/__tests__/event-types.test.ts b/__tests__/event-types.test.ts index f4c46be3ed..2aea868136 100644 --- a/__tests__/event-types.test.ts +++ b/__tests__/event-types.test.ts @@ -5,6 +5,11 @@ import { EventType } from "@calcom/prisma/client"; import handleEvent from "../pages/api/event-types/[id]"; +afterAll((done) => { + prisma.$disconnect().then(); + done(); +}); + describe("/api/event-types/[id]", () => { it("returns a message with the specified events", async () => { const { req, res } = createMocks({ diff --git a/package.json b/package.json index c3b05cc09e..d305999874 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "start": "next start", "build": "next build", "lint": "next lint", - "test": "jest", + "test": "jest --detectOpenHandles", "type-check": "tsc --pretty --noEmit", "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist" }, @@ -30,4 +30,4 @@ "dependencies": { "next": "^12.1.0" } -} \ No newline at end of file +} diff --git a/pages/api/auth/[...nextauth].ts b/pages/api/auth/[...nextauth].ts deleted file mode 100644 index d3d2886b06..0000000000 --- a/pages/api/auth/[...nextauth].ts +++ /dev/null @@ -1,82 +0,0 @@ -import { PrismaAdapter } from "@next-auth/prisma-adapter"; -import { PrismaClient } from "@prisma/client"; -import NextAuth, { NextAuthOptions } from "next-auth"; -import EmailProvider from "next-auth/providers/email"; - -// FIXME: not working when importing prisma directly from our project -// import prisma from "@calcom/prisma"; -const prisma = new PrismaClient(); - -// TODO: get rid of this and do it in it's own auth.cal.com project with a custom Next.js app - -export const authOptions: NextAuthOptions = { - // For more information on each option (and a full list of options) go to - // https://next-auth.js.org/configuration/options - adapter: PrismaAdapter(prisma), - // https://next-auth.js.org/configuration/providers - providers: [ - EmailProvider({ - maxAge: 10 * 60 * 60, // Magic links are valid for 10 min only - // sendVerificationRequest, - }), - ], - secret: process.env.NEXTAUTH_SECRET, - session: { - // Use JSON Web Tokens for session instead of database sessions. - // This option can be used with or without a database for users/accounts. - // Note: `strategy` should be set to 'jwt' if no database is used. - - // TODO: Do we want to move 'database' sessions at some point? - strategy: "jwt", - // Seconds - How long until an idle session expires and is no longer valid. - // maxAge: 30 * 24 * 60 * 60, // 30 days - - // Seconds - Throttle how frequently to write to database to extend a session. - // Use it to limit write operations. Set to 0 to always update the database. - // Note: This option is ignored if using JSON Web Tokens - // updateAge: 24 * 60 * 60, // 24 hours - }, - - // JSON Web tokens are only used for sessions if the `strategy: 'jwt'` session - // option is set - or by default if no database is specified. - // https://next-auth.js.org/configuration/options#jwt - jwt: { - // A secret to use for key generation (you should set this explicitly) - secret: process.env.SECRET, - // Set to true to use encryption (default: false) - // encryption: true, - // You can define your own encode/decode functions for signing and encryption - // if you want to override the default behaviour. - // encode: async ({ secret, token, maxAge }) => {}, - // decode: async ({ secret, token, maxAge }) => {}, - }, - // https://next-auth.js.org/configuration/pages - // NOTE: We don't want to enable these, only the API endpoints for auth. We will get rid of this when we do auth.cal.com - pages: { - signIn: "/", // Displays signin buttons - signOut: "/", // Displays form with sign out button - error: "/", // Error code passed in query string as ?error= - verifyRequest: "/", // Used for check email page - newUser: "/", // If set, new users will be directed here on first sign in - }, - - // Callbacks are asynchronous functions you can use to control what happens - // when an action is performed. - // https://next-auth.js.org/configuration/callbacks - - callbacks: { - // async signIn({ user, account, profile, email, credentials }) { return true }, - // async redirect({ url, baseUrl }) { return baseUrl }, - // async session({ session, token, user }) { return session }, - // FIXME: add a custom jwt callback, that is stored outside next-auth - // and can be reused to generate valid Personal Access Tokens for the API. - // async jwt({ token, user, account, profile, isNewUser }) { return token } - }, - - // Events are useful for logging - // https://next-auth.js.org/configuration/events - - // Enable debug messages in the console if you are having problems - debug: false, -}; -export default NextAuth(authOptions); diff --git a/pages/api/me/index.ts b/pages/api/me/index.ts deleted file mode 100644 index 86010001e5..0000000000 --- a/pages/api/me/index.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { PrismaClient } from "@prisma/client"; -import type { NextApiRequest, NextApiResponse } from "next"; -import { getToken } from "next-auth/jwt"; - -// This local import doesn't work -// import { PrismaClient } from "@calcom/prisma"; -const prisma = new PrismaClient(); -const secret = process.env.NEXTAUTH_SECRET; - -type Data = { - message: string; -}; - -export default async function me(req: NextApiRequest, res: NextApiResponse) { - const token = await getToken({ req, secret, raw: false }); - console.log("token", token); - if (!token) - return res.status(404).json({ - message: `You're not authenticated. Provide a valid Session JWT as Authorization: 'Bearer {your_token_here}'`, - }); - if (!token.email) - return res.status(404).json({ - message: `Your token doesn't have a valid email`, - }); - const email: string | undefined = token?.email; - const user = await prisma.user.findUnique({ - where: { - email: email, - }, - }); - return res.json({ - message: `Hello ${user?.name}, your email is ${user?.email}, and your email is ${ - user?.emailVerified ? "verified" : "unverified" - }`, - }); -} diff --git a/tsconfig.json b/tsconfig.json index b93f1e08a5..bc4d4d4777 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,6 +4,10 @@ "node_modules" ], "compilerOptions": { + "lib": ["ES2015"], + "module": "CommonJS", + "outDir": "./dist", + "rootDir": "./", "strictNullChecks": true, "baseUrl": "./", }, From c5b12d46af2e18f9a31268f1156bcf12da4c119f Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 24 Mar 2022 19:01:37 +0100 Subject: [PATCH 009/658] chore: rename return types to Data, import prisma from @calcom/prisma --- package.json | 3 ++- pages/api/event-types/[id].ts | 6 +++--- pages/api/event-types/index.ts | 10 +++++----- pages/api/event-types/new.ts | 9 +++++---- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index d305999874..1b9504d975 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "zod": "^3.14.2" }, "dependencies": { - "next": "^12.1.0" + "next": "^12.1.0", + "zod": "^3.14.2" } } diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 5fc6352723..508a917572 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -1,14 +1,14 @@ -import { EventType } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; +import { EventType } from "@calcom/prisma/client"; -type EventIdData = { +type Data = { event?: EventType; error?: any; }; -export default async function eventType(req: NextApiRequest, res: NextApiResponse) { +export default async function eventType(req: NextApiRequest, res: NextApiResponse) { try { const event = await prisma.eventType.findUnique({ where: { id: Number(req.query.id) } }); res.status(200).json({ event }); diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 864d657c40..edcd6d6270 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -1,14 +1,14 @@ -import { PrismaClient, EventType } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -type EventTypeIdData = { +import prisma from "@calcom/prisma"; +import { EventType } from "@calcom/prisma/client"; + +type Data = { events?: EventType[]; error?: any; }; -const prisma = new PrismaClient(); - -export default async function eventType(req: NextApiRequest, res: NextApiResponse) { +export default async function eventType(req: NextApiRequest, res: NextApiResponse) { try { const eventTypes = await prisma.eventType.findMany({ where: { id: Number(req.query.eventTypeId) } }); res.status(200).json({ events: { ...eventTypes } }); diff --git a/pages/api/event-types/new.ts b/pages/api/event-types/new.ts index b4b56ba303..529d0151c3 100644 --- a/pages/api/event-types/new.ts +++ b/pages/api/event-types/new.ts @@ -1,7 +1,8 @@ -import { PrismaClient, EventType } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -const prisma = new PrismaClient(); +import prisma from "@calcom/prisma"; +import { EventType } from "@calcom/prisma/client"; + interface Body { userId: string; @@ -10,12 +11,12 @@ interface Body { users: string[]; }; } -type EventsData = { +type Data = { event?: EventType; error?: string; }; -export default async function createEventLink(req: NextApiRequest, res: NextApiResponse) { +export default async function createEventLink(req: NextApiRequest, res: NextApiResponse) { const { body: { title, From 713f53acc4843ac7195703ba05c2b3897334faad Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 24 Mar 2022 21:25:35 +0100 Subject: [PATCH 010/658] feat: add next-validations and zod validations --- package.json | 1 + pages/api/event-types/[id].ts | 50 +++++++++++---- pages/api/event-types/index.ts | 13 ++-- pages/api/event-types/new.ts | 107 +++++++++++---------------------- pages/api/users/[id].ts | 6 +- pages/api/users/valid.ts | 19 ++++++ tsconfig.json | 16 +++-- 7 files changed, 114 insertions(+), 98 deletions(-) create mode 100644 pages/api/users/valid.ts diff --git a/package.json b/package.json index 1b9504d975..135808bdf2 100644 --- a/package.json +++ b/package.json @@ -29,6 +29,7 @@ }, "dependencies": { "next": "^12.1.0", + "next-validations": "^0.1.11", "zod": "^3.14.2" } } diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 508a917572..112f64937b 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -1,19 +1,47 @@ +import { PrismaClient, EventType } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; +import { withValidation } from "next-validations"; +import { z } from "zod"; -import prisma from "@calcom/prisma"; -import { EventType } from "@calcom/prisma/client"; +const prisma = new PrismaClient(); -type Data = { - event?: EventType; +const schema = z + .object({ + id: z + .string() + .regex(/^\d+$/) + .transform((id) => parseInt(id)), + }) + .strict(); + +const validate = withValidation({ + schema, + type: "Zod", + mode: "query", +}); + +type ResponseData = { + data?: EventType; error?: any; }; -export default async function eventType(req: NextApiRequest, res: NextApiResponse) { - try { - const event = await prisma.eventType.findUnique({ where: { id: Number(req.query.id) } }); - res.status(200).json({ event }); - } catch (error) { - console.log(error); - res.status(400).json({ error: error }); +export async function eventType(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + if (method === "GET") { + const safe = await schema.safeParse(query); + if (safe.success) { + try { + const event = await prisma.eventType.findUnique({ where: { id: safe.data.id } }); + res.status(200).json({ data: event }); + } catch (error) { + console.log(error); + res.status(400).json({ error: error }); + } + } + } else { + // Reject any other HTTP method than POST + res.status(405).json({ error: "Only GET Method allowed" }); } } + +export default validate(eventType); diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index edcd6d6270..49c69583c8 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -1,17 +1,16 @@ +import { PrismaClient, EventType } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; -import { EventType } from "@calcom/prisma/client"; - -type Data = { - events?: EventType[]; +const prisma = new PrismaClient(); +type ResponseData = { + data?: EventType[]; error?: any; }; -export default async function eventType(req: NextApiRequest, res: NextApiResponse) { +export default async function eventType(req: NextApiRequest, res: NextApiResponse) { try { const eventTypes = await prisma.eventType.findMany({ where: { id: Number(req.query.eventTypeId) } }); - res.status(200).json({ events: { ...eventTypes } }); + res.status(200).json({ data: { ...eventTypes } }); } catch (error) { console.log(error); // FIXME: Add zod for validation/error handling diff --git a/pages/api/event-types/new.ts b/pages/api/event-types/new.ts index 529d0151c3..a9fc7d770e 100644 --- a/pages/api/event-types/new.ts +++ b/pages/api/event-types/new.ts @@ -1,86 +1,49 @@ +import { PrismaClient, EventType } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; +import { withValidation } from "next-validations"; +import { z } from "zod"; -import prisma from "@calcom/prisma"; -import { EventType } from "@calcom/prisma/client"; +const prisma = new PrismaClient(); + +const schema = z + .object({ + title: z.string().min(3), + slug: z.string().min(3), + length: z.number().min(1).max(1440), // max is a full day. + description: z.string().min(3).optional(), + }) + .strict(); // Adding strict so that we can disallow passing in extra fields + +const validate = withValidation({ + schema, + type: "Zod", + mode: "body", +}); interface Body { - userId: string; - - newOrganization: { - name: string; - users: string[]; - }; + title: string; + slug: string; + length: number; } type Data = { - event?: EventType; + data?: EventType; error?: string; }; -export default async function createEventLink(req: NextApiRequest, res: NextApiResponse) { - const { - body: { - title, - slug, - description, - position, - locations, - hidden, - teamId, - eventName, - timeZone, - periodType, - periodStartDate, - periodEndDate, - periodDays, - periodCountCalendarDays, - requiresConfirmation, - disableGuests, - minimumBookingNotice, - beforeEventBuffer, - afterEventBuffer, - schedulingType, - price, - currency, - slotInterval, - metadata, - length, - }, - method, - } = req; +type NextApiRequestWithBody = NextApiRequest & { + body: Body; +}; + +async function createEventType(req: NextApiRequestWithBody, res: NextApiResponse) { + const { body, method }: { body: Body; method?: string } = req; if (method === "POST") { - // Process a POST request - const newEvent = await prisma.eventType.create({ - data: { - title: `${title}`, - slug: `${slug}`, - length: Number(length), - // description: description as string, - // position: Number(position), - // locations: locations, - // hidden: Boolean(hidden) as boolean, - // teamId: Number.isInteger(teamId) ? Number(teamId) : null, - // eventName: eventName, - // timeZone: timeZone, - // periodType: periodType, - // periodStartDate: periodStartDate, - // periodEndDate: periodEndDate, - // periodDays: periodDays, - // periodCountCalendarDays: periodCountCalendarDays, - // requiresConfirmation: requiresConfirmation, - // disableGuests: disableGuests, - // minimumBookingNotice: minimumBookingNotice, - // beforeEventBuffer: beforeEventBuffer, - // afterEventBuffer: afterEventBuffer, - // schedulingType: schedulingType, - // price: price, - // currency: currency, - // slotInterval: slotInterval, - // metadata: metadata, - }, - }); - res.status(201).json({ event: newEvent }); + schema.safeParse(body); + const newEvent = await prisma.eventType.create({ data: body }); + res.status(201).json({ data: newEvent }); } else { - // Handle any other HTTP method + // Reject any other HTTP method than POST res.status(405).json({ error: "Only POST Method allowed" }); } } + +export default validate(createEventType); diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index 07618f8dc4..9a9cb8fc3f 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -1,9 +1,7 @@ -import { PrismaClient } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -// This local import doesn't work -// import { PrismaClient } from "@calcom/prisma"; -const prisma = new PrismaClient(); +import prisma from "@calcom/prisma"; +import { User } from "@calcom/prisma/client"; type Data = { message: string; diff --git a/pages/api/users/valid.ts b/pages/api/users/valid.ts new file mode 100644 index 0000000000..81a4b3c94a --- /dev/null +++ b/pages/api/users/valid.ts @@ -0,0 +1,19 @@ +import { NextApiRequest, NextApiResponse } from "next"; +import { withValidation } from "next-validations"; +import { z } from "zod"; + +const schema = z.object({ + username: z.string().min(6), +}); + +const validate = withValidation({ + schema, + type: "Zod", + mode: "body", +}); + +const handler = (req: NextApiRequest, res: NextApiResponse) => { + res.status(200).json(req.body); +}; + +export default validate(handler); diff --git a/tsconfig.json b/tsconfig.json index bc4d4d4777..e77f9df418 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -4,12 +4,20 @@ "node_modules" ], "compilerOptions": { - "lib": ["ES2015"], - "module": "CommonJS", - "outDir": "./dist", - "rootDir": "./", "strictNullChecks": true, "baseUrl": "./", + "target": "es5", + "lib": [ + "dom", + "dom.iterable", + "esnext" + ], + "allowJs": true, + "noEmit": true, + "incremental": true, + "module": "esnext", + "resolveJsonModule": true, + "jsx": "preserve" }, "include": [ "./pages/api/*.ts" From dfa227f1b6097c0273f4b6c54324c20071ae4e39 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 24 Mar 2022 23:10:24 +0100 Subject: [PATCH 011/658] adds testing for validations --- __tests__/event-types.test.ts | 38 ++++++++++++++++++++++++++++------- pages/api/event-types/[id].ts | 19 +++++++++++------- pages/api/event-types/new.ts | 30 ++++++++++++++++++--------- tsconfig.json | 2 +- 4 files changed, 64 insertions(+), 25 deletions(-) diff --git a/__tests__/event-types.test.ts b/__tests__/event-types.test.ts index 2aea868136..d6eb7fe57f 100644 --- a/__tests__/event-types.test.ts +++ b/__tests__/event-types.test.ts @@ -1,7 +1,6 @@ import { createMocks } from "node-mocks-http"; import prisma from "@calcom/prisma"; -import { EventType } from "@calcom/prisma/client"; import handleEvent from "../pages/api/event-types/[id]"; @@ -15,13 +14,38 @@ describe("/api/event-types/[id]", () => { const { req, res } = createMocks({ method: "GET", query: { - id: 1, + id: "1", }, }); - prisma.eventType.findUnique({ where: { id: 1 } }).then(async (data: EventType) => { - await handleEvent(req, res); - expect(res._getStatusCode()).toBe(200); - expect(JSON.parse(res._getData())).toStrictEqual({ event: data }); - }); + const event = await prisma.eventType.findUnique({ where: { id: 1 } }); + await handleEvent(req, res); + + expect(res._getStatusCode()).toBe(200); + expect(JSON.parse(res._getData())).toStrictEqual({ data: event }); + }); +}); + +// This can never happen under our normal nextjs setup where query is always a string | string[]. +// But seemed a good example for testing an error validation +describe("/api/event-types/[id] errors if query id is number, requires a string", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "GET", + query: { + id: 1, // passing query as a number, which should fail as nextjs will try to parse it as a string + }, + }); + await handleEvent(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(JSON.parse(res._getData())).toStrictEqual([ + { + code: "invalid_type", + expected: "string", + received: "number", + path: ["id"], + message: "Expected string, received number", + }, + ]); }); }); diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 112f64937b..7ecc4362c9 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -28,15 +28,20 @@ type ResponseData = { export async function eventType(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; if (method === "GET") { - const safe = await schema.safeParse(query); - if (safe.success) { - try { + try { + const safe = await schema.safeParse(query); + // if (!safe.success) { + // res.status(500).json({ error: safe.error.message }); + // } + if (safe.success) { const event = await prisma.eventType.findUnique({ where: { id: safe.data.id } }); - res.status(200).json({ data: event }); - } catch (error) { - console.log(error); - res.status(400).json({ error: error }); + + if (event) res.status(200).json({ data: event }); + if (!event) res.status(404).json({ error: "Event type not found" }); } + } catch (error) { + console.log("catched", error); + res.status(500).json({ error: error }); } } else { // Reject any other HTTP method than POST diff --git a/pages/api/event-types/new.ts b/pages/api/event-types/new.ts index a9fc7d770e..f294a259bb 100644 --- a/pages/api/event-types/new.ts +++ b/pages/api/event-types/new.ts @@ -14,32 +14,42 @@ const schema = z }) .strict(); // Adding strict so that we can disallow passing in extra fields +type schema = z.infer; const validate = withValidation({ schema, type: "Zod", mode: "body", }); -interface Body { - title: string; - slug: string; - length: number; -} +// interface Body { +// title: string; +// slug: string; +// length: number; +// } type Data = { data?: EventType; error?: string; }; type NextApiRequestWithBody = NextApiRequest & { - body: Body; + // body: Body; }; async function createEventType(req: NextApiRequestWithBody, res: NextApiResponse) { - const { body, method }: { body: Body; method?: string } = req; + const { body, method } = req; if (method === "POST") { - schema.safeParse(body); - const newEvent = await prisma.eventType.create({ data: body }); - res.status(201).json({ data: newEvent }); + const safe = schema.safeParse(body); + if (safe.success && safe.data) { + await prisma.eventType + .create({ + data: { title: safe.data.title, slug: safe.data.slug, length: safe.data.length }, + }) + .then((event) => res.status(201).json({ data: event })) + .catch((error) => { + console.log(error); + res.status(400).json({ error: "Could not create event type" }); + }); + } } else { // Reject any other HTTP method than POST res.status(405).json({ error: "Only POST Method allowed" }); diff --git a/tsconfig.json b/tsconfig.json index e77f9df418..8581d9636a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,6 +20,6 @@ "jsx": "preserve" }, "include": [ - "./pages/api/*.ts" + "./" ] } From 84ab74b46a05a3bd7c2084358af82dafb510beff Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 24 Mar 2022 23:16:48 +0100 Subject: [PATCH 012/658] feat: tests all codepaths of event-type/[id] --- __tests__/event-types.test.ts | 32 +++++++++++++++++++++++++++++++- pages/api/event-types/[id].ts | 20 +++++++------------- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/__tests__/event-types.test.ts b/__tests__/event-types.test.ts index d6eb7fe57f..2a76abd3cd 100644 --- a/__tests__/event-types.test.ts +++ b/__tests__/event-types.test.ts @@ -9,7 +9,7 @@ afterAll((done) => { done(); }); -describe("/api/event-types/[id]", () => { +describe("/api/event-types/[id] with valid id as string returns an event-type", () => { it("returns a message with the specified events", async () => { const { req, res } = createMocks({ method: "GET", @@ -49,3 +49,33 @@ describe("/api/event-types/[id] errors if query id is number, requires a string" ]); }); }); + +describe("/api/event-types/[id] an id not present in db like 0, throws 404 not found", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "GET", + query: { + id: "0", // There's no event type with id 0 + }, + }); + await handleEvent(req, res); + + expect(res._getStatusCode()).toBe(404); + expect(JSON.parse(res._getData())).toStrictEqual({ error: "Event type not found" }); + }); +}); + +describe("/api/event-types/[id] only allow GET, fails with POST", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + query: { + id: "1", + }, + }); + await handleEvent(req, res); + + expect(res._getStatusCode()).toBe(405); + expect(JSON.parse(res._getData())).toStrictEqual({ error: "Only GET Method allowed" }); + }); +}); diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 7ecc4362c9..8694d32c38 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -7,6 +7,8 @@ const prisma = new PrismaClient(); const schema = z .object({ + // since nextjs parses query params as strings, + // we need to cast them to numbers using z.transform() and parseInt() id: z .string() .regex(/^\d+$/) @@ -28,20 +30,12 @@ type ResponseData = { export async function eventType(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; if (method === "GET") { - try { - const safe = await schema.safeParse(query); - // if (!safe.success) { - // res.status(500).json({ error: safe.error.message }); - // } - if (safe.success) { - const event = await prisma.eventType.findUnique({ where: { id: safe.data.id } }); + const safe = await schema.safeParse(query); + if (safe.success) { + const event = await prisma.eventType.findUnique({ where: { id: safe.data.id } }); - if (event) res.status(200).json({ data: event }); - if (!event) res.status(404).json({ error: "Event type not found" }); - } - } catch (error) { - console.log("catched", error); - res.status(500).json({ error: error }); + if (event) res.status(200).json({ data: event }); + if (!event) res.status(404).json({ error: "Event type not found" }); } } else { // Reject any other HTTP method than POST From e4d9f7bc7db37568c950c6468ee48bf74d9ff05a Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 24 Mar 2022 23:19:13 +0100 Subject: [PATCH 013/658] remove example validation file --- pages/api/users/valid.ts | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 pages/api/users/valid.ts diff --git a/pages/api/users/valid.ts b/pages/api/users/valid.ts deleted file mode 100644 index 81a4b3c94a..0000000000 --- a/pages/api/users/valid.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { NextApiRequest, NextApiResponse } from "next"; -import { withValidation } from "next-validations"; -import { z } from "zod"; - -const schema = z.object({ - username: z.string().min(6), -}); - -const validate = withValidation({ - schema, - type: "Zod", - mode: "body", -}); - -const handler = (req: NextApiRequest, res: NextApiResponse) => { - res.status(200).json(req.body); -}; - -export default validate(handler); From 737a8897bafa6cf4d16a67e44da279b2b2015a7d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 25 Mar 2022 00:04:07 +0100 Subject: [PATCH 014/658] extracting out schemaQuery validation to lib, extracting out delete/edit to it's own files for clarity --- .../[id]/index.test.ts} | 10 ++-- lib/validations/queryIdTransformParseInt.ts | 15 ++++++ pages/api/event-types/[id]/delete.ts | 42 ++++++++++++++++ pages/api/event-types/[id]/edit.ts | 49 +++++++++++++++++++ .../event-types/{[id].ts => [id]/index.ts} | 44 ++++++++--------- pages/api/event-types/new.ts | 2 +- tsconfig.json | 6 +-- 7 files changed, 135 insertions(+), 33 deletions(-) rename __tests__/{event-types.test.ts => event-types/[id]/index.test.ts} (83%) create mode 100644 lib/validations/queryIdTransformParseInt.ts create mode 100644 pages/api/event-types/[id]/delete.ts create mode 100644 pages/api/event-types/[id]/edit.ts rename pages/api/event-types/{[id].ts => [id]/index.ts} (55%) diff --git a/__tests__/event-types.test.ts b/__tests__/event-types/[id]/index.test.ts similarity index 83% rename from __tests__/event-types.test.ts rename to __tests__/event-types/[id]/index.test.ts index 2a76abd3cd..4c3cfc655b 100644 --- a/__tests__/event-types.test.ts +++ b/__tests__/event-types/[id]/index.test.ts @@ -2,14 +2,14 @@ import { createMocks } from "node-mocks-http"; import prisma from "@calcom/prisma"; -import handleEvent from "../pages/api/event-types/[id]"; +import handleEvent from "../../../pages/api/event-types/[id]"; afterAll((done) => { prisma.$disconnect().then(); done(); }); -describe("/api/event-types/[id] with valid id as string returns an event-type", () => { +describe("GET /api/event-types/[id] with valid id as string returns an event-type", () => { it("returns a message with the specified events", async () => { const { req, res } = createMocks({ method: "GET", @@ -27,7 +27,7 @@ describe("/api/event-types/[id] with valid id as string returns an event-type", // This can never happen under our normal nextjs setup where query is always a string | string[]. // But seemed a good example for testing an error validation -describe("/api/event-types/[id] errors if query id is number, requires a string", () => { +describe("GET /api/event-types/[id] errors if query id is number, requires a string", () => { it("returns a message with the specified events", async () => { const { req, res } = createMocks({ method: "GET", @@ -50,7 +50,7 @@ describe("/api/event-types/[id] errors if query id is number, requires a string" }); }); -describe("/api/event-types/[id] an id not present in db like 0, throws 404 not found", () => { +describe("GET /api/event-types/[id] an id not present in db like 0, throws 404 not found", () => { it("returns a message with the specified events", async () => { const { req, res } = createMocks({ method: "GET", @@ -65,7 +65,7 @@ describe("/api/event-types/[id] an id not present in db like 0, throws 404 not f }); }); -describe("/api/event-types/[id] only allow GET, fails with POST", () => { +describe("POST /api/event-types/[id] fails, only GET allowed", () => { it("returns a message with the specified events", async () => { const { req, res } = createMocks({ method: "POST", // This POST method is not allowed diff --git a/lib/validations/queryIdTransformParseInt.ts b/lib/validations/queryIdTransformParseInt.ts new file mode 100644 index 0000000000..e90f1735ce --- /dev/null +++ b/lib/validations/queryIdTransformParseInt.ts @@ -0,0 +1,15 @@ +import { z } from "zod"; + +// Extracted out as utility function so can be reused +// at different endpoints that require this validation. +const schema = z + .object({ + // since nextjs parses query params as strings, + // we need to cast them to numbers using z.transform() and parseInt() + id: z + .string() + .regex(/^\d+$/) + .transform((id) => parseInt(id)), + }) + .strict(); +export default schema; diff --git a/pages/api/event-types/[id]/delete.ts b/pages/api/event-types/[id]/delete.ts new file mode 100644 index 0000000000..038a23d734 --- /dev/null +++ b/pages/api/event-types/[id]/delete.ts @@ -0,0 +1,42 @@ +import { PrismaClient, EventType } from "@prisma/client"; +import schema from "lib/validations/queryIdTransformParseInt"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { withValidation } from "next-validations"; + +const prisma = new PrismaClient(); + +type ResponseData = { + message?: string; + error?: any; +}; + +export async function eventType(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schema.safeParse(query); + if (safe.success) { + if (method === "DELETE") { + // DELETE WILL DELETE THE EVENT TYPE + prisma.eventType + .delete({ where: { id: safe.data.id } }) + .then(() => { + // We only remove the event type from the database if there's an existing resource. + res.status(200).json({ message: `event-type with id: ${safe.data.id} deleted successfully` }); + }) + .catch((error) => { + // This catches the error thrown by prisma.eventType.delete() if the resource is not found. + res.status(400).json({ error: error }); + }); + } else { + // Reject any other HTTP method than POST + res.status(405).json({ error: "Only DELETE Method allowed in /event-types/[id]/delete endpoint" }); + } + } +} + +const validate = withValidation({ + schema, + type: "Zod", + mode: "query", +}); + +export default validate(eventType); diff --git a/pages/api/event-types/[id]/edit.ts b/pages/api/event-types/[id]/edit.ts new file mode 100644 index 0000000000..34c55b296b --- /dev/null +++ b/pages/api/event-types/[id]/edit.ts @@ -0,0 +1,49 @@ +import { PrismaClient, EventType } from "@prisma/client"; +import schemaQuery from "lib/validations/queryIdTransformParseInt"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { withValidation } from "next-validations"; +import { z } from "zod"; + +const prisma = new PrismaClient(); + +const schema = z + .object({ + title: z.string().min(3), + slug: z.string().min(3), + length: z.number().min(1).max(1440), // max is a full day. + description: z.string().min(3).optional(), + }) + .strict(); // Adding strict so that we can disallow passing in extra fields + +type ResponseData = { + data?: EventType; + error?: any; +}; + +export async function editEventType(req: NextApiRequest, res: NextApiResponse) { + const { query, body, method } = req; + const safeQuery = await schemaQuery.safeParse(query); + const safeBody = await schema.safeParse(body); + + if (safeQuery.success && safeBody.success) { + if (method === "PATCH") { + const event = await prisma.eventType.update({ + where: { id: safeQuery.data.id }, + data: { ...safeBody.data }, + }); + if (event) res.status(200).json({ data: event }); + if (!event) res.status(404).json({ error: "Event type not found" }); + } else { + // Reject any other HTTP method than POST + res.status(405).json({ error: "Only GET Method allowed" }); + } + } +} + +const validate = withValidation({ + schema, + type: "Zod", + mode: "body", +}); + +export default validate(editEventType); diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id]/index.ts similarity index 55% rename from pages/api/event-types/[id].ts rename to pages/api/event-types/[id]/index.ts index 8694d32c38..5fb6a6a519 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id]/index.ts @@ -1,27 +1,10 @@ import { PrismaClient, EventType } from "@prisma/client"; +import schema from "lib/validations/queryIdTransformParseInt"; import type { NextApiRequest, NextApiResponse } from "next"; import { withValidation } from "next-validations"; -import { z } from "zod"; const prisma = new PrismaClient(); -const schema = z - .object({ - // since nextjs parses query params as strings, - // we need to cast them to numbers using z.transform() and parseInt() - id: z - .string() - .regex(/^\d+$/) - .transform((id) => parseInt(id)), - }) - .strict(); - -const validate = withValidation({ - schema, - type: "Zod", - mode: "query", -}); - type ResponseData = { data?: EventType; error?: any; @@ -29,18 +12,31 @@ type ResponseData = { export async function eventType(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; - if (method === "GET") { - const safe = await schema.safeParse(query); - if (safe.success) { + const safe = await schema.safeParse(query); + if (safe.success) { + if (method === "GET") { const event = await prisma.eventType.findUnique({ where: { id: safe.data.id } }); if (event) res.status(200).json({ data: event }); if (!event) res.status(404).json({ error: "Event type not found" }); + } else if (method === "PATCH") { + const event = await prisma.eventType.update({ + where: { id: safe.data.id }, + data: { title: "Updated title" }, + }); + if (event) res.status(200).json({ data: event }); + if (!event) res.status(404).json({ error: "Event type not found" }); + } else { + // Reject any other HTTP method than POST + res.status(405).json({ error: "Only GET Method allowed" }); } - } else { - // Reject any other HTTP method than POST - res.status(405).json({ error: "Only GET Method allowed" }); } } +const validate = withValidation({ + schema, + type: "Zod", + mode: "query", +}); + export default validate(eventType); diff --git a/pages/api/event-types/new.ts b/pages/api/event-types/new.ts index f294a259bb..baf590a4d8 100644 --- a/pages/api/event-types/new.ts +++ b/pages/api/event-types/new.ts @@ -14,7 +14,7 @@ const schema = z }) .strict(); // Adding strict so that we can disallow passing in extra fields -type schema = z.infer; +// type schema = z.infer; const validate = withValidation({ schema, type: "Zod", diff --git a/tsconfig.json b/tsconfig.json index 8581d9636a..67dc71427a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,7 +5,7 @@ ], "compilerOptions": { "strictNullChecks": true, - "baseUrl": "./", + "baseUrl": ".", "target": "es5", "lib": [ "dom", @@ -17,9 +17,9 @@ "incremental": true, "module": "esnext", "resolveJsonModule": true, - "jsx": "preserve" + "jsx": "preserve", }, "include": [ - "./" + "./**/*.ts" ] } From f4d889e87b41c510cd1d326e5d62785a31ddb31b Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 25 Mar 2022 00:43:35 +0100 Subject: [PATCH 015/658] add @lib and @api paths for cleaner imports --- jest.config.ts | 4 +- lib/validation/eventType.ts | 12 ++ .../queryIdTransformParseInt.ts | 0 package.json | 3 +- pages/api/event-types/[id]/delete.ts | 3 +- pages/api/event-types/[id]/edit.ts | 14 +- pages/api/event-types/[id]/index.ts | 3 +- pages/api/event-types/new.ts | 26 +-- tsconfig.json | 5 + yarn-error.log | 200 ++++++++++++++++++ 10 files changed, 232 insertions(+), 38 deletions(-) create mode 100644 lib/validation/eventType.ts rename lib/{validations => validation}/queryIdTransformParseInt.ts (100%) create mode 100644 yarn-error.log diff --git a/jest.config.ts b/jest.config.ts index 6045b4fa45..48bf90223a 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -82,7 +82,9 @@ export default { // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module // moduleNameMapper: {}, - + moduleNameMapper: { + "^@lib/(.*)$": "/lib/$1", + }, // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader // modulePathIgnorePatterns: [], diff --git a/lib/validation/eventType.ts b/lib/validation/eventType.ts new file mode 100644 index 0000000000..581c9fd3c2 --- /dev/null +++ b/lib/validation/eventType.ts @@ -0,0 +1,12 @@ +import { z } from "zod"; + +const schema = z + .object({ + title: z.string().min(3), + slug: z.string().min(3), + length: z.number().min(1).max(1440), // max is a full day. + description: z.string().min(3).optional(), + }) + .strict(); // Adding strict so that we can disallow passing in extra fields + +export default schema; diff --git a/lib/validations/queryIdTransformParseInt.ts b/lib/validation/queryIdTransformParseInt.ts similarity index 100% rename from lib/validations/queryIdTransformParseInt.ts rename to lib/validation/queryIdTransformParseInt.ts diff --git a/package.json b/package.json index 135808bdf2..496c86a04f 100644 --- a/package.json +++ b/package.json @@ -24,8 +24,7 @@ "babel-jest": "^27.5.1", "jest": "^27.5.1", "node-mocks-http": "^1.11.0", - "typescript": "^4.5.3", - "zod": "^3.14.2" + "typescript": "^4.5.3" }, "dependencies": { "next": "^12.1.0", diff --git a/pages/api/event-types/[id]/delete.ts b/pages/api/event-types/[id]/delete.ts index 038a23d734..0158a4c02e 100644 --- a/pages/api/event-types/[id]/delete.ts +++ b/pages/api/event-types/[id]/delete.ts @@ -1,8 +1,9 @@ import { PrismaClient, EventType } from "@prisma/client"; -import schema from "lib/validations/queryIdTransformParseInt"; import type { NextApiRequest, NextApiResponse } from "next"; import { withValidation } from "next-validations"; +import schema from "@lib/validation/queryIdTransformParseInt"; + const prisma = new PrismaClient(); type ResponseData = { diff --git a/pages/api/event-types/[id]/edit.ts b/pages/api/event-types/[id]/edit.ts index 34c55b296b..20e0dad066 100644 --- a/pages/api/event-types/[id]/edit.ts +++ b/pages/api/event-types/[id]/edit.ts @@ -1,20 +1,12 @@ import { PrismaClient, EventType } from "@prisma/client"; -import schemaQuery from "lib/validations/queryIdTransformParseInt"; import type { NextApiRequest, NextApiResponse } from "next"; import { withValidation } from "next-validations"; -import { z } from "zod"; + +import schema from "@lib/validation/eventType"; +import schemaQuery from "@lib/validation/queryIdTransformParseInt"; const prisma = new PrismaClient(); -const schema = z - .object({ - title: z.string().min(3), - slug: z.string().min(3), - length: z.number().min(1).max(1440), // max is a full day. - description: z.string().min(3).optional(), - }) - .strict(); // Adding strict so that we can disallow passing in extra fields - type ResponseData = { data?: EventType; error?: any; diff --git a/pages/api/event-types/[id]/index.ts b/pages/api/event-types/[id]/index.ts index 5fb6a6a519..b17b0bb57b 100644 --- a/pages/api/event-types/[id]/index.ts +++ b/pages/api/event-types/[id]/index.ts @@ -1,8 +1,9 @@ import { PrismaClient, EventType } from "@prisma/client"; -import schema from "lib/validations/queryIdTransformParseInt"; import type { NextApiRequest, NextApiResponse } from "next"; import { withValidation } from "next-validations"; +import schema from "@lib/validation/queryIdTransformParseInt"; + const prisma = new PrismaClient(); type ResponseData = { diff --git a/pages/api/event-types/new.ts b/pages/api/event-types/new.ts index baf590a4d8..accfb24eab 100644 --- a/pages/api/event-types/new.ts +++ b/pages/api/event-types/new.ts @@ -1,48 +1,30 @@ import { PrismaClient, EventType } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; import { withValidation } from "next-validations"; -import { z } from "zod"; + +import schema from "@lib/validation/eventType"; const prisma = new PrismaClient(); -const schema = z - .object({ - title: z.string().min(3), - slug: z.string().min(3), - length: z.number().min(1).max(1440), // max is a full day. - description: z.string().min(3).optional(), - }) - .strict(); // Adding strict so that we can disallow passing in extra fields - -// type schema = z.infer; const validate = withValidation({ schema, type: "Zod", mode: "body", }); -// interface Body { -// title: string; -// slug: string; -// length: number; -// } type Data = { data?: EventType; error?: string; }; -type NextApiRequestWithBody = NextApiRequest & { - // body: Body; -}; - -async function createEventType(req: NextApiRequestWithBody, res: NextApiResponse) { +async function createEventType(req: NextApiRequest, res: NextApiResponse) { const { body, method } = req; if (method === "POST") { const safe = schema.safeParse(body); if (safe.success && safe.data) { await prisma.eventType .create({ - data: { title: safe.data.title, slug: safe.data.slug, length: safe.data.length }, + data: safe.data, }) .then((event) => res.status(201).json({ data: event })) .catch((error) => { diff --git a/tsconfig.json b/tsconfig.json index 67dc71427a..b9b2164ce0 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,6 +6,7 @@ "compilerOptions": { "strictNullChecks": true, "baseUrl": ".", + "target": "es5", "lib": [ "dom", @@ -18,6 +19,10 @@ "module": "esnext", "resolveJsonModule": true, "jsx": "preserve", + "paths": { + "@api/*": ["pages/api/*"], + "@lib/*": ["lib/*"] +}, }, "include": [ "./**/*.ts" diff --git a/yarn-error.log b/yarn-error.log new file mode 100644 index 0000000000..aed4e9d863 --- /dev/null +++ b/yarn-error.log @@ -0,0 +1,200 @@ +Arguments: + /Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/bin/node /Users/ag/Library/Caches/fnm_multishells/3034_1648146693474/bin/yarn test + +PATH: + /Users/ag/Library/pnpm:/Users/ag/Library/Caches/fnm_multishells/3034_1648146693474/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/ag/.local/bin:/Users/ag/.fig/bin:/Users/ag/.local/bin:/Users/ag/.local/bin:/Users/ag/.yarn/bin + +Yarn version: + 1.22.17 + +Node version: + 14.17.6 + +Platform: + darwin x64 + +Trace: + SyntaxError: /Users/ag/src/cal.com/apps/api/package.json: Unexpected token } in JSON at position 793 + at JSON.parse () + at /Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/lib/node_modules/yarn/lib/cli.js:1625:59 + at Generator.next () + at step (/Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/lib/node_modules/yarn/lib/cli.js:310:30) + at /Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/lib/node_modules/yarn/lib/cli.js:321:13 + +npm manifest: + { + "name": "@calcom/api", + "version": "1.0.0", + "description": "Public API for Cal.com", + "main": "index.ts", + "repository": "git@github.com:calcom/api.git", + "author": "Cal.com Inc.", + "private": true, + "scripts": { + "dev": "PORT=3002 next", + "start": "next start", + "build": "next build", + "lint": "next lint", + "test": "jest --detectOpenHandles", + "type-check": "tsc --pretty --noEmit", + "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist" + }, + "devDependencies": { + "@babel/core": "^7.17.8", + "@babel/preset-env": "^7.16.11", + "@babel/preset-typescript": "^7.16.7", + "@calcom/prisma": "*", + "@calcom/tsconfig": "*", + "babel-jest": "^27.5.1", + "jest": "^27.5.1", + "node-mocks-http": "^1.11.0", + "typescript": "^4.5.3", + }, + "dependencies": { + "next": "^12.1.0", + "next-validations": "^0.1.11", + "zod": "^3.14.2" + } + } + +yarn manifest: + No manifest + +Lockfile: + # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. + # yarn lockfile v1 + + + "@next/env@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/env/-/env-12.1.0.tgz#73713399399b34aa5a01771fb73272b55b22c314" + integrity sha512-nrIgY6t17FQ9xxwH3jj0a6EOiQ/WDHUos35Hghtr+SWN/ntHIQ7UpuvSi0vaLzZVHQWaDupKI+liO5vANcDeTQ== + + "@next/swc-android-arm64@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.1.0.tgz#865ba3a9afc204ff2bdeea49dd64d58705007a39" + integrity sha512-/280MLdZe0W03stA69iL+v6I+J1ascrQ6FrXBlXGCsGzrfMaGr7fskMa0T5AhQIVQD4nA/46QQWxG//DYuFBcA== + + "@next/swc-darwin-arm64@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.0.tgz#08e8b411b8accd095009ed12efbc2f1d4d547135" + integrity sha512-R8vcXE2/iONJ1Unf5Ptqjk6LRW3bggH+8drNkkzH4FLEQkHtELhvcmJwkXcuipyQCsIakldAXhRbZmm3YN1vXg== + + "@next/swc-darwin-x64@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.0.tgz#fcd684497a76e8feaca88db3c394480ff0b007cd" + integrity sha512-ieAz0/J0PhmbZBB8+EA/JGdhRHBogF8BWaeqR7hwveb6SYEIJaDNQy0I+ZN8gF8hLj63bEDxJAs/cEhdnTq+ug== + + "@next/swc-linux-arm-gnueabihf@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.0.tgz#9ec6380a27938a5799aaa6035c205b3c478468a7" + integrity sha512-njUd9hpl6o6A5d08dC0cKAgXKCzm5fFtgGe6i0eko8IAdtAPbtHxtpre3VeSxdZvuGFh+hb0REySQP9T1ttkog== + + "@next/swc-linux-arm64-gnu@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.0.tgz#7f4196dff1049cea479607c75b81033ae2dbd093" + integrity sha512-OqangJLkRxVxMhDtcb7Qn1xjzFA3s50EIxY7mljbSCLybU+sByPaWAHY4px97ieOlr2y4S0xdPKkQ3BCAwyo6Q== + + "@next/swc-linux-arm64-musl@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.0.tgz#b445f767569cdc2dddee785ca495e1a88c025566" + integrity sha512-hB8cLSt4GdmOpcwRe2UzI5UWn6HHO/vLkr5OTuNvCJ5xGDwpPXelVkYW/0+C3g5axbDW2Tym4S+MQCkkH9QfWA== + + "@next/swc-linux-x64-gnu@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.0.tgz#67610e9be4fbc987de7535f1bcb17e45fe12f90e" + integrity sha512-OKO4R/digvrVuweSw/uBM4nSdyzsBV5EwkUeeG4KVpkIZEe64ZwRpnFB65bC6hGwxIBnTv5NMSnJ+0K/WmG78A== + + "@next/swc-linux-x64-musl@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.0.tgz#ea19a23db08a9f2e34ac30401f774cf7d1669d31" + integrity sha512-JohhgAHZvOD3rQY7tlp7NlmvtvYHBYgY0x5ZCecUT6eCCcl9lv6iV3nfu82ErkxNk1H893fqH0FUpznZ/H3pSw== + + "@next/swc-win32-arm64-msvc@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.0.tgz#eadf054fc412085659b98e145435bbba200b5283" + integrity sha512-T/3gIE6QEfKIJ4dmJk75v9hhNiYZhQYAoYm4iVo1TgcsuaKLFa+zMPh4056AHiG6n9tn2UQ1CFE8EoybEsqsSw== + + "@next/swc-win32-ia32-msvc@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.0.tgz#68faeae10c89f698bf9d28759172b74c9c21bda1" + integrity sha512-iwnKgHJdqhIW19H9PRPM9j55V6RdcOo6rX+5imx832BCWzkDbyomWnlzBfr6ByUYfhohb8QuH4hSGEikpPqI0Q== + + "@next/swc-win32-x64-msvc@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.0.tgz#d27e7e76c87a460a4da99c5bfdb1618dcd6cd064" + integrity sha512-aBvcbMwuanDH4EMrL2TthNJy+4nP59Bimn8egqv6GHMVj0a44cU6Au4PjOhLNqEh9l+IpRGBqMTzec94UdC5xg== + + "@types/node@^17.0.21": + version "17.0.21" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.21.tgz#864b987c0c68d07b4345845c3e63b75edd143644" + integrity sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ== + + caniuse-lite@^1.0.30001283: + version "1.0.30001317" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001317.tgz#0548fb28fd5bc259a70b8c1ffdbe598037666a1b" + integrity sha512-xIZLh8gBm4dqNX0gkzrBeyI86J2eCjWzYAs40q88smG844YIrN4tVQl/RhquHvKEKImWWFIVh1Lxe5n1G/N+GQ== + + nanoid@^3.1.30: + version "3.3.1" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" + integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== + + next@^12.1.0: + version "12.1.0" + resolved "https://registry.yarnpkg.com/next/-/next-12.1.0.tgz#c33d753b644be92fc58e06e5a214f143da61dd5d" + integrity sha512-s885kWvnIlxsUFHq9UGyIyLiuD0G3BUC/xrH0CEnH5lHEWkwQcHOORgbDF0hbrW9vr/7am4ETfX4A7M6DjrE7Q== + dependencies: + "@next/env" "12.1.0" + caniuse-lite "^1.0.30001283" + postcss "8.4.5" + styled-jsx "5.0.0" + use-subscription "1.5.1" + optionalDependencies: + "@next/swc-android-arm64" "12.1.0" + "@next/swc-darwin-arm64" "12.1.0" + "@next/swc-darwin-x64" "12.1.0" + "@next/swc-linux-arm-gnueabihf" "12.1.0" + "@next/swc-linux-arm64-gnu" "12.1.0" + "@next/swc-linux-arm64-musl" "12.1.0" + "@next/swc-linux-x64-gnu" "12.1.0" + "@next/swc-linux-x64-musl" "12.1.0" + "@next/swc-win32-arm64-msvc" "12.1.0" + "@next/swc-win32-ia32-msvc" "12.1.0" + "@next/swc-win32-x64-msvc" "12.1.0" + + object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + + picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + + postcss@8.4.5: + version "8.4.5" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95" + integrity sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg== + dependencies: + nanoid "^3.1.30" + picocolors "^1.0.0" + source-map-js "^1.0.1" + + source-map-js@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + + styled-jsx@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.0.tgz#816b4b92e07b1786c6b7111821750e0ba4d26e77" + integrity sha512-qUqsWoBquEdERe10EW8vLp3jT25s/ssG1/qX5gZ4wu15OZpmSMFI2v+fWlRhLfykA5rFtlJ1ME8A8pm/peV4WA== + + use-subscription@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.5.1.tgz#73501107f02fad84c6dd57965beb0b75c68c42d1" + integrity sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA== + dependencies: + object-assign "^4.1.1" From f6371c3b75ff1398499c635afcd860090ebf7bb2 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 25 Mar 2022 01:52:13 +0100 Subject: [PATCH 016/658] adds message and full error in eventtype/new --- pages/api/event-types/new.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/pages/api/event-types/new.ts b/pages/api/event-types/new.ts index accfb24eab..7f46aceaee 100644 --- a/pages/api/event-types/new.ts +++ b/pages/api/event-types/new.ts @@ -12,25 +12,21 @@ const validate = withValidation({ mode: "body", }); -type Data = { +type ResponseData = { data?: EventType; + message?: string; error?: string; }; -async function createEventType(req: NextApiRequest, res: NextApiResponse) { +async function createEventType(req: NextApiRequest, res: NextApiResponse) { const { body, method } = req; if (method === "POST") { const safe = schema.safeParse(body); if (safe.success && safe.data) { await prisma.eventType - .create({ - data: safe.data, - }) + .create({ data: safe.data }) .then((event) => res.status(201).json({ data: event })) - .catch((error) => { - console.log(error); - res.status(400).json({ error: "Could not create event type" }); - }); + .catch((error) => res.status(400).json({ message: "Could not create event type", error: error })); } } else { // Reject any other HTTP method than POST From a71039328f9c97664fe54c69a997dbd82747435f Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 25 Mar 2022 02:07:51 +0100 Subject: [PATCH 017/658] feat: 100% code-coverage, add coverage to gitignore --- .gitignore | 73 ++++++++++++++++++++++-- __tests__/event-types/[id]/index.test.ts | 27 +++++++-- jest.config.ts | 68 ++-------------------- 3 files changed, 95 insertions(+), 73 deletions(-) diff --git a/.gitignore b/.gitignore index f1476ef06a..a50ad511f9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,71 @@ -dist -node_modules/ +# .env file .env + +# dependencies +node_modules +.pnp +.pnp.js + +# testing +coverage +/test-results/ +playwright/videos +playwright/screenshots +playwright/artifacts +playwright/results +playwright/reports/* + +# next.js .next/ -.turbo/ -*.tsbuildinfo +out/ +build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# local env files +.env.local +.env.development.local +.env.test.local +.env.production.local +.env.* +!.env.example + +# vercel +.vercel + +# Webstorm +.idea + +### VisualStudioCode template +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Typescript +tsconfig.tsbuildinfo + +# turbo +.turbo + +# Prisma-Zod +packages/prisma/zod/*.ts + +# Builds +dist + +# Linting +lint-results diff --git a/__tests__/event-types/[id]/index.test.ts b/__tests__/event-types/[id]/index.test.ts index 4c3cfc655b..3420d221f1 100644 --- a/__tests__/event-types/[id]/index.test.ts +++ b/__tests__/event-types/[id]/index.test.ts @@ -4,11 +4,6 @@ import prisma from "@calcom/prisma"; import handleEvent from "../../../pages/api/event-types/[id]"; -afterAll((done) => { - prisma.$disconnect().then(); - done(); -}); - describe("GET /api/event-types/[id] with valid id as string returns an event-type", () => { it("returns a message with the specified events", async () => { const { req, res } = createMocks({ @@ -79,3 +74,25 @@ describe("POST /api/event-types/[id] fails, only GET allowed", () => { expect(JSON.parse(res._getData())).toStrictEqual({ error: "Only GET Method allowed" }); }); }); + +describe("PATCH /api/event-types/[id]/edit with valid id and body updates an event-type", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "PATCH", + query: { + id: "1", + }, + }); + const event = await prisma.eventType.findUnique({ where: { id: 1 } }); + await handleEvent(req, res); + + expect(res._getStatusCode()).toBe(200); + if (event) event.title = "Updated title"; + expect(JSON.parse(res._getData())).toStrictEqual({ data: event }); + }); +}); + +afterAll((done) => { + prisma.$disconnect().then(); + done(); +}); diff --git a/jest.config.ts b/jest.config.ts index 48bf90223a..1abd4994a8 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -3,16 +3,7 @@ * https://jestjs.io/docs/en/configuration.html */ -export default { - // All imported modules in your tests should be mocked automatically - // automock: false, - - // Stop running tests after `n` failures - // bail: 0, - - // The directory where Jest should store its cached dependency information - // cacheDirectory: "/private/var/folders/fl/sw088bcs0dx4zyy0f_ghzvwc0000gn/T/jest_dx", - +const config = { // Automatically clear mock calls and instances between every test clearMocks: true, @@ -24,6 +15,7 @@ export default { // The directory where Jest should output its coverage files coverageDirectory: "coverage", + collectCoverage: true, // An array of regexp pattern strings used to skip coverage collection // coveragePathIgnorePatterns: [ @@ -133,64 +125,12 @@ export default { // setupFilesAfterEnv: [], // The number of seconds after which a test is considered as slow and reported as such in the results. - // slowTestThreshold: 5, + slowTestThreshold: 1, // A list of paths to snapshot serializer modules Jest should use for snapshot testing // snapshotSerializers: [], // The test environment that will be used for testing testEnvironment: "node", - - // Options that will be passed to the testEnvironment - // testEnvironmentOptions: {}, - - // Adds a location field to test results - // testLocationInResults: false, - - // The glob patterns Jest uses to detect test files - // testMatch: [ - // "**/__tests__/**/*.[jt]s?(x)", - // "**/?(*.)+(spec|test).[tj]s?(x)" - // ], - - // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped - // testPathIgnorePatterns: [ - // "/node_modules/" - // ], - - // The regexp pattern or array of patterns that Jest uses to detect test files - // testRegex: [], - - // This option allows the use of a custom results processor - // testResultsProcessor: undefined, - - // This option allows use of a custom test runner - // testRunner: "jasmine2", - - // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href - // testURL: "http://localhost", - - // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" - // timers: "real", - - // A map from regular expressions to paths to transformers - // transform: undefined, - - // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation - // transformIgnorePatterns: [ - // "/node_modules/", - // "\\.pnp\\.[^\\/]+$" - // ], - - // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them - // unmockedModulePathPatterns: undefined, - - // Indicates whether each individual test should be reported during the run - // verbose: undefined, - - // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode - // watchPathIgnorePatterns: [], - - // Whether to use watchman for file crawling - // watchman: true, }; +export default config; From 2e2f6a5e57c0edeefd2b3d2bc8d2cf486489bb0d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 25 Mar 2022 02:18:43 +0100 Subject: [PATCH 018/658] feat: adds git hooks and husky for pre-commit linting --- .husky/pre-commit | 4 ++++ package.json | 8 ++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100755 .husky/pre-commit diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 0000000000..025779ed2b --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +yarn pre-commit diff --git a/package.json b/package.json index 496c86a04f..cb8d543065 100644 --- a/package.json +++ b/package.json @@ -11,9 +11,12 @@ "start": "next start", "build": "next build", "lint": "next lint", + "lint-fix": "next lint --fix", "test": "jest --detectOpenHandles", "type-check": "tsc --pretty --noEmit", - "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist" + "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist", + "prepare": "husky install", + "pre-commit": "next lint" }, "devDependencies": { "@babel/core": "^7.17.8", @@ -22,9 +25,10 @@ "@calcom/prisma": "*", "@calcom/tsconfig": "*", "babel-jest": "^27.5.1", + "husky": "^7.0.4", "jest": "^27.5.1", "node-mocks-http": "^1.11.0", - "typescript": "^4.5.3" + "typescript": "^4.6.3" }, "dependencies": { "next": "^12.1.0", From a2817a2fee2ab4f0c4ac5c5f16ac39df773452d7 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 25 Mar 2022 06:54:57 +0100 Subject: [PATCH 019/658] Feat: event-types and tests --- .eslintrc.js | 1 - .eslintrc.json | 15 + README.md | 24 +- .../[id]/event-type.id.test.edit.ts | 95 + ...ex.test.ts => event-type.id.test.index.ts} | 24 +- jest.config.ts | 82 +- lib/{validation => validations}/eventType.ts | 10 +- .../queryIdTransformParseInt.ts | 12 +- package.json | 7 +- pages/api/event-types/[id]/delete.ts | 21 +- pages/api/event-types/[id]/edit.ts | 40 +- pages/api/event-types/[id]/index.ts | 26 +- pages/api/event-types/index.ts | 2 +- pages/api/event-types/new.ts | 14 +- pages/api/users/[id].ts | 19 - yarn-error.log | 15705 +++++++++++++++- 16 files changed, 15892 insertions(+), 205 deletions(-) delete mode 100644 .eslintrc.js create mode 100644 .eslintrc.json create mode 100644 __tests__/event-types/[id]/event-type.id.test.edit.ts rename __tests__/event-types/[id]/{index.test.ts => event-type.id.test.index.ts} (73%) rename lib/{validation => validations}/eventType.ts (55%) rename lib/{validation => validations}/queryIdTransformParseInt.ts (62%) delete mode 100644 pages/api/users/[id].ts diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 0e71ec1eae..0000000000 --- a/.eslintrc.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require("@calcom/config/eslint-preset"); diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000000..176de0b130 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,15 @@ +// FIXME: import eslint-config-calcom-base from '@calcom/config/eslint +{ + "root": true, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:@next/next/recommended" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { "project": ["./tsconfig.json"] }, + "plugins": [ + "@typescript-eslint" + ], + "ignorePatterns": ["src/**/*.test.ts", "src/frontend/generated/*"] +} \ No newline at end of file diff --git a/README.md b/README.md index bb162f312a..c2320f50c9 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ## This will be the new public enterprise-only API -This is the public REST api for cal.com. +This is the public REST api for cal.com ## NextJS + TypeScript @@ -12,14 +12,30 @@ It's a barebones **NextJS** + **TypeScript** project leveraging the nextJS API w It doesn't have react or react-dom as a dependency, and will only be used by a redirect as a folder or subdomain on cal.com with maybe a v1 tag like: -- `v1.api.cal.com` - `api.cal.com/v1` -- `app.cal.com/api/v1/` +- `api.cal.com/api/v1` +## API Endpoint Validation -## API Endpoint Validation +### Zod The API uses `zod` library like our main web repo. It validates that either GET query parameters or POST body content's are valid and up to our spec. It gives appropiate errors when parsing result's with schemas. +### Next Validations + +[Next-Validations Docs](https://next-validations.productsway.com/) +[Next-Validations Repo](https://github.com/jellydn/next-validations) +We also use this useful helper library that let's us wrap our endpoints in a validate HOC that checks the req against our validation schema built out with zod for either query and / or body's requests. + ## Testing with Jest + node-mocks-http + +We aim to provide a fully tested API for our peace of mind, this is accomplished by using jest + node-mocks-http + + +## Next.config.js + +### Redirects + +Since this will only support an API, we redirect the requests to root to the /api folder. +We also added a redirect for future-proofing API versioning when we might need it, without having to resort to dirty hacks like a v1/v2 folders with lots of duplicated code, instead we redirect /api/v*/:rest to /api/:rest?version=* diff --git a/__tests__/event-types/[id]/event-type.id.test.edit.ts b/__tests__/event-types/[id]/event-type.id.test.edit.ts new file mode 100644 index 0000000000..8f55f76a53 --- /dev/null +++ b/__tests__/event-types/[id]/event-type.id.test.edit.ts @@ -0,0 +1,95 @@ +import handleEventEdit from "@api/event-types/[id]/edit"; +import { createMocks } from "node-mocks-http"; + +import prisma from "@calcom/prisma"; + +describe("PATCH /api/event-types/[id]/edit with valid id and body updates an event-type", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "PATCH", + query: { + id: "2", + }, + body: { + title: "Updated title", + slug: "updated-slug", + length: 1, + }, + }); + const event = await prisma.eventType.findUnique({ where: { id: 2 } }); + await handleEventEdit(req, res); + + expect(res._getStatusCode()).toBe(200); + if (event) event.title = "Updated title"; + expect(JSON.parse(res._getData())).toStrictEqual({ data: event }); + }); +}); + +describe("PATCH /api/event-types/[id]/edit with invalid id returns 404", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "PATCH", + query: { + id: "0", + }, + body: { + title: "Updated title", + slug: "updated-slug", + length: 1, + }, + }); + const event = await prisma.eventType.findUnique({ where: { id: 2 } }); + await handleEventEdit(req, res); + + expect(res._getStatusCode()).toBe(404); + if (event) event.title = "Updated title"; + expect(JSON.parse(res._getData())).toStrictEqual({ "error": { + "clientVersion": "3.10.0", + "code": "P2025", + "meta": { + "cause": "Record to update not found.", + }, + }, + "message": "Event type with ID 0 not found and wasn't updated", }); + }); +}); + +describe("PATCH /api/event-types/[id]/edit with valid id and no body returns 400 error and zod validation errors", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "PATCH", + query: { + id: "2", + }, + }); + await handleEventEdit(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(JSON.parse(res._getData())).toStrictEqual([{"code": "invalid_type", "expected": "string", "message": "Required", "path": ["title"], "received": "undefined"}, {"code": "invalid_type", "expected": "string", "message": "Required", "path": ["slug"], "received": "undefined"}, {"code": "invalid_type", "expected": "number", "message": "Required", "path": ["length"], "received": "undefined"}]); + }); +}); + +describe("POST /api/event-types/[id]/edit fails, only PATCH allowed", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + query: { + id: "1", + }, + body: { + title: "Updated title", + slug: "updated-slug", + length: 1, + }, + }); + await handleEventEdit(req, res); + + expect(res._getStatusCode()).toBe(405); + expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only PATCH Method allowed for updating event-types" }); + }); +}); + +afterAll((done) => { + prisma.$disconnect().then(); + done(); +}); diff --git a/__tests__/event-types/[id]/index.test.ts b/__tests__/event-types/[id]/event-type.id.test.index.ts similarity index 73% rename from __tests__/event-types/[id]/index.test.ts rename to __tests__/event-types/[id]/event-type.id.test.index.ts index 3420d221f1..a80e04c41c 100644 --- a/__tests__/event-types/[id]/index.test.ts +++ b/__tests__/event-types/[id]/event-type.id.test.index.ts @@ -1,9 +1,8 @@ +import handleEvent from "@api/event-types/[id]"; import { createMocks } from "node-mocks-http"; import prisma from "@calcom/prisma"; -import handleEvent from "../../../pages/api/event-types/[id]"; - describe("GET /api/event-types/[id] with valid id as string returns an event-type", () => { it("returns a message with the specified events", async () => { const { req, res } = createMocks({ @@ -56,7 +55,7 @@ describe("GET /api/event-types/[id] an id not present in db like 0, throws 404 n await handleEvent(req, res); expect(res._getStatusCode()).toBe(404); - expect(JSON.parse(res._getData())).toStrictEqual({ error: "Event type not found" }); + expect(JSON.parse(res._getData())).toStrictEqual({ message: "Event type not found" }); }); }); @@ -71,24 +70,7 @@ describe("POST /api/event-types/[id] fails, only GET allowed", () => { await handleEvent(req, res); expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ error: "Only GET Method allowed" }); - }); -}); - -describe("PATCH /api/event-types/[id]/edit with valid id and body updates an event-type", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "1", - }, - }); - const event = await prisma.eventType.findUnique({ where: { id: 1 } }); - await handleEvent(req, res); - - expect(res._getStatusCode()).toBe(200); - if (event) event.title = "Updated title"; - expect(JSON.parse(res._getData())).toStrictEqual({ data: event }); + expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); }); }); diff --git a/jest.config.ts b/jest.config.ts index 1abd4994a8..d6ad32763e 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -4,17 +4,8 @@ */ const config = { - // Automatically clear mock calls and instances between every test clearMocks: true, - - // Indicates whether the coverage information should be collected while executing the test - // collectCoverage: false, - - // An array of glob patterns indicating a set of files for which coverage information should be collected - // collectCoverageFrom: undefined, - - // The directory where Jest should output its coverage files - coverageDirectory: "coverage", + coverageDirectory: "./coverage", collectCoverage: true, // An array of regexp pattern strings used to skip coverage collection @@ -26,12 +17,12 @@ const config = { // coverageProvider: "babel", // A list of reporter names that Jest uses when writing coverage reports - // coverageReporters: [ - // "json", - // "text", - // "lcov", - // "clover" - // ], + coverageReporters: [ + "json", + "text", + "lcov", + "clover" + ], // An object that configures minimum threshold enforcement for coverage results // coverageThreshold: undefined, @@ -40,7 +31,7 @@ const config = { // dependencyExtractor: undefined, // Make calling deprecated APIs throw helpful error messages - // errorOnDeprecated: false, + errorOnDeprecated: true, // Force coverage collection from ignored files using an array of glob patterns // forceCoverageMatch: [], @@ -55,68 +46,15 @@ const config = { // globals: {}, // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. - // maxWorkers: "50%", + maxWorkers: "50%", - // An array of directory names to be searched recursively up from the requiring module's location - // moduleDirectories: [ - // "node_modules" - // ], - // An array of file extensions your modules use - // moduleFileExtensions: [ - // "js", - // "json", - // "jsx", - // "ts", - // "tsx", - // "node" - // ], - // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module - // moduleNameMapper: {}, moduleNameMapper: { "^@lib/(.*)$": "/lib/$1", + "^@api/(.*)$": "/pages/api/$1", }, - // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader - // modulePathIgnorePatterns: [], - // Activates notifications for test results - // notify: false, - - // An enum that specifies notification mode. Requires { notify: true } - // notifyMode: "failure-change", - - // A preset that is used as a base for Jest's configuration - // preset: undefined, - - // Run tests from one or more projects - // projects: undefined, - - // Use this configuration option to add custom reporters to Jest - // reporters: undefined, - - // Automatically reset mock state between every test - // resetMocks: false, - - // Reset the module registry before running each individual test - // resetModules: false, - - // A path to a custom resolver - // resolver: undefined, - - // Automatically restore mock state between every test - // restoreMocks: false, - - // The root directory that Jest should scan for tests and modules within - // rootDir: undefined, - - // A list of paths to directories that Jest should use to search for files in - // roots: [ - // "" - // ], - - // Allows you to use a custom runner instead of Jest's default test runner - // runner: "jest-runner", // The paths to modules that run some code to configure or set up the testing environment before each test // setupFiles: [], diff --git a/lib/validation/eventType.ts b/lib/validations/eventType.ts similarity index 55% rename from lib/validation/eventType.ts rename to lib/validations/eventType.ts index 581c9fd3c2..d9be43a1e2 100644 --- a/lib/validation/eventType.ts +++ b/lib/validations/eventType.ts @@ -1,6 +1,7 @@ +import { withValidation } from "next-validations"; import { z } from "zod"; -const schema = z +const schemaEventType = z .object({ title: z.string().min(3), slug: z.string().min(3), @@ -8,5 +9,10 @@ const schema = z description: z.string().min(3).optional(), }) .strict(); // Adding strict so that we can disallow passing in extra fields +const withValidEventType = withValidation({ + schema: schemaEventType, + type: "Zod", + mode: "body", +}); -export default schema; +export { schemaEventType, withValidEventType }; diff --git a/lib/validation/queryIdTransformParseInt.ts b/lib/validations/queryIdTransformParseInt.ts similarity index 62% rename from lib/validation/queryIdTransformParseInt.ts rename to lib/validations/queryIdTransformParseInt.ts index e90f1735ce..1bbb5cfa09 100644 --- a/lib/validation/queryIdTransformParseInt.ts +++ b/lib/validations/queryIdTransformParseInt.ts @@ -1,8 +1,9 @@ +import { withValidation } from "next-validations"; import { z } from "zod"; // Extracted out as utility function so can be reused // at different endpoints that require this validation. -const schema = z +const schemaQueryId = z .object({ // since nextjs parses query params as strings, // we need to cast them to numbers using z.transform() and parseInt() @@ -12,4 +13,11 @@ const schema = z .transform((id) => parseInt(id)), }) .strict(); -export default schema; + +const withValidQueryId = withValidation({ + schema: schemaQueryId, + type: "Zod", + mode: "query", +}); + +export { schemaQueryId, withValidQueryId }; diff --git a/package.json b/package.json index cb8d543065..12a5753dc7 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "build": "next build", "lint": "next lint", "lint-fix": "next lint --fix", - "test": "jest --detectOpenHandles", + "test": "jest --detectOpenHandles --verbose", "type-check": "tsc --pretty --noEmit", "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist", "prepare": "husky install", @@ -24,13 +24,14 @@ "@babel/preset-typescript": "^7.16.7", "@calcom/prisma": "*", "@calcom/tsconfig": "*", + "@typescript-eslint/eslint-plugin": "^5.16.0", "babel-jest": "^27.5.1", "husky": "^7.0.4", "jest": "^27.5.1", - "node-mocks-http": "^1.11.0", - "typescript": "^4.6.3" + "node-mocks-http": "^1.11.0" }, "dependencies": { + "typescript": "^4.6.3", "next": "^12.1.0", "next-validations": "^0.1.11", "zod": "^3.14.2" diff --git a/pages/api/event-types/[id]/delete.ts b/pages/api/event-types/[id]/delete.ts index 0158a4c02e..7912907b51 100644 --- a/pages/api/event-types/[id]/delete.ts +++ b/pages/api/event-types/[id]/delete.ts @@ -1,19 +1,18 @@ -import { PrismaClient, EventType } from "@prisma/client"; +import { PrismaClient } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { withValidation } from "next-validations"; -import schema from "@lib/validation/queryIdTransformParseInt"; +import { schemaQueryId, withValidQueryId } from "@lib/validations/queryIdTransformParseInt"; const prisma = new PrismaClient(); type ResponseData = { message?: string; - error?: any; + error?: unknown; }; export async function eventType(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; - const safe = await schema.safeParse(query); + const safe = await schemaQueryId.safeParse(query); if (safe.success) { if (method === "DELETE") { // DELETE WILL DELETE THE EVENT TYPE @@ -25,19 +24,13 @@ export async function eventType(req: NextApiRequest, res: NextApiResponse { // This catches the error thrown by prisma.eventType.delete() if the resource is not found. - res.status(400).json({ error: error }); + res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); }); } else { // Reject any other HTTP method than POST - res.status(405).json({ error: "Only DELETE Method allowed in /event-types/[id]/delete endpoint" }); + res.status(405).json({ message: "Only DELETE Method allowed in /event-types/[id]/delete endpoint" }); } } } -const validate = withValidation({ - schema, - type: "Zod", - mode: "query", -}); - -export default validate(eventType); +export default withValidQueryId(eventType); diff --git a/pages/api/event-types/[id]/edit.ts b/pages/api/event-types/[id]/edit.ts index 20e0dad066..c4eac80975 100644 --- a/pages/api/event-types/[id]/edit.ts +++ b/pages/api/event-types/[id]/edit.ts @@ -1,41 +1,37 @@ import { PrismaClient, EventType } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { withValidation } from "next-validations"; -import schema from "@lib/validation/eventType"; -import schemaQuery from "@lib/validation/queryIdTransformParseInt"; +import { schemaEventType, withValidEventType } from "@lib/validations/eventType"; +import { schemaQueryId, withValidQueryId } from "@lib/validations/queryIdTransformParseInt"; const prisma = new PrismaClient(); type ResponseData = { data?: EventType; - error?: any; + message?: string; + error?: unknown; }; export async function editEventType(req: NextApiRequest, res: NextApiResponse) { const { query, body, method } = req; - const safeQuery = await schemaQuery.safeParse(query); - const safeBody = await schema.safeParse(body); + const safeQuery = await schemaQueryId.safeParse(query); + const safeBody = await schemaEventType.safeParse(body); - if (safeQuery.success && safeBody.success) { - if (method === "PATCH") { - const event = await prisma.eventType.update({ + if (method === "PATCH") { + if (safeQuery.success && safeBody.success) { + await prisma.eventType.update({ where: { id: safeQuery.data.id }, - data: { ...safeBody.data }, + data: safeBody.data, + }).then(event => { + res.status(200).json({ data: event }); + }).catch(error => { + res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) }); - if (event) res.status(200).json({ data: event }); - if (!event) res.status(404).json({ error: "Event type not found" }); - } else { - // Reject any other HTTP method than POST - res.status(405).json({ error: "Only GET Method allowed" }); } + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only PATCH Method allowed for updating event-types" }); } } -const validate = withValidation({ - schema, - type: "Zod", - mode: "body", -}); - -export default validate(editEventType); +export default withValidQueryId(withValidEventType(editEventType)); diff --git a/pages/api/event-types/[id]/index.ts b/pages/api/event-types/[id]/index.ts index b17b0bb57b..087a30cd55 100644 --- a/pages/api/event-types/[id]/index.ts +++ b/pages/api/event-types/[id]/index.ts @@ -1,43 +1,31 @@ import { PrismaClient, EventType } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { withValidation } from "next-validations"; -import schema from "@lib/validation/queryIdTransformParseInt"; +import { schemaQueryId, withValidQueryId } from "@lib/validations/queryIdTransformParseInt"; const prisma = new PrismaClient(); type ResponseData = { data?: EventType; - error?: any; + message?: string; + error?: unknown; }; export async function eventType(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; - const safe = await schema.safeParse(query); + const safe = await schemaQueryId.safeParse(query); if (safe.success) { if (method === "GET") { const event = await prisma.eventType.findUnique({ where: { id: safe.data.id } }); if (event) res.status(200).json({ data: event }); - if (!event) res.status(404).json({ error: "Event type not found" }); - } else if (method === "PATCH") { - const event = await prisma.eventType.update({ - where: { id: safe.data.id }, - data: { title: "Updated title" }, - }); - if (event) res.status(200).json({ data: event }); - if (!event) res.status(404).json({ error: "Event type not found" }); + if (!event) res.status(404).json({ message: "Event type not found" }); } else { // Reject any other HTTP method than POST - res.status(405).json({ error: "Only GET Method allowed" }); + res.status(405).json({ message: "Only GET Method allowed" }); } } } -const validate = withValidation({ - schema, - type: "Zod", - mode: "query", -}); -export default validate(eventType); +export default withValidQueryId(eventType); diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 49c69583c8..946dcde907 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -4,7 +4,7 @@ import type { NextApiRequest, NextApiResponse } from "next"; const prisma = new PrismaClient(); type ResponseData = { data?: EventType[]; - error?: any; + error?: unknown; }; export default async function eventType(req: NextApiRequest, res: NextApiResponse) { diff --git a/pages/api/event-types/new.ts b/pages/api/event-types/new.ts index 7f46aceaee..efe01150da 100644 --- a/pages/api/event-types/new.ts +++ b/pages/api/event-types/new.ts @@ -1,17 +1,9 @@ import { PrismaClient, EventType } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { withValidation } from "next-validations"; -import schema from "@lib/validation/eventType"; +import { schemaEventType, withValidEventType } from "@lib/validations/eventType"; const prisma = new PrismaClient(); - -const validate = withValidation({ - schema, - type: "Zod", - mode: "body", -}); - type ResponseData = { data?: EventType; message?: string; @@ -21,7 +13,7 @@ type ResponseData = { async function createEventType(req: NextApiRequest, res: NextApiResponse) { const { body, method } = req; if (method === "POST") { - const safe = schema.safeParse(body); + const safe = schemaEventType.safeParse(body); if (safe.success && safe.data) { await prisma.eventType .create({ data: safe.data }) @@ -34,4 +26,4 @@ async function createEventType(req: NextApiRequest, res: NextApiResponse) { - const { id }: { id?: string } = req.query; - if (!id) return res.status(404).json({ message: `User not found` }); - const user = await prisma.user.findUnique({ - where: { - id: parseInt(id), - }, - }); - return res.json({ message: `Hello ${user?.name}` }); -} diff --git a/yarn-error.log b/yarn-error.log index aed4e9d863..e56325651f 100644 --- a/yarn-error.log +++ b/yarn-error.log @@ -1,5 +1,5 @@ Arguments: - /Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/bin/node /Users/ag/Library/Caches/fnm_multishells/3034_1648146693474/bin/yarn test + /Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/bin/node /Users/ag/Library/Caches/fnm_multishells/3034_1648146693474/bin/yarn add --dev -W @typescript-eslint PATH: /Users/ag/Library/pnpm:/Users/ag/Library/Caches/fnm_multishells/3034_1648146693474/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/ag/.local/bin:/Users/ag/.fig/bin:/Users/ag/.local/bin:/Users/ag/.local/bin:/Users/ag/.yarn/bin @@ -14,12 +14,17 @@ Platform: darwin x64 Trace: - SyntaxError: /Users/ag/src/cal.com/apps/api/package.json: Unexpected token } in JSON at position 793 - at JSON.parse () - at /Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/lib/node_modules/yarn/lib/cli.js:1625:59 - at Generator.next () - at step (/Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/lib/node_modules/yarn/lib/cli.js:310:30) - at /Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/lib/node_modules/yarn/lib/cli.js:321:13 + Error: https://registry.yarnpkg.com/@typescript-eslint: Request "https://registry.yarnpkg.com/@typescript-eslint" returned a 405 + at Request.params.callback [as _callback] (/Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/lib/node_modules/yarn/lib/cli.js:67038:18) + at Request.self.callback (/Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/lib/node_modules/yarn/lib/cli.js:140883:22) + at Request.emit (events.js:400:28) + at Request. (/Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/lib/node_modules/yarn/lib/cli.js:141855:10) + at Request.emit (events.js:400:28) + at IncomingMessage. (/Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/lib/node_modules/yarn/lib/cli.js:141777:12) + at Object.onceWrapper (events.js:519:28) + at IncomingMessage.emit (events.js:412:35) + at endReadableNT (internal/streams/readable.js:1317:12) + at processTicksAndRejections (internal/process/task_queues.js:82:21) npm manifest: { @@ -35,9 +40,12 @@ npm manifest: "start": "next start", "build": "next build", "lint": "next lint", + "lint-fix": "next lint --fix", "test": "jest --detectOpenHandles", "type-check": "tsc --pretty --noEmit", - "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist" + "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist", + "prepare": "husky install", + "pre-commit": "next lint" }, "devDependencies": { "@babel/core": "^7.17.8", @@ -46,9 +54,10 @@ npm manifest: "@calcom/prisma": "*", "@calcom/tsconfig": "*", "babel-jest": "^27.5.1", + "husky": "^7.0.4", "jest": "^27.5.1", "node-mocks-http": "^1.11.0", - "typescript": "^4.5.3", + "typescript": "^4.6.3" }, "dependencies": { "next": "^12.1.0", @@ -65,11 +74,2361 @@ Lockfile: # yarn lockfile v1 + "@ampproject/remapping@^2.1.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.1.2.tgz#4edca94973ded9630d20101cd8559cedb8d8bd34" + integrity sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg== + dependencies: + "@jridgewell/trace-mapping" "^0.3.0" + + "@babel/code-frame@7.16.7", "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" + integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== + dependencies: + "@babel/highlight" "^7.16.7" + + "@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.8", "@babel/compat-data@^7.17.0", "@babel/compat-data@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.7.tgz#078d8b833fbbcc95286613be8c716cef2b519fa2" + integrity sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ== + + "@babel/core@7.13.10": + version "7.13.10" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.13.10.tgz#07de050bbd8193fcd8a3c27918c0890613a94559" + integrity sha512-bfIYcT0BdKeAZrovpMqX2Mx5NrgAckGbwT982AkdS5GNfn3KMGiprlBAtmBcFZRUmpaufS6WZFP8trvx8ptFDw== + dependencies: + "@babel/code-frame" "^7.12.13" + "@babel/generator" "^7.13.9" + "@babel/helper-compilation-targets" "^7.13.10" + "@babel/helper-module-transforms" "^7.13.0" + "@babel/helpers" "^7.13.10" + "@babel/parser" "^7.13.10" + "@babel/template" "^7.12.13" + "@babel/traverse" "^7.13.0" + "@babel/types" "^7.13.0" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + lodash "^4.17.19" + semver "^6.3.0" + source-map "^0.5.0" + + "@babel/core@7.16.12": + version "7.16.12" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.12.tgz#5edc53c1b71e54881315923ae2aedea2522bb784" + integrity sha512-dK5PtG1uiN2ikk++5OzSYsitZKny4wOCD0nrO4TqnW4BVBTQ2NGS3NgilvT/TEyxTST7LNyWV/T4tXDoD3fOgg== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.16.8" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helpers" "^7.16.7" + "@babel/parser" "^7.16.12" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.10" + "@babel/types" "^7.16.8" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + source-map "^0.5.0" + + "@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.7.5": + version "7.17.5" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.5.tgz#6cd2e836058c28f06a4ca8ee7ed955bbf37c8225" + integrity sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.17.3" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helpers" "^7.17.2" + "@babel/parser" "^7.17.3" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.3" + "@babel/types" "^7.17.0" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + + "@babel/core@^7.17.8", "@babel/core@^7.7.2", "@babel/core@^7.8.0": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.8.tgz#3dac27c190ebc3a4381110d46c80e77efe172e1a" + integrity sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ== + dependencies: + "@ampproject/remapping" "^2.1.0" + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.17.7" + "@babel/helper-compilation-targets" "^7.17.7" + "@babel/helper-module-transforms" "^7.17.7" + "@babel/helpers" "^7.17.8" + "@babel/parser" "^7.17.8" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.3" + "@babel/types" "^7.17.0" + convert-source-map "^1.7.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.1.2" + semver "^6.3.0" + + "@babel/generator@7.13.9": + version "7.13.9" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.13.9.tgz#3a7aa96f9efb8e2be42d38d80e2ceb4c64d8de39" + integrity sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw== + dependencies: + "@babel/types" "^7.13.0" + jsesc "^2.5.1" + source-map "^0.5.0" + + "@babel/generator@^7.13.0", "@babel/generator@^7.13.9", "@babel/generator@^7.16.8", "@babel/generator@^7.17.3": + version "7.17.3" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.3.tgz#a2c30b0c4f89858cb87050c3ffdfd36bdf443200" + integrity sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg== + dependencies: + "@babel/types" "^7.17.0" + jsesc "^2.5.1" + source-map "^0.5.0" + + "@babel/generator@^7.17.7", "@babel/generator@^7.7.2": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad" + integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w== + dependencies: + "@babel/types" "^7.17.0" + jsesc "^2.5.1" + source-map "^0.5.0" + + "@babel/helper-annotate-as-pure@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" + integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== + dependencies: + "@babel/types" "^7.16.7" + + "@babel/helper-builder-binary-assignment-operator-visitor@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz#38d138561ea207f0f69eb1626a418e4f7e6a580b" + integrity sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA== + dependencies: + "@babel/helper-explode-assignable-expression" "^7.16.7" + "@babel/types" "^7.16.7" + + "@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.13.10", "@babel/helper-compilation-targets@^7.16.7", "@babel/helper-compilation-targets@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz#a3c2924f5e5f0379b356d4cfb313d1414dc30e46" + integrity sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w== + dependencies: + "@babel/compat-data" "^7.17.7" + "@babel/helper-validator-option" "^7.16.7" + browserslist "^4.17.5" + semver "^6.3.0" + + "@babel/helper-create-class-features-plugin@^7.16.10", "@babel/helper-create-class-features-plugin@^7.16.7", "@babel/helper-create-class-features-plugin@^7.17.6": + version "7.17.6" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz#3778c1ed09a7f3e65e6d6e0f6fbfcc53809d92c9" + integrity sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-member-expression-to-functions" "^7.16.7" + "@babel/helper-optimise-call-expression" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + + "@babel/helper-create-regexp-features-plugin@^7.16.7": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz#1dcc7d40ba0c6b6b25618997c5dbfd310f186fe1" + integrity sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + regexpu-core "^5.0.1" + + "@babel/helper-define-polyfill-provider@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz#52411b445bdb2e676869e5a74960d2d3826d2665" + integrity sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA== + dependencies: + "@babel/helper-compilation-targets" "^7.13.0" + "@babel/helper-module-imports" "^7.12.13" + "@babel/helper-plugin-utils" "^7.13.0" + "@babel/traverse" "^7.13.0" + debug "^4.1.1" + lodash.debounce "^4.0.8" + resolve "^1.14.2" + semver "^6.1.2" + + "@babel/helper-environment-visitor@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" + integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== + dependencies: + "@babel/types" "^7.16.7" + + "@babel/helper-explode-assignable-expression@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz#12a6d8522fdd834f194e868af6354e8650242b7a" + integrity sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ== + dependencies: + "@babel/types" "^7.16.7" + + "@babel/helper-function-name@^7.12.13", "@babel/helper-function-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" + integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== + dependencies: + "@babel/helper-get-function-arity" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/types" "^7.16.7" + + "@babel/helper-get-function-arity@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" + integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== + dependencies: + "@babel/types" "^7.16.7" + + "@babel/helper-hoist-variables@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" + integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== + dependencies: + "@babel/types" "^7.16.7" + + "@babel/helper-member-expression-to-functions@^7.16.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz#a34013b57d8542a8c4ff8ba3f747c02452a4d8c4" + integrity sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw== + dependencies: + "@babel/types" "^7.17.0" + + "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" + integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== + dependencies: + "@babel/types" "^7.16.7" + + "@babel/helper-module-transforms@^7.13.0", "@babel/helper-module-transforms@^7.16.7": + version "7.17.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz#3c3b03cc6617e33d68ef5a27a67419ac5199ccd0" + integrity sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA== + dependencies: + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-simple-access" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.3" + "@babel/types" "^7.17.0" + + "@babel/helper-module-transforms@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz#3943c7f777139e7954a5355c815263741a9c1cbd" + integrity sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw== + dependencies: + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-simple-access" "^7.17.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.3" + "@babel/types" "^7.17.0" + + "@babel/helper-optimise-call-expression@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz#a34e3560605abbd31a18546bd2aad3e6d9a174f2" + integrity sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w== + dependencies: + "@babel/types" "^7.16.7" + + "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" + integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== + + "@babel/helper-remap-async-to-generator@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz#29ffaade68a367e2ed09c90901986918d25e57e3" + integrity sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-wrap-function" "^7.16.8" + "@babel/types" "^7.16.8" + + "@babel/helper-replace-supers@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz#e9f5f5f32ac90429c1a4bdec0f231ef0c2838ab1" + integrity sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw== + dependencies: + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-member-expression-to-functions" "^7.16.7" + "@babel/helper-optimise-call-expression" "^7.16.7" + "@babel/traverse" "^7.16.7" + "@babel/types" "^7.16.7" + + "@babel/helper-simple-access@^7.16.7", "@babel/helper-simple-access@^7.17.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz#aaa473de92b7987c6dfa7ce9a7d9674724823367" + integrity sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA== + dependencies: + "@babel/types" "^7.17.0" + + "@babel/helper-skip-transparent-expression-wrappers@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" + integrity sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw== + dependencies: + "@babel/types" "^7.16.0" + + "@babel/helper-split-export-declaration@^7.12.13", "@babel/helper-split-export-declaration@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" + integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== + dependencies: + "@babel/types" "^7.16.7" + + "@babel/helper-validator-identifier@^7.12.11", "@babel/helper-validator-identifier@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" + integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== + + "@babel/helper-validator-option@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" + integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== + + "@babel/helper-wrap-function@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz#58afda087c4cd235de92f7ceedebca2c41274200" + integrity sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw== + dependencies: + "@babel/helper-function-name" "^7.16.7" + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.16.8" + "@babel/types" "^7.16.8" + + "@babel/helpers@^7.13.10", "@babel/helpers@^7.16.7", "@babel/helpers@^7.17.2": + version "7.17.2" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.2.tgz#23f0a0746c8e287773ccd27c14be428891f63417" + integrity sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ== + dependencies: + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.0" + "@babel/types" "^7.17.0" + + "@babel/helpers@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.8.tgz#288450be8c6ac7e4e44df37bcc53d345e07bc106" + integrity sha512-QcL86FGxpfSJwGtAvv4iG93UL6bmqBdmoVY0CMCU2g+oD2ezQse3PT5Pa+jiD6LJndBQi0EDlpzOWNlLuhz5gw== + dependencies: + "@babel/template" "^7.16.7" + "@babel/traverse" "^7.17.3" + "@babel/types" "^7.17.0" + + "@babel/highlight@^7.16.7": + version "7.16.10" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" + integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.7" + chalk "^2.0.0" + js-tokens "^4.0.0" + + "@babel/parser@7.14.6": + version "7.14.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.6.tgz#d85cc68ca3cac84eae384c06f032921f5227f4b2" + integrity sha512-oG0ej7efjEXxb4UgE+klVx+3j4MVo+A2vCzm7OUN4CLo6WhQ+vSOD2yJ8m7B+DghObxtLxt3EfgMWpq+AsWehQ== + + "@babel/parser@^7.1.0", "@babel/parser@^7.13.0", "@babel/parser@^7.13.10", "@babel/parser@^7.14.7", "@babel/parser@^7.16.12", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3": + version "7.17.3" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.3.tgz#b07702b982990bf6fdc1da5049a23fece4c5c3d0" + integrity sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA== + + "@babel/parser@^7.17.8": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.8.tgz#2817fb9d885dd8132ea0f8eb615a6388cca1c240" + integrity sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ== + + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz#4eda6d6c2a0aa79c70fa7b6da67763dfe2141050" + integrity sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz#cc001234dfc139ac45f6bcf801866198c8c72ff9" + integrity sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/plugin-proposal-optional-chaining" "^7.16.7" + + "@babel/plugin-proposal-async-generator-functions@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz#3bdd1ebbe620804ea9416706cd67d60787504bc8" + integrity sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-remap-async-to-generator" "^7.16.8" + "@babel/plugin-syntax-async-generators" "^7.8.4" + + "@babel/plugin-proposal-class-properties@7.16.7", "@babel/plugin-proposal-class-properties@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz#925cad7b3b1a2fcea7e59ecc8eb5954f961f91b0" + integrity sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-proposal-class-static-block@^7.16.7": + version "7.17.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.6.tgz#164e8fd25f0d80fa48c5a4d1438a6629325ad83c" + integrity sha512-X/tididvL2zbs7jZCeeRJ8167U/+Ac135AM6jCAx6gYXDUviZV5Ku9UDvWS2NCuWlFjIRXklYhwo6HhAC7ETnA== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.17.6" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + + "@babel/plugin-proposal-dynamic-import@7.16.7", "@babel/plugin-proposal-dynamic-import@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz#c19c897eaa46b27634a00fee9fb7d829158704b2" + integrity sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + + "@babel/plugin-proposal-export-namespace-from@7.16.7", "@babel/plugin-proposal-export-namespace-from@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz#09de09df18445a5786a305681423ae63507a6163" + integrity sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + + "@babel/plugin-proposal-json-strings@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz#9732cb1d17d9a2626a08c5be25186c195b6fa6e8" + integrity sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-json-strings" "^7.8.3" + + "@babel/plugin-proposal-logical-assignment-operators@7.16.7", "@babel/plugin-proposal-logical-assignment-operators@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz#be23c0ba74deec1922e639832904be0bea73cdea" + integrity sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + + "@babel/plugin-proposal-nullish-coalescing-operator@7.16.7", "@babel/plugin-proposal-nullish-coalescing-operator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz#141fc20b6857e59459d430c850a0011e36561d99" + integrity sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + + "@babel/plugin-proposal-numeric-separator@7.16.7", "@babel/plugin-proposal-numeric-separator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz#d6b69f4af63fb38b6ca2558442a7fb191236eba9" + integrity sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + + "@babel/plugin-proposal-object-rest-spread@^7.16.7": + version "7.17.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz#d9eb649a54628a51701aef7e0ea3d17e2b9dd390" + integrity sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw== + dependencies: + "@babel/compat-data" "^7.17.0" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.16.7" + + "@babel/plugin-proposal-optional-catch-binding@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz#c623a430674ffc4ab732fd0a0ae7722b67cb74cf" + integrity sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + + "@babel/plugin-proposal-optional-chaining@7.16.7", "@babel/plugin-proposal-optional-chaining@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz#7cd629564724816c0e8a969535551f943c64c39a" + integrity sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + + "@babel/plugin-proposal-private-methods@7.16.11", "@babel/plugin-proposal-private-methods@^7.16.11": + version "7.16.11" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz#e8df108288555ff259f4527dbe84813aac3a1c50" + integrity sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.10" + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-proposal-private-property-in-object@7.16.7", "@babel/plugin-proposal-private-property-in-object@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz#b0b8cef543c2c3d57e59e2c611994861d46a3fce" + integrity sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + + "@babel/plugin-proposal-unicode-property-regex@^7.16.7", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz#635d18eb10c6214210ffc5ff4932552de08188a2" + integrity sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-syntax-async-generators@7.8.4", "@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + + "@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + + "@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + + "@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + + "@babel/plugin-syntax-dynamic-import@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" + integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + + "@babel/plugin-syntax-export-namespace-from@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" + integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== + 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", "@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + + "@babel/plugin-syntax-jsx@^7.12.13", "@babel/plugin-syntax-jsx@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz#50b6571d13f764266a113d77c82b4a6508bbe665" + integrity sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + + "@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.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + + "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + + "@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + + "@babel/plugin-syntax-object-rest-spread@7.8.3", "@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + + "@babel/plugin-syntax-optional-catch-binding@7.8.3", "@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + + "@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + + "@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^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.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + + "@babel/plugin-syntax-typescript@^7.16.7", "@babel/plugin-syntax-typescript@^7.7.2": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz#39c9b55ee153151990fb038651d58d3fd03f98f8" + integrity sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-arrow-functions@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz#44125e653d94b98db76369de9c396dc14bef4154" + integrity sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-async-to-generator@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz#b83dff4b970cf41f1b819f8b49cc0cfbaa53a808" + integrity sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg== + dependencies: + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-remap-async-to-generator" "^7.16.8" + + "@babel/plugin-transform-block-scoped-functions@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz#4d0d57d9632ef6062cdf354bb717102ee042a620" + integrity sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-block-scoping@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz#f50664ab99ddeaee5bc681b8f3a6ea9d72ab4f87" + integrity sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-classes@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz#8f4b9562850cd973de3b498f1218796eb181ce00" + integrity sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-optimise-call-expression" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + globals "^11.1.0" + + "@babel/plugin-transform-computed-properties@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz#66dee12e46f61d2aae7a73710f591eb3df616470" + integrity sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-destructuring@^7.16.7": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.7.tgz#49dc2675a7afa9a5e4c6bdee636061136c3408d1" + integrity sha512-XVh0r5yq9sLR4vZ6eVZe8FKfIcSgaTBxVBRSYokRj2qksf6QerYnTxz9/GTuKTH/n/HwLP7t6gtlybHetJ/6hQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-dotall-regex@^7.16.7", "@babel/plugin-transform-dotall-regex@^7.4.4": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz#6b2d67686fab15fb6a7fd4bd895d5982cfc81241" + integrity sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-duplicate-keys@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz#2207e9ca8f82a0d36a5a67b6536e7ef8b08823c9" + integrity sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-exponentiation-operator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz#efa9862ef97e9e9e5f653f6ddc7b665e8536fe9b" + integrity sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA== + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-for-of@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz#649d639d4617dff502a9a158c479b3b556728d8c" + integrity sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-function-name@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz#5ab34375c64d61d083d7d2f05c38d90b97ec65cf" + integrity sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA== + dependencies: + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-literals@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz#254c9618c5ff749e87cb0c0cef1a0a050c0bdab1" + integrity sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-member-expression-literals@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz#6e5dcf906ef8a098e630149d14c867dd28f92384" + integrity sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-modules-amd@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz#b28d323016a7daaae8609781d1f8c9da42b13186" + integrity sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g== + dependencies: + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + babel-plugin-dynamic-import-node "^2.3.3" + + "@babel/plugin-transform-modules-commonjs@7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz#cdee19aae887b16b9d331009aa9a219af7c86afe" + integrity sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA== + dependencies: + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-simple-access" "^7.16.7" + babel-plugin-dynamic-import-node "^2.3.3" + + "@babel/plugin-transform-modules-commonjs@^7.16.8": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.7.tgz#d86b217c8e45bb5f2dbc11eefc8eab62cf980d19" + integrity sha512-ITPmR2V7MqioMJyrxUo2onHNC3e+MvfFiFIR0RP21d3PtlVb6sfzoxNKiphSZUOM9hEIdzCcZe83ieX3yoqjUA== + dependencies: + "@babel/helper-module-transforms" "^7.17.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-simple-access" "^7.17.7" + babel-plugin-dynamic-import-node "^2.3.3" + + "@babel/plugin-transform-modules-systemjs@^7.16.7": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.8.tgz#81fd834024fae14ea78fbe34168b042f38703859" + integrity sha512-39reIkMTUVagzgA5x88zDYXPCMT6lcaRKs1+S9K6NKBPErbgO/w/kP8GlNQTC87b412ZTlmNgr3k2JrWgHH+Bw== + dependencies: + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-module-transforms" "^7.17.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-identifier" "^7.16.7" + babel-plugin-dynamic-import-node "^2.3.3" + + "@babel/plugin-transform-modules-umd@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz#23dad479fa585283dbd22215bff12719171e7618" + integrity sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ== + dependencies: + "@babel/helper-module-transforms" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-named-capturing-groups-regex@^7.16.8": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz#7f860e0e40d844a02c9dcf9d84965e7dfd666252" + integrity sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + + "@babel/plugin-transform-new-target@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz#9967d89a5c243818e0800fdad89db22c5f514244" + integrity sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-object-super@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz#ac359cf8d32cf4354d27a46867999490b6c32a94" + integrity sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-replace-supers" "^7.16.7" + + "@babel/plugin-transform-parameters@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz#a1721f55b99b736511cb7e0152f61f17688f331f" + integrity sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-property-literals@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz#2dadac85155436f22c696c4827730e0fe1057a55" + integrity sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-react-jsx@7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.7.tgz#86a6a220552afd0e4e1f0388a68a372be7add0d4" + integrity sha512-8D16ye66fxiE8m890w0BpPpngG9o9OVBBy0gH2E+2AR7qMR2ZpTYJEqLxAsoroenMId0p/wMW+Blc0meDgu0Ag== + dependencies: + "@babel/helper-annotate-as-pure" "^7.16.7" + "@babel/helper-module-imports" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-jsx" "^7.16.7" + "@babel/types" "^7.16.7" + + "@babel/plugin-transform-regenerator@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz#9e7576dc476cb89ccc5096fff7af659243b4adeb" + integrity sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q== + dependencies: + regenerator-transform "^0.14.2" + + "@babel/plugin-transform-reserved-words@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz#1d798e078f7c5958eec952059c460b220a63f586" + integrity sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-shorthand-properties@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz#e8549ae4afcf8382f711794c0c7b6b934c5fbd2a" + integrity sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-spread@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz#a303e2122f9f12e0105daeedd0f30fb197d8ff44" + integrity sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" + + "@babel/plugin-transform-sticky-regex@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz#c84741d4f4a38072b9a1e2e3fd56d359552e8660" + integrity sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-template-literals@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz#f3d1c45d28967c8e80f53666fc9c3e50618217ab" + integrity sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-typeof-symbol@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz#9cdbe622582c21368bd482b660ba87d5545d4f7e" + integrity sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-typescript@^7.16.7": + version "7.16.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz#591ce9b6b83504903fa9dd3652c357c2ba7a1ee0" + integrity sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/plugin-syntax-typescript" "^7.16.7" + + "@babel/plugin-transform-unicode-escapes@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz#da8717de7b3287a2c6d659750c964f302b31ece3" + integrity sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/plugin-transform-unicode-regex@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz#0f7aa4a501198976e25e82702574c34cfebe9ef2" + integrity sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q== + dependencies: + "@babel/helper-create-regexp-features-plugin" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + + "@babel/preset-env@^7.16.11": + version "7.16.11" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.16.11.tgz#5dd88fd885fae36f88fd7c8342475c9f0abe2982" + integrity sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g== + dependencies: + "@babel/compat-data" "^7.16.8" + "@babel/helper-compilation-targets" "^7.16.7" + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-option" "^7.16.7" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.16.7" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.16.7" + "@babel/plugin-proposal-async-generator-functions" "^7.16.8" + "@babel/plugin-proposal-class-properties" "^7.16.7" + "@babel/plugin-proposal-class-static-block" "^7.16.7" + "@babel/plugin-proposal-dynamic-import" "^7.16.7" + "@babel/plugin-proposal-export-namespace-from" "^7.16.7" + "@babel/plugin-proposal-json-strings" "^7.16.7" + "@babel/plugin-proposal-logical-assignment-operators" "^7.16.7" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.7" + "@babel/plugin-proposal-numeric-separator" "^7.16.7" + "@babel/plugin-proposal-object-rest-spread" "^7.16.7" + "@babel/plugin-proposal-optional-catch-binding" "^7.16.7" + "@babel/plugin-proposal-optional-chaining" "^7.16.7" + "@babel/plugin-proposal-private-methods" "^7.16.11" + "@babel/plugin-proposal-private-property-in-object" "^7.16.7" + "@babel/plugin-proposal-unicode-property-regex" "^7.16.7" + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-transform-arrow-functions" "^7.16.7" + "@babel/plugin-transform-async-to-generator" "^7.16.8" + "@babel/plugin-transform-block-scoped-functions" "^7.16.7" + "@babel/plugin-transform-block-scoping" "^7.16.7" + "@babel/plugin-transform-classes" "^7.16.7" + "@babel/plugin-transform-computed-properties" "^7.16.7" + "@babel/plugin-transform-destructuring" "^7.16.7" + "@babel/plugin-transform-dotall-regex" "^7.16.7" + "@babel/plugin-transform-duplicate-keys" "^7.16.7" + "@babel/plugin-transform-exponentiation-operator" "^7.16.7" + "@babel/plugin-transform-for-of" "^7.16.7" + "@babel/plugin-transform-function-name" "^7.16.7" + "@babel/plugin-transform-literals" "^7.16.7" + "@babel/plugin-transform-member-expression-literals" "^7.16.7" + "@babel/plugin-transform-modules-amd" "^7.16.7" + "@babel/plugin-transform-modules-commonjs" "^7.16.8" + "@babel/plugin-transform-modules-systemjs" "^7.16.7" + "@babel/plugin-transform-modules-umd" "^7.16.7" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.16.8" + "@babel/plugin-transform-new-target" "^7.16.7" + "@babel/plugin-transform-object-super" "^7.16.7" + "@babel/plugin-transform-parameters" "^7.16.7" + "@babel/plugin-transform-property-literals" "^7.16.7" + "@babel/plugin-transform-regenerator" "^7.16.7" + "@babel/plugin-transform-reserved-words" "^7.16.7" + "@babel/plugin-transform-shorthand-properties" "^7.16.7" + "@babel/plugin-transform-spread" "^7.16.7" + "@babel/plugin-transform-sticky-regex" "^7.16.7" + "@babel/plugin-transform-template-literals" "^7.16.7" + "@babel/plugin-transform-typeof-symbol" "^7.16.7" + "@babel/plugin-transform-unicode-escapes" "^7.16.7" + "@babel/plugin-transform-unicode-regex" "^7.16.7" + "@babel/preset-modules" "^0.1.5" + "@babel/types" "^7.16.8" + babel-plugin-polyfill-corejs2 "^0.3.0" + babel-plugin-polyfill-corejs3 "^0.5.0" + babel-plugin-polyfill-regenerator "^0.3.0" + core-js-compat "^3.20.2" + semver "^6.3.0" + + "@babel/preset-modules@^0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" + integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" + "@babel/plugin-transform-dotall-regex" "^7.4.4" + "@babel/types" "^7.4.4" + esutils "^2.0.2" + + "@babel/preset-typescript@7.16.7", "@babel/preset-typescript@^7.16.7": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz#ab114d68bb2020afc069cd51b37ff98a046a70b9" + integrity sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ== + dependencies: + "@babel/helper-plugin-utils" "^7.16.7" + "@babel/helper-validator-option" "^7.16.7" + "@babel/plugin-transform-typescript" "^7.16.7" + + "@babel/runtime-corejs3@^7.10.2": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.17.7.tgz#cf914f474c490ef1aa8661d47adaa0a993636e7e" + integrity sha512-TvliGJjhxis5m7xIMvlXH/xG8Oa/LK0SCUCyfKD6nLi42n5fB4WibDJ0g9trmmBB6hwpMNx+Lzbxy9/4gpMaVw== + dependencies: + core-js-pure "^3.20.2" + regenerator-runtime "^0.13.4" + + "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.13.17", "@babel/runtime@^7.14.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.0": + version "7.17.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.7.tgz#a5f3328dc41ff39d803f311cfe17703418cf9825" + integrity sha512-L6rvG9GDxaLgFjg41K+5Yv9OMrU98sWe+Ykmc6FDJW/+vYZMhdOMKkISgzptMaERHvS2Y2lw9MDRm2gHhlQQoA== + dependencies: + regenerator-runtime "^0.13.4" + + "@babel/runtime@^7.8.4": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.8.tgz#3e56e4aff81befa55ac3ac6a0967349fd1c5bca2" + integrity sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA== + dependencies: + regenerator-runtime "^0.13.4" + + "@babel/template@^7.12.13", "@babel/template@^7.16.7", "@babel/template@^7.3.3": + version "7.16.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" + integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/parser" "^7.16.7" + "@babel/types" "^7.16.7" + + "@babel/traverse@7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.13.0.tgz#6d95752475f86ee7ded06536de309a65fc8966cc" + integrity sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ== + dependencies: + "@babel/code-frame" "^7.12.13" + "@babel/generator" "^7.13.0" + "@babel/helper-function-name" "^7.12.13" + "@babel/helper-split-export-declaration" "^7.12.13" + "@babel/parser" "^7.13.0" + "@babel/types" "^7.13.0" + debug "^4.1.0" + globals "^11.1.0" + lodash "^4.17.19" + + "@babel/traverse@^7.1.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.16.10", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.0", "@babel/traverse@^7.17.3", "@babel/traverse@^7.7.2": + version "7.17.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57" + integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw== + dependencies: + "@babel/code-frame" "^7.16.7" + "@babel/generator" "^7.17.3" + "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-function-name" "^7.16.7" + "@babel/helper-hoist-variables" "^7.16.7" + "@babel/helper-split-export-declaration" "^7.16.7" + "@babel/parser" "^7.17.3" + "@babel/types" "^7.17.0" + debug "^4.1.0" + globals "^11.1.0" + + "@babel/types@7.13.0": + version "7.13.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.0.tgz#74424d2816f0171b4100f0ab34e9a374efdf7f80" + integrity sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA== + dependencies: + "@babel/helper-validator-identifier" "^7.12.11" + lodash "^4.17.19" + to-fast-properties "^2.0.0" + + "@babel/types@^7.0.0", "@babel/types@^7.13.0", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.17.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": + version "7.17.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b" + integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw== + dependencies: + "@babel/helper-validator-identifier" "^7.16.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== + + "@boxyhq/saml-jackson@0.3.6": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@boxyhq/saml-jackson/-/saml-jackson-0.3.6.tgz#fc76e696094d5dcb780167a8c730d073cdb4ec1b" + integrity sha512-5kRk4VqkxlYwAJ1S4KMvrbn0R6YddT1/dA60w6HVO4CZiKDnspreLG6Q3WSU8D1hLj7mhqDUz4Joacvwynx+fg== + dependencies: + "@boxyhq/saml20" "0.2.0" + "@peculiar/webcrypto" "1.2.3" + "@peculiar/x509" "1.6.1" + cors "2.8.5" + express "4.17.2" + mongodb "4.3.0" + mysql2 "2.3.3" + pg "8.7.1" + rambda "7.0.1" + redis "4.0.1" + reflect-metadata "0.1.13" + ripemd160 "2.0.2" + thumbprint "0.0.1" + typeorm "0.2.41" + xml-crypto "2.1.3" + xml2js "0.4.23" + xmlbuilder "15.1.1" + + "@boxyhq/saml20@0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@boxyhq/saml20/-/saml20-0.2.0.tgz#251eb675f3c08ff65bc67e009d5f5119dcc4719f" + integrity sha512-octyllYuCD//N8DagXB5BMpDQ4B1aA6wTDC0XI72z2E+GJMwPzwYLSvzwKpSetsaXRUYPiIexxqyPYRqA+Uqnw== + dependencies: + "@xmldom/xmldom" "0.7.5" + lodash "^4.17.21" + thumbprint "^0.0.1" + xml-crypto "^2.1.3" + xml2js "^0.4.23" + + "@cnakazawa/watch@^1.0.3": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" + integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== + dependencies: + exec-sh "^0.3.2" + minimist "^1.2.0" + + "@cspotcode/source-map-consumer@0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" + integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== + + "@cspotcode/source-map-support@0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5" + integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA== + dependencies: + "@cspotcode/source-map-consumer" "0.8.0" + + "@daily-co/daily-js@^0.18.0": + version "0.18.0" + resolved "https://registry.yarnpkg.com/@daily-co/daily-js/-/daily-js-0.18.0.tgz#b8341c2ac12b6e27fec2ab187be6cca699e60dce" + integrity sha512-MXY6mpC0bJ1RCbVLlNioOfoNFhMX8lwoI/G9t3d/CAQqO9brxnp73t2Ltyaf2SXMIR+S88flgtfMcRtEBnFsjQ== + dependencies: + "@babel/runtime" "^7.12.5" + bowser "^2.8.1" + events "^3.1.0" + fast-equals "^1.6.3" + lodash "^4.17.15" + + "@daily-co/daily-js@^0.21.0": + version "0.21.0" + resolved "https://registry.yarnpkg.com/@daily-co/daily-js/-/daily-js-0.21.0.tgz#f0773d5e430dc886763ddfe8d100262774db3ce6" + integrity sha512-yE5xXrhaVWxXMGYraJkFvuohHnuh8ytv2WudQxcPe+et3Vajx2gG4TMnBAu+bH6Nf3WBcIJjETIq++jjvrSUiw== + dependencies: + "@babel/runtime" "^7.12.5" + bowser "^2.8.1" + events "^3.1.0" + fast-equals "^1.6.3" + lodash "^4.17.15" + + "@emotion/babel-plugin@^11.7.1": + version "11.7.2" + resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.7.2.tgz#fec75f38a6ab5b304b0601c74e2a5e77c95e5fa0" + integrity sha512-6mGSCWi9UzXut/ZAN6lGFu33wGR3SJisNl3c0tvlmb8XChH1b2SUvxvnOh7hvLpqyRdHHU9AiazV3Cwbk5SXKQ== + dependencies: + "@babel/helper-module-imports" "^7.12.13" + "@babel/plugin-syntax-jsx" "^7.12.13" + "@babel/runtime" "^7.13.10" + "@emotion/hash" "^0.8.0" + "@emotion/memoize" "^0.7.5" + "@emotion/serialize" "^1.0.2" + babel-plugin-macros "^2.6.1" + convert-source-map "^1.5.0" + escape-string-regexp "^4.0.0" + find-root "^1.1.0" + source-map "^0.5.7" + stylis "4.0.13" + + "@emotion/cache@^11.4.0", "@emotion/cache@^11.7.1": + version "11.7.1" + resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.7.1.tgz#08d080e396a42e0037848214e8aa7bf879065539" + integrity sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A== + dependencies: + "@emotion/memoize" "^0.7.4" + "@emotion/sheet" "^1.1.0" + "@emotion/utils" "^1.0.0" + "@emotion/weak-memoize" "^0.2.5" + stylis "4.0.13" + + "@emotion/hash@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" + integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== + + "@emotion/memoize@^0.7.4", "@emotion/memoize@^0.7.5": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50" + integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ== + + "@emotion/react@^11.1.1": + version "11.8.2" + resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.8.2.tgz#e51f5e6372e22e82780836c9288da19af4b51e70" + integrity sha512-+1bcHBaNJv5nkIIgnGKVsie3otS0wF9f1T1hteF3WeVvMNQEtfZ4YyFpnphGoot3ilU/wWMgP2SgIDuHLE/wAA== + dependencies: + "@babel/runtime" "^7.13.10" + "@emotion/babel-plugin" "^11.7.1" + "@emotion/cache" "^11.7.1" + "@emotion/serialize" "^1.0.2" + "@emotion/utils" "^1.1.0" + "@emotion/weak-memoize" "^0.2.5" + hoist-non-react-statics "^3.3.1" + + "@emotion/serialize@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.2.tgz#77cb21a0571c9f68eb66087754a65fa97bfcd965" + integrity sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A== + dependencies: + "@emotion/hash" "^0.8.0" + "@emotion/memoize" "^0.7.4" + "@emotion/unitless" "^0.7.5" + "@emotion/utils" "^1.0.0" + csstype "^3.0.2" + + "@emotion/sheet@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.1.0.tgz#56d99c41f0a1cda2726a05aa6a20afd4c63e58d2" + integrity sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g== + + "@emotion/unitless@^0.7.5": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" + integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== + + "@emotion/utils@^1.0.0", "@emotion/utils@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.1.0.tgz#86b0b297f3f1a0f2bdb08eeac9a2f49afd40d0cf" + integrity sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ== + + "@emotion/weak-memoize@^0.2.5": + version "0.2.5" + resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" + integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== + + "@eslint/eslintrc@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.1.tgz#8b5e1c49f4077235516bc9ec7d41378c0f69b8c6" + integrity sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.3.1" + globals "^13.9.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.0.4" + strip-json-comments "^3.1.1" + + "@ethereumjs/common@^2.5.0", "@ethereumjs/common@^2.6.1": + version "2.6.2" + resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.6.2.tgz#eb006c9329c75c80f634f340dc1719a5258244df" + integrity sha512-vDwye5v0SVeuDky4MtKsu+ogkH2oFUV8pBKzH/eNBzT8oI91pKa8WyzDuYuxOQsgNgv5R34LfFDh2aaw3H4HbQ== + dependencies: + crc-32 "^1.2.0" + ethereumjs-util "^7.1.4" + + "@ethereumjs/tx@^3.3.2": + version "3.5.0" + resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.5.0.tgz#783b0aeb08518b9991b23f5155763bbaf930a037" + integrity sha512-/+ZNbnJhQhXC83Xuvy6I9k4jT5sXiV0tMR9C+AzSSpcCV64+NB8dTE1m3x98RYMqb8+TLYWA+HML4F5lfXTlJw== + dependencies: + "@ethereumjs/common" "^2.6.1" + ethereumjs-util "^7.1.4" + + "@ethersproject/abi@5.0.7": + version "5.0.7" + resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.0.7.tgz#79e52452bd3ca2956d0e1c964207a58ad1a0ee7b" + integrity sha512-Cqktk+hSIckwP/W8O47Eef60VwmoSC/L3lY0+dIBhQPCNn9E4V7rwmm2aFrNRRDJfFlGuZ1khkQUOc3oBX+niw== + dependencies: + "@ethersproject/address" "^5.0.4" + "@ethersproject/bignumber" "^5.0.7" + "@ethersproject/bytes" "^5.0.4" + "@ethersproject/constants" "^5.0.4" + "@ethersproject/hash" "^5.0.4" + "@ethersproject/keccak256" "^5.0.3" + "@ethersproject/logger" "^5.0.5" + "@ethersproject/properties" "^5.0.3" + "@ethersproject/strings" "^5.0.4" + + "@ethersproject/abstract-provider@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.6.0.tgz#0c4ac7054650dbd9c476cf5907f588bbb6ef3061" + integrity sha512-oPMFlKLN+g+y7a79cLK3WiLcjWFnZQtXWgnLAbHZcN3s7L4v90UHpTOrLk+m3yr0gt+/h9STTM6zrr7PM8uoRw== + dependencies: + "@ethersproject/bignumber" "^5.6.0" + "@ethersproject/bytes" "^5.6.0" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/networks" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/transactions" "^5.6.0" + "@ethersproject/web" "^5.6.0" + + "@ethersproject/abstract-signer@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.6.0.tgz#9cd7ae9211c2b123a3b29bf47aab17d4d016e3e7" + integrity sha512-WOqnG0NJKtI8n0wWZPReHtaLkDByPL67tn4nBaDAhmVq8sjHTPbCdz4DRhVu/cfTOvfy9w3iq5QZ7BX7zw56BQ== + dependencies: + "@ethersproject/abstract-provider" "^5.6.0" + "@ethersproject/bignumber" "^5.6.0" + "@ethersproject/bytes" "^5.6.0" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + + "@ethersproject/address@^5.0.4", "@ethersproject/address@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.6.0.tgz#13c49836d73e7885fc148ad633afad729da25012" + integrity sha512-6nvhYXjbXsHPS+30sHZ+U4VMagFC/9zAk6Gd/h3S21YW4+yfb0WfRtaAIZ4kfM4rrVwqiy284LP0GtL5HXGLxQ== + dependencies: + "@ethersproject/bignumber" "^5.6.0" + "@ethersproject/bytes" "^5.6.0" + "@ethersproject/keccak256" "^5.6.0" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/rlp" "^5.6.0" + + "@ethersproject/base64@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.6.0.tgz#a12c4da2a6fb86d88563216b0282308fc15907c9" + integrity sha512-2Neq8wxJ9xHxCF9TUgmKeSh9BXJ6OAxWfeGWvbauPh8FuHEjamgHilllx8KkSd5ErxyHIX7Xv3Fkcud2kY9ezw== + dependencies: + "@ethersproject/bytes" "^5.6.0" + + "@ethersproject/bignumber@^5.0.7", "@ethersproject/bignumber@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.6.0.tgz#116c81b075c57fa765a8f3822648cf718a8a0e26" + integrity sha512-VziMaXIUHQlHJmkv1dlcd6GY2PmT0khtAqaMctCIDogxkrarMzA9L94KN1NeXqqOfFD6r0sJT3vCTOFSmZ07DA== + dependencies: + "@ethersproject/bytes" "^5.6.0" + "@ethersproject/logger" "^5.6.0" + bn.js "^4.11.9" + + "@ethersproject/bytes@^5.0.4", "@ethersproject/bytes@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.6.0.tgz#81652f2a0e04533575befadce555213c11d8aa20" + integrity sha512-3hJPlYemb9V4VLfJF5BfN0+55vltPZSHU3QKUyP9M3Y2TcajbiRrz65UG+xVHOzBereB1b9mn7r12o177xgN7w== + dependencies: + "@ethersproject/logger" "^5.6.0" + + "@ethersproject/constants@^5.0.4", "@ethersproject/constants@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.6.0.tgz#55e3eb0918584d3acc0688e9958b0cedef297088" + integrity sha512-SrdaJx2bK0WQl23nSpV/b1aq293Lh0sUaZT/yYKPDKn4tlAbkH96SPJwIhwSwTsoQQZxuh1jnqsKwyymoiBdWA== + dependencies: + "@ethersproject/bignumber" "^5.6.0" + + "@ethersproject/hash@^5.0.4": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.6.0.tgz#d24446a5263e02492f9808baa99b6e2b4c3429a2" + integrity sha512-fFd+k9gtczqlr0/BruWLAu7UAOas1uRRJvOR84uDf4lNZ+bTkGl366qvniUZHKtlqxBRU65MkOobkmvmpHU+jA== + dependencies: + "@ethersproject/abstract-signer" "^5.6.0" + "@ethersproject/address" "^5.6.0" + "@ethersproject/bignumber" "^5.6.0" + "@ethersproject/bytes" "^5.6.0" + "@ethersproject/keccak256" "^5.6.0" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/strings" "^5.6.0" + + "@ethersproject/keccak256@^5.0.3", "@ethersproject/keccak256@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.6.0.tgz#fea4bb47dbf8f131c2e1774a1cecbfeb9d606459" + integrity sha512-tk56BJ96mdj/ksi7HWZVWGjCq0WVl/QvfhFQNeL8fxhBlGoP+L80uDCiQcpJPd+2XxkivS3lwRm3E0CXTfol0w== + dependencies: + "@ethersproject/bytes" "^5.6.0" + js-sha3 "0.8.0" + + "@ethersproject/logger@^5.0.5", "@ethersproject/logger@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.6.0.tgz#d7db1bfcc22fd2e4ab574cba0bb6ad779a9a3e7a" + integrity sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg== + + "@ethersproject/networks@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.6.0.tgz#486d03fff29b4b6b5414d47a232ded09fe10de5e" + integrity sha512-DaVzgyThzHgSDLuURhvkp4oviGoGe9iTZW4jMEORHDRCgSZ9K9THGFKqL+qGXqPAYLEgZTf5z2w56mRrPR1MjQ== + dependencies: + "@ethersproject/logger" "^5.6.0" + + "@ethersproject/properties@^5.0.3", "@ethersproject/properties@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.6.0.tgz#38904651713bc6bdd5bdd1b0a4287ecda920fa04" + integrity sha512-szoOkHskajKePTJSZ46uHUWWkbv7TzP2ypdEK6jGMqJaEt2sb0jCgfBo0gH0m2HBpRixMuJ6TBRaQCF7a9DoCg== + dependencies: + "@ethersproject/logger" "^5.6.0" + + "@ethersproject/rlp@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.6.0.tgz#55a7be01c6f5e64d6e6e7edb6061aa120962a717" + integrity sha512-dz9WR1xpcTL+9DtOT/aDO+YyxSSdO8YIS0jyZwHHSlAmnxA6cKU3TrTd4Xc/bHayctxTgGLYNuVVoiXE4tTq1g== + dependencies: + "@ethersproject/bytes" "^5.6.0" + "@ethersproject/logger" "^5.6.0" + + "@ethersproject/signing-key@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.6.0.tgz#4f02e3fb09e22b71e2e1d6dc4bcb5dafa69ce042" + integrity sha512-S+njkhowmLeUu/r7ir8n78OUKx63kBdMCPssePS89So1TH4hZqnWFsThEd/GiXYp9qMxVrydf7KdM9MTGPFukA== + dependencies: + "@ethersproject/bytes" "^5.6.0" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + bn.js "^4.11.9" + elliptic "6.5.4" + hash.js "1.1.7" + + "@ethersproject/strings@^5.0.4", "@ethersproject/strings@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.6.0.tgz#9891b26709153d996bf1303d39a7f4bc047878fd" + integrity sha512-uv10vTtLTZqrJuqBZR862ZQjTIa724wGPWQqZrofaPI/kUsf53TBG0I0D+hQ1qyNtllbNzaW+PDPHHUI6/65Mg== + dependencies: + "@ethersproject/bytes" "^5.6.0" + "@ethersproject/constants" "^5.6.0" + "@ethersproject/logger" "^5.6.0" + + "@ethersproject/transactions@^5.0.0-beta.135", "@ethersproject/transactions@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.6.0.tgz#4b594d73a868ef6e1529a2f8f94a785e6791ae4e" + integrity sha512-4HX+VOhNjXHZyGzER6E/LVI2i6lf9ejYeWD6l4g50AdmimyuStKc39kvKf1bXWQMg7QNVh+uC7dYwtaZ02IXeg== + dependencies: + "@ethersproject/address" "^5.6.0" + "@ethersproject/bignumber" "^5.6.0" + "@ethersproject/bytes" "^5.6.0" + "@ethersproject/constants" "^5.6.0" + "@ethersproject/keccak256" "^5.6.0" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/rlp" "^5.6.0" + "@ethersproject/signing-key" "^5.6.0" + + "@ethersproject/web@^5.6.0": + version "5.6.0" + resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.6.0.tgz#4bf8b3cbc17055027e1a5dd3c357e37474eaaeb8" + integrity sha512-G/XHj0hV1FxI2teHRfCGvfBUHFmU+YOSbCxlAMqJklxSa7QMiHFQfAxvwY2PFqgvdkxEKwRNr/eCjfAPEm2Ctg== + dependencies: + "@ethersproject/base64" "^5.6.0" + "@ethersproject/bytes" "^5.6.0" + "@ethersproject/logger" "^5.6.0" + "@ethersproject/properties" "^5.6.0" + "@ethersproject/strings" "^5.6.0" + + "@formatjs/ecma402-abstract@1.11.3": + version "1.11.3" + resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.3.tgz#f25276dfd4ef3dac90da667c3961d8aa9732e384" + integrity sha512-kP/Buv5vVFMAYLHNvvUzr0lwRTU0u2WTy44Tqwku1X3C3lJ5dKqDCYVqA8wL+Y19Bq+MwHgxqd5FZJRCIsLRyQ== + dependencies: + "@formatjs/intl-localematcher" "0.2.24" + tslib "^2.1.0" + + "@formatjs/fast-memoize@1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-1.2.1.tgz#e6f5aee2e4fd0ca5edba6eba7668e2d855e0fc21" + integrity sha512-Rg0e76nomkz3vF9IPlKeV+Qynok0r7YZjL6syLz4/urSg0IbjPZCB/iYUMNsYA643gh4mgrX3T7KEIFIxJBQeg== + dependencies: + tslib "^2.1.0" + + "@formatjs/icu-messageformat-parser@2.0.18": + version "2.0.18" + resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.0.18.tgz#b09e8f16b88e988fd125e7c5810300e8a6dd2c42" + integrity sha512-vquIzsAJJmZ5jWVH8dEgUKcbG4yu3KqtyPet+q35SW5reLOvblkfeCXTRW2TpIwNXzdVqsJBwjbTiRiSU9JxwQ== + dependencies: + "@formatjs/ecma402-abstract" "1.11.3" + "@formatjs/icu-skeleton-parser" "1.3.5" + tslib "^2.1.0" + + "@formatjs/icu-skeleton-parser@1.3.5": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.5.tgz#babc93a1c36383cf87cbb3d2f2145d26c2f7cb40" + integrity sha512-Nhyo2/6kG7ZfgeEfo02sxviOuBcvtzH6SYUharj3DLCDJH3A/4OxkKcmx/2PWGX4bc6iSieh+FA94CsKDxnZBQ== + dependencies: + "@formatjs/ecma402-abstract" "1.11.3" + tslib "^2.1.0" + + "@formatjs/intl-displaynames@5.4.2": + version "5.4.2" + resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-5.4.2.tgz#feb6b41087a88286d178032490a8ca78bafd4c56" + integrity sha512-SLesCDan9NCMqBbHPXMEwqAcPn3tnbQw0sv0rssH1JQDLDUQYwKXL93kz30X3yskTyQS7N+pd47bhoIe3kbXyw== + dependencies: + "@formatjs/ecma402-abstract" "1.11.3" + "@formatjs/intl-localematcher" "0.2.24" + tslib "^2.1.0" + + "@formatjs/intl-listformat@6.5.2": + version "6.5.2" + resolved "https://registry.yarnpkg.com/@formatjs/intl-listformat/-/intl-listformat-6.5.2.tgz#7fbc310db89e866250e34084e914894c67e09254" + integrity sha512-/IYagQJkzTvpBlhhaysGYNgM3o72WBg1ZWZcpookkgXEJbINwLP5kVagHxmgxffYKs1CDzQ8rmKHghu2qR/7zw== + dependencies: + "@formatjs/ecma402-abstract" "1.11.3" + "@formatjs/intl-localematcher" "0.2.24" + tslib "^2.1.0" + + "@formatjs/intl-localematcher@0.2.24": + version "0.2.24" + resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.2.24.tgz#b49fd753c0f54421f26a3c1d0e9cf98a3966e78f" + integrity sha512-K/HRGo6EMnCbhpth/y3u4rW4aXkmQNqRe1L2G+Y5jNr3v0gYhvaucV8WixNju/INAMbPBlbsRBRo/nfjnoOnxQ== + dependencies: + tslib "^2.1.0" + + "@formatjs/intl@2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-2.1.0.tgz#383b186b1f26195ac896fc6912871abccf9dad2d" + integrity sha512-1iGGqKcCym+ZH+cktHa6YILVGn8Sve+yuYK7hJpN21JiPKCPJuFJViKFY6rDM5jnj5LDCeH8N5YbhQjccDVOVA== + dependencies: + "@formatjs/ecma402-abstract" "1.11.3" + "@formatjs/fast-memoize" "1.2.1" + "@formatjs/icu-messageformat-parser" "2.0.18" + "@formatjs/intl-displaynames" "5.4.2" + "@formatjs/intl-listformat" "6.5.2" + intl-messageformat "9.11.4" + tslib "^2.1.0" + + "@glidejs/glide@^3.5.2": + version "3.5.2" + resolved "https://registry.yarnpkg.com/@glidejs/glide/-/glide-3.5.2.tgz#7012c5920ecf202bbda44d8526fc979984b6dd54" + integrity sha512-7jGciNJ2bQ4eZLSNlSZ+VAyW63kALf420CvkEpK4lEsUfWJq9odqimci0YCiyNyMUFB+pWHwLYyNc57dijYsCg== + + "@headlessui/react@^1.4.1": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.5.0.tgz#483b44ba2c8b8d4391e1d2c863898d7dd0cc0296" + integrity sha512-aaRnYxBb3MU2FNJf3Ut9RMTUqqU3as0aI1lQhgo2n9Fa67wRu14iOGqx93xB+uMNVfNwZ5B3y/Ndm7qZGuFeMQ== + + "@heroicons/react@^1.0.4", "@heroicons/react@^1.0.5": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-1.0.6.tgz#35dd26987228b39ef2316db3b1245c42eb19e324" + integrity sha512-JJCXydOFWMDpCP4q13iEplA503MQO3xLoZiKum+955ZCtHINWnx26CUxVxxFQu/uLb4LW3ge15ZpzIkXKkJ8oQ== + + "@hookform/error-message@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@hookform/error-message/-/error-message-2.0.0.tgz#9b1b037fd816ea9b1531c06aa7fab5f5154aa740" + integrity sha512-Y90nHzjgL2MP7GFy75kscdvxrCTjtyxGmOLLxX14nd08OXRIh9lMH/y9Kpdo0p1IPowJBiZMHyueg7p+yrqynQ== + + "@hookform/resolvers@^2.8.1", "@hookform/resolvers@^2.8.5": + version "2.8.8" + resolved "https://registry.yarnpkg.com/@hookform/resolvers/-/resolvers-2.8.8.tgz#17cf806485435877fdafce9f3bee6ff68f7f87b6" + integrity sha512-meAEDur1IJBfKyTo9yPYAuzjIfrxA7m9Ov+1nxaW/YupsqMeseWifoUjWK03+hz/RJizsVQAaUjVxFEkyu0GWg== + + "@humanwhocodes/config-array@^0.9.2": + version "0.9.5" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" + integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.4" + + "@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + + "@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + + "@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + + "@jest/console@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.6.2.tgz#4e04bc464014358b03ab4937805ee36a0aeb98f2" + integrity sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g== + dependencies: + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^26.6.2" + jest-util "^26.6.2" + slash "^3.0.0" + + "@jest/console@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.5.1.tgz#260fe7239602fe5130a94f1aa386eff54b014bba" + integrity sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^27.5.1" + jest-util "^27.5.1" + slash "^3.0.0" + + "@jest/core@^26.6.3": + version "26.6.3" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.6.3.tgz#7639fcb3833d748a4656ada54bde193051e45fad" + integrity sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw== + dependencies: + "@jest/console" "^26.6.2" + "@jest/reporters" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-changed-files "^26.6.2" + jest-config "^26.6.3" + jest-haste-map "^26.6.2" + jest-message-util "^26.6.2" + jest-regex-util "^26.0.0" + jest-resolve "^26.6.2" + jest-resolve-dependencies "^26.6.3" + jest-runner "^26.6.3" + jest-runtime "^26.6.3" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" + jest-watcher "^26.6.2" + micromatch "^4.0.2" + p-each-series "^2.1.0" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + + "@jest/core@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.5.1.tgz#267ac5f704e09dc52de2922cbf3af9edcd64b626" + integrity sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ== + dependencies: + "@jest/console" "^27.5.1" + "@jest/reporters" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.8.1" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^27.5.1" + jest-config "^27.5.1" + jest-haste-map "^27.5.1" + jest-message-util "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-resolve-dependencies "^27.5.1" + jest-runner "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + jest-watcher "^27.5.1" + micromatch "^4.0.4" + rimraf "^3.0.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + + "@jest/environment@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.6.2.tgz#ba364cc72e221e79cc8f0a99555bf5d7577cf92c" + integrity sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA== + dependencies: + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" + + "@jest/environment@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.5.1.tgz#d7425820511fe7158abbecc010140c3fd3be9c74" + integrity sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA== + dependencies: + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" + + "@jest/fake-timers@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.6.2.tgz#459c329bcf70cee4af4d7e3f3e67848123535aad" + integrity sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA== + dependencies: + "@jest/types" "^26.6.2" + "@sinonjs/fake-timers" "^6.0.1" + "@types/node" "*" + jest-message-util "^26.6.2" + jest-mock "^26.6.2" + jest-util "^26.6.2" + + "@jest/fake-timers@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.5.1.tgz#76979745ce0579c8a94a4678af7a748eda8ada74" + integrity sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ== + dependencies: + "@jest/types" "^27.5.1" + "@sinonjs/fake-timers" "^8.0.1" + "@types/node" "*" + jest-message-util "^27.5.1" + jest-mock "^27.5.1" + jest-util "^27.5.1" + + "@jest/globals@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.6.2.tgz#5b613b78a1aa2655ae908eba638cc96a20df720a" + integrity sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA== + dependencies: + "@jest/environment" "^26.6.2" + "@jest/types" "^26.6.2" + expect "^26.6.2" + + "@jest/globals@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.5.1.tgz#7ac06ce57ab966566c7963431cef458434601b2b" + integrity sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/types" "^27.5.1" + expect "^27.5.1" + + "@jest/reporters@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.6.2.tgz#1f518b99637a5f18307bd3ecf9275f6882a667f6" + integrity sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.2" + graceful-fs "^4.2.4" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^4.0.3" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.0.2" + jest-haste-map "^26.6.2" + jest-resolve "^26.6.2" + jest-util "^26.6.2" + jest-worker "^26.6.2" + slash "^3.0.0" + source-map "^0.6.0" + string-length "^4.0.1" + terminal-link "^2.0.0" + v8-to-istanbul "^7.0.0" + optionalDependencies: + node-notifier "^8.0.0" + + "@jest/reporters@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.5.1.tgz#ceda7be96170b03c923c37987b64015812ffec04" + integrity sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.2" + 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-haste-map "^27.5.1" + jest-resolve "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" + slash "^3.0.0" + source-map "^0.6.0" + string-length "^4.0.1" + terminal-link "^2.0.0" + v8-to-istanbul "^8.1.0" + + "@jest/source-map@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.6.2.tgz#29af5e1e2e324cafccc936f218309f54ab69d535" + integrity sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA== + dependencies: + callsites "^3.0.0" + graceful-fs "^4.2.4" + source-map "^0.6.0" + + "@jest/source-map@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.5.1.tgz#6608391e465add4205eae073b55e7f279e04e8cf" + integrity sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg== + dependencies: + callsites "^3.0.0" + graceful-fs "^4.2.9" + source-map "^0.6.0" + + "@jest/test-result@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.6.2.tgz#55da58b62df134576cc95476efa5f7949e3f5f18" + integrity sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ== + dependencies: + "@jest/console" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + + "@jest/test-result@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.5.1.tgz#56a6585fa80f7cdab72b8c5fc2e871d03832f5bb" + integrity sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag== + dependencies: + "@jest/console" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + + "@jest/test-sequencer@^26.6.3": + version "26.6.3" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz#98e8a45100863886d074205e8ffdc5a7eb582b17" + integrity sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw== + dependencies: + "@jest/test-result" "^26.6.2" + graceful-fs "^4.2.4" + jest-haste-map "^26.6.2" + jest-runner "^26.6.3" + jest-runtime "^26.6.3" + + "@jest/test-sequencer@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz#4057e0e9cea4439e544c6353c6affe58d095745b" + integrity sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ== + dependencies: + "@jest/test-result" "^27.5.1" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-runtime "^27.5.1" + + "@jest/transform@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.6.2.tgz#5ac57c5fa1ad17b2aae83e73e45813894dcf2e4b" + integrity sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^26.6.2" + babel-plugin-istanbul "^6.0.0" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.4" + jest-haste-map "^26.6.2" + jest-regex-util "^26.0.0" + jest-util "^26.6.2" + micromatch "^4.0.2" + pirates "^4.0.1" + slash "^3.0.0" + source-map "^0.6.1" + write-file-atomic "^3.0.0" + + "@jest/transform@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.5.1.tgz#6c3501dcc00c4c08915f292a600ece5ecfe1f409" + integrity sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^27.5.1" + 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 "^27.5.1" + jest-regex-util "^27.5.1" + jest-util "^27.5.1" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + source-map "^0.6.1" + write-file-atomic "^3.0.0" + + "@jest/types@^26.6.2": + version "26.6.2" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" + integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^15.0.0" + chalk "^4.0.0" + + "@jest/types@^27.2.5", "@jest/types@^27.5.1": + version "27.5.1" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80" + integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + + "@jimp/bmp@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/bmp/-/bmp-0.16.1.tgz#6e2da655b2ba22e721df0795423f34e92ef13768" + integrity sha512-iwyNYQeBawrdg/f24x3pQ5rEx+/GwjZcCXd3Kgc+ZUd+Ivia7sIqBsOnDaMZdKCBPlfW364ekexnlOqyVa0NWg== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + bmp-js "^0.1.0" + + "@jimp/core@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/core/-/core-0.16.1.tgz#68c4288f6ef7f31a0f6b859ba3fb28dae930d39d" + integrity sha512-la7kQia31V6kQ4q1kI/uLimu8FXx7imWVajDGtwUG8fzePLWDFJyZl0fdIXVCL1JW2nBcRHidUot6jvlRDi2+g== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + any-base "^1.1.0" + buffer "^5.2.0" + exif-parser "^0.1.12" + file-type "^9.0.0" + load-bmfont "^1.3.1" + mkdirp "^0.5.1" + phin "^2.9.1" + pixelmatch "^4.0.2" + tinycolor2 "^1.4.1" + + "@jimp/custom@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/custom/-/custom-0.16.1.tgz#28b659c59e20a1d75a0c46067bd3f4bd302cf9c5" + integrity sha512-DNUAHNSiUI/j9hmbatD6WN/EBIyeq4AO0frl5ETtt51VN1SvE4t4v83ZA/V6ikxEf3hxLju4tQ5Pc3zmZkN/3A== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/core" "^0.16.1" + + "@jimp/gif@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/gif/-/gif-0.16.1.tgz#d1f7c3a58f4666482750933af8b8f4666414f3ca" + integrity sha512-r/1+GzIW1D5zrP4tNrfW+3y4vqD935WBXSc8X/wm23QTY9aJO9Lw6PEdzpYCEY+SOklIFKaJYUAq/Nvgm/9ryw== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + gifwrap "^0.9.2" + omggif "^1.0.9" + + "@jimp/jpeg@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/jpeg/-/jpeg-0.16.1.tgz#3b7bb08a4173f2f6d81f3049b251df3ee2ac8175" + integrity sha512-8352zrdlCCLFdZ/J+JjBslDvml+fS3Z8gttdml0We759PnnZGqrnPRhkOEOJbNUlE+dD4ckLeIe6NPxlS/7U+w== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + jpeg-js "0.4.2" + + "@jimp/plugin-blit@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-blit/-/plugin-blit-0.16.1.tgz#09ea919f9d326de3b9c2826fe4155da37dde8edb" + integrity sha512-fKFNARm32RoLSokJ8WZXHHH2CGzz6ire2n1Jh6u+XQLhk9TweT1DcLHIXwQMh8oR12KgjbgsMGvrMVlVknmOAg== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + + "@jimp/plugin-blur@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-blur/-/plugin-blur-0.16.1.tgz#e614fa002797dcd662e705d4cea376e7db968bf5" + integrity sha512-1WhuLGGj9MypFKRcPvmW45ht7nXkOKu+lg3n2VBzIB7r4kKNVchuI59bXaCYQumOLEqVK7JdB4glaDAbCQCLyw== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + + "@jimp/plugin-circle@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-circle/-/plugin-circle-0.16.1.tgz#20e3194a67ca29740aba2630fd4d0a89afa27491" + integrity sha512-JK7yi1CIU7/XL8hdahjcbGA3V7c+F+Iw+mhMQhLEi7Q0tCnZ69YJBTamMiNg3fWPVfMuvWJJKOBRVpwNTuaZRg== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + + "@jimp/plugin-color@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-color/-/plugin-color-0.16.1.tgz#0f298ba74dee818b663834cd80d53e56f3755233" + integrity sha512-9yQttBAO5SEFj7S6nJK54f+1BnuBG4c28q+iyzm1JjtnehjqMg6Ljw4gCSDCvoCQ3jBSYHN66pmwTV74SU1B7A== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + tinycolor2 "^1.4.1" + + "@jimp/plugin-contain@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-contain/-/plugin-contain-0.16.1.tgz#3c5f5c495fd9bb08a970739d83694934f58123f2" + integrity sha512-44F3dUIjBDHN+Ym/vEfg+jtjMjAqd2uw9nssN67/n4FdpuZUVs7E7wadKY1RRNuJO+WgcD5aDQcsvurXMETQTg== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + + "@jimp/plugin-cover@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-cover/-/plugin-cover-0.16.1.tgz#0e8caec16a40abe15b1b32e5383a603a3306dc41" + integrity sha512-YztWCIldBAVo0zxcQXR+a/uk3/TtYnpKU2CanOPJ7baIuDlWPsG+YE4xTsswZZc12H9Kl7CiziEbDtvF9kwA/Q== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + + "@jimp/plugin-crop@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-crop/-/plugin-crop-0.16.1.tgz#b362497c873043fe47ba881ab08604bf7226f50f" + integrity sha512-UQdva9oQzCVadkyo3T5Tv2CUZbf0klm2cD4cWMlASuTOYgaGaFHhT9st+kmfvXjKL8q3STkBu/zUPV6PbuV3ew== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + + "@jimp/plugin-displace@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-displace/-/plugin-displace-0.16.1.tgz#4dd9db518c3e78de9d723f86a234bf98922afe8d" + integrity sha512-iVAWuz2+G6Heu8gVZksUz+4hQYpR4R0R/RtBzpWEl8ItBe7O6QjORAkhxzg+WdYLL2A/Yd4ekTpvK0/qW8hTVw== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + + "@jimp/plugin-dither@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-dither/-/plugin-dither-0.16.1.tgz#b47de2c0bb09608bed228b41c3cd01a85ec2d45b" + integrity sha512-tADKVd+HDC9EhJRUDwMvzBXPz4GLoU6s5P7xkVq46tskExYSptgj5713J5Thj3NMgH9Rsqu22jNg1H/7tr3V9Q== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + + "@jimp/plugin-fisheye@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-fisheye/-/plugin-fisheye-0.16.1.tgz#f625047b6cdbe1b83b89e9030fd025ab19cdb1a4" + integrity sha512-BWHnc5hVobviTyIRHhIy9VxI1ACf4CeSuCfURB6JZm87YuyvgQh5aX5UDKtOz/3haMHXBLP61ZBxlNpMD8CG4A== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + + "@jimp/plugin-flip@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-flip/-/plugin-flip-0.16.1.tgz#7a99ea22bde802641017ed0f2615870c144329bb" + integrity sha512-KdxTf0zErfZ8DyHkImDTnQBuHby+a5YFdoKI/G3GpBl3qxLBvC+PWkS2F/iN3H7wszP7/TKxTEvWL927pypT0w== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + + "@jimp/plugin-gaussian@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-gaussian/-/plugin-gaussian-0.16.1.tgz#0845e314085ccd52e34fad9a83949bc0d81a68e8" + integrity sha512-u9n4wjskh3N1mSqketbL6tVcLU2S5TEaFPR40K6TDv4phPLZALi1Of7reUmYpVm8mBDHt1I6kGhuCJiWvzfGyg== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + + "@jimp/plugin-invert@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-invert/-/plugin-invert-0.16.1.tgz#7e6f5a15707256f3778d06921675bbcf18545c97" + integrity sha512-2DKuyVXANH8WDpW9NG+PYFbehzJfweZszFYyxcaewaPLN0GxvxVLOGOPP1NuUTcHkOdMFbE0nHDuB7f+sYF/2w== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + + "@jimp/plugin-mask@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-mask/-/plugin-mask-0.16.1.tgz#e7f2460e05c3cda7af5e76f33ccb0579f66f90df" + integrity sha512-snfiqHlVuj4bSFS0v96vo2PpqCDMe4JB+O++sMo5jF5mvGcGL6AIeLo8cYqPNpdO6BZpBJ8MY5El0Veckhr39Q== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + + "@jimp/plugin-normalize@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-normalize/-/plugin-normalize-0.16.1.tgz#032dfd88eefbc4dedc8b1b2d243832e4f3af30c8" + integrity sha512-dOQfIOvGLKDKXPU8xXWzaUeB0nvkosHw6Xg1WhS1Z5Q0PazByhaxOQkSKgUryNN/H+X7UdbDvlyh/yHf3ITRaw== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + + "@jimp/plugin-print@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-print/-/plugin-print-0.16.1.tgz#66b803563f9d109825970714466e6ab9ae639ff6" + integrity sha512-ceWgYN40jbN4cWRxixym+csyVymvrryuKBQ+zoIvN5iE6OyS+2d7Mn4zlNgumSczb9GGyZZESIgVcBDA1ezq0Q== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + load-bmfont "^1.4.0" + + "@jimp/plugin-resize@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-resize/-/plugin-resize-0.16.1.tgz#65e39d848ed13ba2d6c6faf81d5d590396571d10" + integrity sha512-u4JBLdRI7dargC04p2Ha24kofQBk3vhaf0q8FwSYgnCRwxfvh2RxvhJZk9H7Q91JZp6wgjz/SjvEAYjGCEgAwQ== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + + "@jimp/plugin-rotate@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-rotate/-/plugin-rotate-0.16.1.tgz#53fb5d51a4b3d05af9c91c2a8fffe5d7a1a47c8c" + integrity sha512-ZUU415gDQ0VjYutmVgAYYxC9Og9ixu2jAGMCU54mSMfuIlmohYfwARQmI7h4QB84M76c9hVLdONWjuo+rip/zg== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + + "@jimp/plugin-scale@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-scale/-/plugin-scale-0.16.1.tgz#89f6ba59feed3429847ed226aebda33a240cc647" + integrity sha512-jM2QlgThIDIc4rcyughD5O7sOYezxdafg/2Xtd1csfK3z6fba3asxDwthqPZAgitrLgiKBDp6XfzC07Y/CefUw== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + + "@jimp/plugin-shadow@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-shadow/-/plugin-shadow-0.16.1.tgz#a7af892a740febf41211e10a5467c3c5c521a04c" + integrity sha512-MeD2Is17oKzXLnsphAa1sDstTu6nxscugxAEk3ji0GV1FohCvpHBcec0nAq6/czg4WzqfDts+fcPfC79qWmqrA== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + + "@jimp/plugin-threshold@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugin-threshold/-/plugin-threshold-0.16.1.tgz#34f3078f9965145b7ae26c53a32ad74b1195bbf5" + integrity sha512-iGW8U/wiCSR0+6syrPioVGoSzQFt4Z91SsCRbgNKTAk7D+XQv6OI78jvvYg4o0c2FOlwGhqz147HZV5utoSLxA== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + + "@jimp/plugins@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/plugins/-/plugins-0.16.1.tgz#9f08544c97226d6460a16ced79f57e85bec3257b" + integrity sha512-c+lCqa25b+4q6mJZSetlxhMoYuiltyS+ValLzdwK/47+aYsq+kcJNl+TuxIEKf59yr9+5rkbpsPkZHLF/V7FFA== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/plugin-blit" "^0.16.1" + "@jimp/plugin-blur" "^0.16.1" + "@jimp/plugin-circle" "^0.16.1" + "@jimp/plugin-color" "^0.16.1" + "@jimp/plugin-contain" "^0.16.1" + "@jimp/plugin-cover" "^0.16.1" + "@jimp/plugin-crop" "^0.16.1" + "@jimp/plugin-displace" "^0.16.1" + "@jimp/plugin-dither" "^0.16.1" + "@jimp/plugin-fisheye" "^0.16.1" + "@jimp/plugin-flip" "^0.16.1" + "@jimp/plugin-gaussian" "^0.16.1" + "@jimp/plugin-invert" "^0.16.1" + "@jimp/plugin-mask" "^0.16.1" + "@jimp/plugin-normalize" "^0.16.1" + "@jimp/plugin-print" "^0.16.1" + "@jimp/plugin-resize" "^0.16.1" + "@jimp/plugin-rotate" "^0.16.1" + "@jimp/plugin-scale" "^0.16.1" + "@jimp/plugin-shadow" "^0.16.1" + "@jimp/plugin-threshold" "^0.16.1" + timm "^1.6.1" + + "@jimp/png@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/png/-/png-0.16.1.tgz#f24cfc31529900b13a2dd9d4fdb4460c1e4d814e" + integrity sha512-iyWoCxEBTW0OUWWn6SveD4LePW89kO7ZOy5sCfYeDM/oTPLpR8iMIGvZpZUz1b8kvzFr27vPst4E5rJhGjwsdw== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/utils" "^0.16.1" + pngjs "^3.3.3" + + "@jimp/tiff@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/tiff/-/tiff-0.16.1.tgz#0e8756695687d7574b6bc73efab0acd4260b7a12" + integrity sha512-3K3+xpJS79RmSkAvFMgqY5dhSB+/sxhwTFA9f4AVHUK0oKW+u6r52Z1L0tMXHnpbAdR9EJ+xaAl2D4x19XShkQ== + dependencies: + "@babel/runtime" "^7.7.2" + utif "^2.0.1" + + "@jimp/types@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/types/-/types-0.16.1.tgz#0dbab37b3202315c91010f16c31766d35a2322cc" + integrity sha512-g1w/+NfWqiVW4CaXSJyD28JQqZtm2eyKMWPhBBDCJN9nLCN12/Az0WFF3JUAktzdsEC2KRN2AqB1a2oMZBNgSQ== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/bmp" "^0.16.1" + "@jimp/gif" "^0.16.1" + "@jimp/jpeg" "^0.16.1" + "@jimp/png" "^0.16.1" + "@jimp/tiff" "^0.16.1" + timm "^1.6.1" + + "@jimp/utils@^0.16.1": + version "0.16.1" + resolved "https://registry.yarnpkg.com/@jimp/utils/-/utils-0.16.1.tgz#2f51e6f14ff8307c4aa83d5e1a277da14a9fe3f7" + integrity sha512-8fULQjB0x4LzUSiSYG6ZtQl355sZjxbv8r9PPAuYHzS9sGiSHJQavNqK/nKnpDsVkU88/vRGcE7t3nMU0dEnVw== + dependencies: + "@babel/runtime" "^7.7.2" + regenerator-runtime "^0.13.3" + + "@jitsu/sdk-js@^2.2.4": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@jitsu/sdk-js/-/sdk-js-2.4.0.tgz#fccfe5821766e7b623e89386ef0d359d797031b4" + integrity sha512-2BO6NYJOLdKy3jt5fCAQPXukK+esFTRD1g3D1vqLPq7iHgCwOJgG1V9j02ILeTEFlaFKeu59B3FM81orhbGymA== + + "@jridgewell/resolve-uri@^3.0.3": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c" + integrity sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew== + + "@jridgewell/sourcemap-codec@^1.4.10": + version "1.4.11" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec" + integrity sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg== + + "@jridgewell/trace-mapping@^0.3.0": + version "0.3.4" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz#f6a0832dffd5b8a6aaa633b7d9f8e8e94c83a0c3" + integrity sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + + "@mdx-js/loader@^2.0.0-next.9": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@mdx-js/loader/-/loader-2.0.0.tgz#4ff3278d341e7a15ecf87c4623a8ecd533cb3dbc" + integrity sha512-gPuzQQ19K9OUkgRVMUMRu8lYXgJPwSQaHcc6olvRxbdUMms4mtn6so3v4v8J+f58bAk0R98IzBbkvBenAOZu7g== + dependencies: + "@mdx-js/mdx" "^2.0.0" + source-map "^0.7.0" + + "@mdx-js/mdx@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@mdx-js/mdx/-/mdx-2.0.0.tgz#7f270df1e77c46f8338fc32089016b3ea383d023" + integrity sha512-Q/Zv+gdm80qcxpmL/Dtd/b9+UyZjjJUCQeZyywLAQqre648hRYgeGNPu7Bl2hB7M8/WBLXpabQEKW3dmGdDTDQ== + dependencies: + "@types/estree-jsx" "^0.0.1" + "@types/mdx" "^2.0.0" + astring "^1.6.0" + estree-util-build-jsx "^2.0.0" + estree-util-is-identifier-name "^2.0.0" + estree-walker "^3.0.0" + hast-util-to-estree "^2.0.0" + markdown-extensions "^1.0.0" + periscopic "^3.0.0" + remark-mdx "^2.0.0" + remark-parse "^10.0.0" + remark-rehype "^10.0.0" + unified "^10.0.0" + unist-util-position-from-estree "^1.0.0" + unist-util-stringify-position "^3.0.0" + unist-util-visit "^4.0.0" + vfile "^5.0.0" + + "@mdx-js/react@^1.6.16": + version "1.6.22" + resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-1.6.22.tgz#ae09b4744fddc74714ee9f9d6f17a66e77c43573" + integrity sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg== + + "@metamask/object-multiplex@^1.1.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@metamask/object-multiplex/-/object-multiplex-1.2.0.tgz#38fc15c142f61939391e1b9a8eed679696c7e4f4" + integrity sha512-hksV602d3NWE2Q30Mf2Np1WfVKaGqfJRy9vpHAmelbaD0OkDt06/0KQkRR6UVYdMbTbkuEu8xN5JDUU80inGwQ== + dependencies: + end-of-stream "^1.4.4" + once "^1.4.0" + readable-stream "^2.3.3" + + "@metamask/providers@^8.1.1": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@metamask/providers/-/providers-8.1.1.tgz#7b0dbb54700c949aafba24c9b98e6f4e9d81f325" + integrity sha512-CG1sAuD6Mp4MZ5U90anf1FT0moDbStGXT+80TQFYXJbBeTQjhp321WgC/F2IgIJ3mFqOiByC3MQHLuunEVMQOA== + dependencies: + "@metamask/object-multiplex" "^1.1.0" + "@metamask/safe-event-emitter" "^2.0.0" + "@types/chrome" "^0.0.136" + detect-browser "^5.2.0" + eth-rpc-errors "^4.0.2" + extension-port-stream "^2.0.1" + fast-deep-equal "^2.0.1" + is-stream "^2.0.0" + json-rpc-engine "^6.1.0" + json-rpc-middleware-stream "^3.0.0" + pump "^3.0.0" + webextension-polyfill-ts "^0.25.0" + + "@metamask/safe-event-emitter@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz#af577b477c683fad17c619a78208cede06f9605c" + integrity sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q== + + "@microsoft/microsoft-graph-types-beta@0.15.0-preview": + version "0.15.0-preview" + resolved "https://registry.yarnpkg.com/@microsoft/microsoft-graph-types-beta/-/microsoft-graph-types-beta-0.15.0-preview.tgz#fed0a99be4e1151d566cf063f024913fb48640cd" + integrity sha512-M0zC4t3pmkDz7Qsjx/iZcS+zRuckzsbHESvT9qjLFv64RUgkRmDdmhcvPMiUqUzw/h3YxfYAq9MU+XWjROk/dg== + + "@next/bundle-analyzer@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/bundle-analyzer/-/bundle-analyzer-12.1.0.tgz#9f6d6cda2a26220c936805be407243e22790f4b7" + integrity sha512-pOtWRWaKQXff8A80Ex3E67EH8XuERHxBPn8cQgKzfhRKQwoTEareHe2nWJO1uXTQm6m7ZRhmhb4+uwp+UvmITQ== + dependencies: + webpack-bundle-analyzer "4.3.0" + "@next/env@12.1.0": version "12.1.0" resolved "https://registry.yarnpkg.com/@next/env/-/env-12.1.0.tgz#73713399399b34aa5a01771fb73272b55b22c314" integrity sha512-nrIgY6t17FQ9xxwH3jj0a6EOiQ/WDHUos35Hghtr+SWN/ntHIQ7UpuvSi0vaLzZVHQWaDupKI+liO5vANcDeTQ== + "@next/eslint-plugin-next@12.1.0": + version "12.1.0" + resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-12.1.0.tgz#32586a11378b3ffa5a93ac40a3c44ad99d70e95a" + integrity sha512-WFiyvSM2G5cQmh32t/SiQuJ+I2O+FHVlK/RFw5b1565O2kEM/36EXncjt88Pa+X5oSc+1SS+tWxowWJd1lqI+g== + dependencies: + glob "7.1.7" + "@next/swc-android-arm64@12.1.0": version "12.1.0" resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.1.0.tgz#865ba3a9afc204ff2bdeea49dd64d58705007a39" @@ -125,21 +2484,8644 @@ Lockfile: resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.0.tgz#d27e7e76c87a460a4da99c5bfdb1618dcd6cd064" integrity sha512-aBvcbMwuanDH4EMrL2TthNJy+4nP59Bimn8egqv6GHMVj0a44cU6Au4PjOhLNqEh9l+IpRGBqMTzec94UdC5xg== - "@types/node@^17.0.21": + "@node-redis/client@^1.0.1": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@node-redis/client/-/client-1.0.4.tgz#fe185750df3bcc07524f63fe8dbc8d14d22d6cbb" + integrity sha512-IM/NRAqg7MvNC3bIRQipXGrEarunrdgvrbAzsd3ty93LSHi/M+ybQulOERQi8a3M+P5BL8HenwXjiIoKm6ml2g== + dependencies: + cluster-key-slot "1.1.0" + generic-pool "3.8.2" + redis-parser "3.0.0" + yallist "4.0.0" + + "@node-redis/json@^1.0.1": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@node-redis/json/-/json-1.0.2.tgz#8ad2d0f026698dc1a4238cc3d1eb099a3bee5ab8" + integrity sha512-qVRgn8WfG46QQ08CghSbY4VhHFgaTY71WjpwRBGEuqGPfWwfRcIf3OqSpR7Q/45X+v3xd8mvYjywqh0wqJ8T+g== + + "@node-redis/search@^1.0.1": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@node-redis/search/-/search-1.0.3.tgz#7c3d026bf994caf82019fd0c3924cfc09f041a29" + integrity sha512-rsrzkGWI84di/uYtEctS/4qLusWt0DESx/psjfB0TFpORDhe7JfC0h8ary+eHulTksumor244bXLRSqQXbFJmw== + + "@node-redis/time-series@^1.0.0": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@node-redis/time-series/-/time-series-1.0.2.tgz#5dd3638374edd85ebe0aa6b0e87addc88fb9df69" + integrity sha512-HGQ8YooJ8Mx7l28tD7XjtB3ImLEjlUxG1wC1PAjxu6hPJqjPshUZxAICzDqDjtIbhDTf48WXXUcx8TQJB1XTKA== + + "@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + + "@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + + "@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + + "@otplib/core@^12.0.1": + version "12.0.1" + resolved "https://registry.yarnpkg.com/@otplib/core/-/core-12.0.1.tgz#73720a8cedce211fe5b3f683cd5a9c098eaf0f8d" + integrity sha512-4sGntwbA/AC+SbPhbsziRiD+jNDdIzsZ3JUyfZwjtKyc/wufl1pnSIaG4Uqx8ymPagujub0o92kgBnB89cuAMA== + + "@otplib/plugin-crypto@^12.0.1": + version "12.0.1" + resolved "https://registry.yarnpkg.com/@otplib/plugin-crypto/-/plugin-crypto-12.0.1.tgz#2b42c624227f4f9303c1c041fca399eddcbae25e" + integrity sha512-qPuhN3QrT7ZZLcLCyKOSNhuijUi9G5guMRVrxq63r9YNOxxQjPm59gVxLM+7xGnHnM6cimY57tuKsjK7y9LM1g== + dependencies: + "@otplib/core" "^12.0.1" + + "@otplib/plugin-thirty-two@^12.0.1": + version "12.0.1" + resolved "https://registry.yarnpkg.com/@otplib/plugin-thirty-two/-/plugin-thirty-two-12.0.1.tgz#5cc9b56e6e89f2a1fe4a2b38900ca4e11c87aa9e" + integrity sha512-MtT+uqRso909UkbrrYpJ6XFjj9D+x2Py7KjTO9JDPhL0bJUYVu5kFP4TFZW4NFAywrAtFRxOVY261u0qwb93gA== + dependencies: + "@otplib/core" "^12.0.1" + thirty-two "^1.0.2" + + "@otplib/preset-default@^12.0.1": + version "12.0.1" + resolved "https://registry.yarnpkg.com/@otplib/preset-default/-/preset-default-12.0.1.tgz#cb596553c08251e71b187ada4a2246ad2a3165ba" + integrity sha512-xf1v9oOJRyXfluBhMdpOkr+bsE+Irt+0D5uHtvg6x1eosfmHCsCC6ej/m7FXiWqdo0+ZUI6xSKDhJwc8yfiOPQ== + dependencies: + "@otplib/core" "^12.0.1" + "@otplib/plugin-crypto" "^12.0.1" + "@otplib/plugin-thirty-two" "^12.0.1" + + "@otplib/preset-v11@^12.0.1": + version "12.0.1" + resolved "https://registry.yarnpkg.com/@otplib/preset-v11/-/preset-v11-12.0.1.tgz#4c7266712e7230500b421ba89252963c838fc96d" + integrity sha512-9hSetMI7ECqbFiKICrNa4w70deTUfArtwXykPUvSHWOdzOlfa9ajglu7mNCntlvxycTiOAXkQGwjQCzzDEMRMg== + dependencies: + "@otplib/core" "^12.0.1" + "@otplib/plugin-crypto" "^12.0.1" + "@otplib/plugin-thirty-two" "^12.0.1" + + "@panva/hkdf@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@panva/hkdf/-/hkdf-1.0.1.tgz#ed0da773bd5f794d0603f5a5b5cee6d2354e5660" + integrity sha512-mMyQ9vjpuFqePkfe5bZVIf/H3Dmk6wA8Kjxff9RcO4kqzJo+Ek9pGKwZHpeMr7Eku0QhLXMCd7fNCSnEnRMubg== + + "@peculiar/asn1-cms@^2.0.44": + version "2.0.44" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-cms/-/asn1-cms-2.0.44.tgz#ebe8bc1490d5301f9af4c84d1e23526994590efa" + integrity sha512-CzjCz8VZqG2jqRI/4YKCk3D9WS8V9cezt0tftWT5zmYxeZvAWOmtInj013zSooHEn1Oi65rzdDZ1m+wgascmiw== + dependencies: + "@peculiar/asn1-schema" "^2.0.44" + "@peculiar/asn1-x509" "^2.0.44" + "@peculiar/asn1-x509-attr" "^2.0.44" + asn1js "^2.1.1" + tslib "^2.3.0" + + "@peculiar/asn1-csr@^2.0.44": + version "2.0.44" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-csr/-/asn1-csr-2.0.44.tgz#fd7df64036840a536dda71d474bdcaf4eb906907" + integrity sha512-9FG9ySzLyYIlk/W3o/mpE+ukn/XMokv+BysqyhNGifUet362slp+uF4XliKGLt53TO53uYCsQimVyTK4vwe/yg== + dependencies: + "@peculiar/asn1-schema" "^2.0.44" + "@peculiar/asn1-x509" "^2.0.44" + asn1js "^2.1.1" + tslib "^2.3.0" + + "@peculiar/asn1-ecc@^2.0.44": + version "2.0.44" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-ecc/-/asn1-ecc-2.0.44.tgz#11f45324efb01419aa8fb779a2ea3c8dc712094b" + integrity sha512-GvfifE5xCZjEz9EsOl9gqTVgex9m7ATLloTaSE3Go+iG8bc7C/VDK8lOnFb3/UsCqfI46Gwh4Q3RQCP2JB3GDQ== + dependencies: + "@peculiar/asn1-schema" "^2.0.44" + "@peculiar/asn1-x509" "^2.0.44" + asn1js "^2.1.1" + tslib "^2.3.0" + + "@peculiar/asn1-pfx@^2.0.44": + version "2.0.44" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-pfx/-/asn1-pfx-2.0.44.tgz#fd0b4b61b4427687305b2d2a94f0f2bb8d1b96b5" + integrity sha512-rVsGoZWMtensS9+AEtU97cImHXEu+Oi6K31/EzzzdqfUx/aF49RYCVKOyuCjUg5cwIOE93WsNm0hQFYB2pYwVQ== + dependencies: + "@peculiar/asn1-cms" "^2.0.44" + "@peculiar/asn1-pkcs8" "^2.0.44" + "@peculiar/asn1-rsa" "^2.0.44" + "@peculiar/asn1-schema" "^2.0.44" + asn1js "^2.1.1" + tslib "^2.3.0" + + "@peculiar/asn1-pkcs8@^2.0.44": + version "2.0.44" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.0.44.tgz#62b28efcd59c495c4c3a46914859584a20033f8c" + integrity sha512-cs/zGEv/6Jxx14tZ6NS82PNJFMCb4aFOiAFzv+I1I1ud7o5wyDGOOAIiIs4vI+Z6xtkoSyF+hWH51kRutdFV4A== + dependencies: + "@peculiar/asn1-schema" "^2.0.44" + "@peculiar/asn1-x509" "^2.0.44" + asn1js "^2.1.1" + tslib "^2.3.0" + + "@peculiar/asn1-pkcs9@^2.0.44": + version "2.0.44" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.0.44.tgz#9153555be59ea6518c77d7b28989fc4cc81ea338" + integrity sha512-b54VRWsM5NdIOlSuBbfBeximwVQIHcUoUdx10mHM6QuvZlXKciVP/nkerxg0ytQzC5BvPbohfYuiq46gYCPZSA== + dependencies: + "@peculiar/asn1-cms" "^2.0.44" + "@peculiar/asn1-pfx" "^2.0.44" + "@peculiar/asn1-pkcs8" "^2.0.44" + "@peculiar/asn1-schema" "^2.0.44" + "@peculiar/asn1-x509" "^2.0.44" + "@peculiar/asn1-x509-attr" "^2.0.44" + asn1js "^2.1.1" + tslib "^2.3.0" + + "@peculiar/asn1-rsa@^2.0.44": + version "2.0.44" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-rsa/-/asn1-rsa-2.0.44.tgz#1a1455d129905c1378f8056af0d25429a34054fa" + integrity sha512-DYfo33Yl3y4Bu8V0RrAhKBZJDy1ESEGQzKVl7DxCUJna164/U/JB767W9ze0Vlq7quTawUJLMX3RRfesEFGigA== + dependencies: + "@peculiar/asn1-schema" "^2.0.44" + "@peculiar/asn1-x509" "^2.0.44" + asn1js "^2.1.1" + tslib "^2.3.0" + + "@peculiar/asn1-schema@^2.0.44": + version "2.0.44" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.0.44.tgz#dcb1b8f84a4dd5f07f674028beade9c3de43cc06" + integrity sha512-uaCnjQ9A9WwQSMuDJcNOCYEPXTahgKbFMvI7eMOMd8lXgx0J1eU7F3BoMsK5PFxa3dVUxjSQbaOjfgGoeHGgoQ== + dependencies: + "@types/asn1js" "^2.0.2" + asn1js "^2.1.1" + pvtsutils "^1.2.1" + tslib "^2.3.0" + + "@peculiar/asn1-x509-attr@^2.0.44": + version "2.0.44" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.0.44.tgz#b3146aa6f57c531858114ef1ed229cd41cf610dc" + integrity sha512-mYyf1fMT1JVrmPInjqVC3O2Vm3LBm7sd75Mg2hKB0A/zPKIYZ5WRz396lliucHagg17PalMjDOxtIQFOqs1WGg== + dependencies: + "@peculiar/asn1-schema" "^2.0.44" + "@peculiar/asn1-x509" "^2.0.44" + asn1js "^2.1.1" + tslib "^2.3.0" + + "@peculiar/asn1-x509@^2.0.44": + version "2.0.44" + resolved "https://registry.yarnpkg.com/@peculiar/asn1-x509/-/asn1-x509-2.0.44.tgz#0798819ffb9d8380dedbd98f6cd069952e9ec130" + integrity sha512-jKGy+7Ew1PADjzInblBaQWVdh9kTiy49lkTko/MiYg5lHyCi/N9xPtQCuincpY1UeNPwXaeoT2DXRJOuN6U/8A== + dependencies: + "@peculiar/asn1-schema" "^2.0.44" + asn1js "^2.1.1" + ipaddr.js "^2.0.1" + pvtsutils "^1.2.1" + tslib "^2.3.0" + + "@peculiar/json-schema@^1.1.12": + version "1.1.12" + resolved "https://registry.yarnpkg.com/@peculiar/json-schema/-/json-schema-1.1.12.tgz#fe61e85259e3b5ba5ad566cb62ca75b3d3cd5339" + integrity sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w== + dependencies: + tslib "^2.0.0" + + "@peculiar/webcrypto@1.2.3": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@peculiar/webcrypto/-/webcrypto-1.2.3.tgz#79268ef0a8068bed2a40fc33bc68b4d3546fe2cc" + integrity sha512-q7wDfZy3k/tpnsYB23/MyyDkjn6IdHh8w+xwoVMS5cu6CjVoFzngXDZEOOuSE4zus2yO6ciQhhHxd4XkLpwVnQ== + dependencies: + "@peculiar/asn1-schema" "^2.0.44" + "@peculiar/json-schema" "^1.1.12" + pvtsutils "^1.2.1" + tslib "^2.3.1" + webcrypto-core "^1.4.0" + + "@peculiar/x509@1.6.1": + version "1.6.1" + resolved "https://registry.yarnpkg.com/@peculiar/x509/-/x509-1.6.1.tgz#cc33807ab481824c69145e884cb40012aec501b0" + integrity sha512-C4oxpCuYasfjuhy6QRFJhs0R6gyeQSRsB7MsT6JkO3qaFi4b75mm8hNEKa+sIJPtTjXCC94tW9rHx1hw5dOvnQ== + dependencies: + "@peculiar/asn1-cms" "^2.0.44" + "@peculiar/asn1-csr" "^2.0.44" + "@peculiar/asn1-ecc" "^2.0.44" + "@peculiar/asn1-pkcs9" "^2.0.44" + "@peculiar/asn1-rsa" "^2.0.44" + "@peculiar/asn1-schema" "^2.0.44" + "@peculiar/asn1-x509" "^2.0.44" + pvtsutils "^1.2.1" + reflect-metadata "^0.1.13" + tslib "^2.3.1" + tsyringe "^4.6.0" + + "@playwright/test@^1.18.1": + version "1.19.2" + resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.19.2.tgz#429d1aa70f5e4cd521cdc8a5d9861ae4fcda3f7c" + integrity sha512-5oCmlYHjtOL662OxSkZBYGnoHWIQui7b4YHWNeSCYwhQjmjVcV5njRc8oBZlU8IwJgG7ZH2yhDk1haU96ygbWw== + dependencies: + "@babel/code-frame" "7.16.7" + "@babel/core" "7.16.12" + "@babel/plugin-proposal-class-properties" "7.16.7" + "@babel/plugin-proposal-dynamic-import" "7.16.7" + "@babel/plugin-proposal-export-namespace-from" "7.16.7" + "@babel/plugin-proposal-logical-assignment-operators" "7.16.7" + "@babel/plugin-proposal-nullish-coalescing-operator" "7.16.7" + "@babel/plugin-proposal-numeric-separator" "7.16.7" + "@babel/plugin-proposal-optional-chaining" "7.16.7" + "@babel/plugin-proposal-private-methods" "7.16.11" + "@babel/plugin-proposal-private-property-in-object" "7.16.7" + "@babel/plugin-syntax-async-generators" "7.8.4" + "@babel/plugin-syntax-json-strings" "7.8.3" + "@babel/plugin-syntax-object-rest-spread" "7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "7.8.3" + "@babel/plugin-transform-modules-commonjs" "7.16.8" + "@babel/plugin-transform-react-jsx" "7.16.7" + "@babel/preset-typescript" "7.16.7" + babel-plugin-module-resolver "4.1.0" + colors "1.4.0" + commander "8.3.0" + debug "4.3.3" + expect "27.2.5" + jest-matcher-utils "27.2.5" + jpeg-js "0.4.3" + json5 "2.2.0" + mime "3.0.0" + minimatch "3.0.4" + ms "2.1.3" + open "8.4.0" + pirates "4.0.4" + pixelmatch "5.2.1" + playwright-core "1.19.2" + pngjs "6.0.0" + rimraf "3.0.2" + source-map-support "0.4.18" + stack-utils "2.0.5" + yazl "2.5.1" + + "@polka/url@^1.0.0-next.20": + version "1.0.0-next.21" + resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" + integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== + + "@prisma/client@3.10.0": + version "3.10.0" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.10.0.tgz#4782fe6f1b0e43c2a11a75ad4bb1098599d1dfb1" + integrity sha512-6P4sV7WFuODSfSoSEzCH1qfmWMrCUBk1LIIuTbQf6m1LI/IOpLN4lnqGDmgiBGprEzuWobnGLfe9YsXLn0inrg== + dependencies: + "@prisma/engines-version" "3.10.0-50.73e60b76d394f8d37d8ebd1f8918c79029f0db86" + + "@prisma/debug@3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-3.8.1.tgz#3c6717d6e0501651709714774ea6d90127c6a2d3" + integrity sha512-ft4VPTYME1UBJ7trfrBuF2w9jX1ipDy786T9fAEskNGb+y26gPDqz5fiEWc2kgHNeVdz/qTI/V3wXILRyEcgxQ== + dependencies: + "@types/debug" "4.1.7" + ms "2.1.3" + strip-ansi "6.0.1" + + "@prisma/engines-version@3.10.0-50.73e60b76d394f8d37d8ebd1f8918c79029f0db86": + version "3.10.0-50.73e60b76d394f8d37d8ebd1f8918c79029f0db86" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.10.0-50.73e60b76d394f8d37d8ebd1f8918c79029f0db86.tgz#82750856fa637dd89b8f095d2dcc6ac0631231c6" + integrity sha512-cVYs5gyQH/qyut24hUvDznCfPrWiNMKNfPb9WmEoiU6ihlkscIbCfkmuKTtspVLWRdl0LqjYEC7vfnPv17HWhw== + + "@prisma/engines@3.10.0-50.73e60b76d394f8d37d8ebd1f8918c79029f0db86": + version "3.10.0-50.73e60b76d394f8d37d8ebd1f8918c79029f0db86" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.10.0-50.73e60b76d394f8d37d8ebd1f8918c79029f0db86.tgz#2964113729a78b8b21e186b5592affd1fde73c16" + integrity sha512-LjRssaWu9w2SrXitofnutRIyURI7l0veQYIALz7uY4shygM9nMcK3omXcObRm7TAcw3Z+9ytfK1B+ySOsOesxQ== + + "@prisma/generator-helper@~3.8.1": + version "3.8.1" + resolved "https://registry.yarnpkg.com/@prisma/generator-helper/-/generator-helper-3.8.1.tgz#eb1dcc8382faa17c784a9d0e0d79fd207a222aa4" + integrity sha512-3zSy+XTEjmjLj6NO+/YPN1Cu7or3xA11TOoOnLRJ9G4pTT67RJXjK0L9Xy5n+3I0Xlb7xrWCgo8MvQQLMWzxPA== + dependencies: + "@prisma/debug" "3.8.1" + "@types/cross-spawn" "6.0.2" + chalk "4.1.2" + cross-spawn "7.0.3" + + "@radix-ui/number@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-0.1.0.tgz#73ad13d5cc5f75fa5e147d72e5d5d5e50d688256" + integrity sha512-rpf6QiOWLHAkM4FEMYu9i+5Jr8cKT893+R4mPpcdsy4LD7omr9JfdOqj/h/xPA5+EcVrpMMlU6rrRYpUB5UI8g== + dependencies: + "@babel/runtime" "^7.13.10" + + "@radix-ui/popper@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/popper/-/popper-0.1.0.tgz#c387a38f31b7799e1ea0d2bb1ca0c91c2931b063" + integrity sha512-uzYeElL3w7SeNMuQpXiFlBhTT+JyaNMCwDfjKkrzugEcYrf5n52PHqncNdQPUtR42hJh8V9FsqyEDbDxkeNjJQ== + dependencies: + "@babel/runtime" "^7.13.10" + csstype "^3.0.4" + + "@radix-ui/primitive@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-0.1.0.tgz#6206b97d379994f0d1929809db035733b337e543" + integrity sha512-tqxZKybwN5Fa3VzZry4G6mXAAb9aAqKmPtnVbZpL0vsBwvOHTBwsjHVPXylocYLwEtBY9SCe665bYnNB515uoA== + dependencies: + "@babel/runtime" "^7.13.10" + + "@radix-ui/react-arrow@0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-0.1.4.tgz#a871448a418cd3507d83840fdd47558cb961672b" + integrity sha512-BB6XzAb7Ml7+wwpFdYVtZpK1BlMgqyafSQNGzhIpSZ4uXvXOHPlR5GP8M449JkeQzgQjv9Mp1AsJxFC0KuOtuA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "0.1.4" + + "@radix-ui/react-avatar@^0.1.0": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-avatar/-/react-avatar-0.1.4.tgz#36210e629e0eecde44027195c82d2a4101cbd7e9" + integrity sha512-RTs3KQTToVKJHHsn/E+vC2MyP0LnA6uMdcD7thwaCJEbI6NAvf56Y+RNJPSsGXz1o2LkD7Iy5SogsrzBwXQk6A== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-context" "0.1.1" + "@radix-ui/react-primitive" "0.1.4" + "@radix-ui/react-use-callback-ref" "0.1.0" + "@radix-ui/react-use-layout-effect" "0.1.0" + + "@radix-ui/react-collapsible@^0.1.0": + version "0.1.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-collapsible/-/react-collapsible-0.1.6.tgz#3eeadac476761b3c9b8dd91e8a32eb1a547e5a06" + integrity sha512-Gkf8VuqMc6HTLzA2AxVYnyK6aMczVLpatCjdD9Lj4wlYLXCz9KtiqZYslLMeqnQFLwLyZS0WKX/pQ8j5fioIBw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "0.1.0" + "@radix-ui/react-compose-refs" "0.1.0" + "@radix-ui/react-context" "0.1.1" + "@radix-ui/react-id" "0.1.5" + "@radix-ui/react-presence" "0.1.2" + "@radix-ui/react-primitive" "0.1.4" + "@radix-ui/react-use-controllable-state" "0.1.0" + "@radix-ui/react-use-layout-effect" "0.1.0" + + "@radix-ui/react-collection@0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-0.1.4.tgz#734061ffd5bb93e88889d49b87391a73a63824c9" + integrity sha512-3muGI15IdgaDFjOcO7xX8a35HQRBRF6LH9pS6UCeZeRmbslkVeHyJRQr2rzICBUoX7zgIA0kXyMDbpQnJGyJTA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "0.1.0" + "@radix-ui/react-context" "0.1.1" + "@radix-ui/react-primitive" "0.1.4" + "@radix-ui/react-slot" "0.1.2" + + "@radix-ui/react-compose-refs@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-0.1.0.tgz#cff6e780a0f73778b976acff2c2a5b6551caab95" + integrity sha512-eyclbh+b77k+69Dk72q3694OHrn9B3QsoIRx7ywX341U9RK1ThgQjMFZoPtmZNQTksXHLNEiefR8hGVeFyInGg== + dependencies: + "@babel/runtime" "^7.13.10" + + "@radix-ui/react-context@0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-0.1.1.tgz#06996829ea124d9a1bc1dbe3e51f33588fab0875" + integrity sha512-PkyVX1JsLBioeu0jB9WvRpDBBLtLZohVDT3BB5CTSJqActma8S8030P57mWZb4baZifMvN7KKWPAA40UmWKkQg== + dependencies: + "@babel/runtime" "^7.13.10" + + "@radix-ui/react-dialog@^0.1.0": + version "0.1.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-0.1.7.tgz#285414cf66f5bbf42bc9935314e0381abe01e7d0" + integrity sha512-jXt8srGhHBRvEr9jhEAiwwJzWCWZoGRJ030aC9ja/gkRJbZdy0iD3FwXf+Ff4RtsZyLUMHW7VUwFOlz3Ixe1Vw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "0.1.0" + "@radix-ui/react-compose-refs" "0.1.0" + "@radix-ui/react-context" "0.1.1" + "@radix-ui/react-dismissable-layer" "0.1.5" + "@radix-ui/react-focus-guards" "0.1.0" + "@radix-ui/react-focus-scope" "0.1.4" + "@radix-ui/react-id" "0.1.5" + "@radix-ui/react-portal" "0.1.4" + "@radix-ui/react-presence" "0.1.2" + "@radix-ui/react-primitive" "0.1.4" + "@radix-ui/react-slot" "0.1.2" + "@radix-ui/react-use-controllable-state" "0.1.0" + aria-hidden "^1.1.1" + react-remove-scroll "^2.4.0" + + "@radix-ui/react-dismissable-layer@0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-0.1.5.tgz#9379032351e79028d472733a5cc8ba4a0ea43314" + integrity sha512-J+fYWijkX4M4QKwf9dtu1oC0U6e6CEl8WhBp3Ad23yz2Hia0XCo6Pk/mp5CAFy4QBtQedTSkhW05AdtSOEoajQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "0.1.0" + "@radix-ui/react-compose-refs" "0.1.0" + "@radix-ui/react-primitive" "0.1.4" + "@radix-ui/react-use-body-pointer-events" "0.1.1" + "@radix-ui/react-use-callback-ref" "0.1.0" + "@radix-ui/react-use-escape-keydown" "0.1.0" + + "@radix-ui/react-dropdown-menu@^0.1.1": + version "0.1.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-0.1.6.tgz#3203229788cd57e552c9f19dcc7008e2b545919c" + integrity sha512-RZhtzjWwJ4ZBN7D8ek4Zn+ilHzYuYta9yIxFnbC0pfqMnSi67IQNONo1tuuNqtFh9SRHacPKc65zo+kBBlxtdg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "0.1.0" + "@radix-ui/react-compose-refs" "0.1.0" + "@radix-ui/react-context" "0.1.1" + "@radix-ui/react-id" "0.1.5" + "@radix-ui/react-menu" "0.1.6" + "@radix-ui/react-primitive" "0.1.4" + "@radix-ui/react-use-controllable-state" "0.1.0" + + "@radix-ui/react-focus-guards@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-0.1.0.tgz#ba3b6f902cba7826569f8edc21ff8223dece7def" + integrity sha512-kRx/swAjEfBpQ3ns7J3H4uxpXuWCqN7MpALiSDOXiyo2vkWv0L9sxvbpZeTulINuE3CGMzicVMuNc/VWXjFKOg== + dependencies: + "@babel/runtime" "^7.13.10" + + "@radix-ui/react-focus-scope@0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-0.1.4.tgz#c830724e212d42ffaaa81aee49533213d09b47df" + integrity sha512-fbA4ES3H4Wkxp+OeLhvN6SwL7mXNn/aBtUf7DRYxY9+Akrf7dRxl2ck4lgcpPsSg3zSDsEwLcY+h5cmj5yvlug== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "0.1.0" + "@radix-ui/react-primitive" "0.1.4" + "@radix-ui/react-use-callback-ref" "0.1.0" + + "@radix-ui/react-id@0.1.5", "@radix-ui/react-id@^0.1.0": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-0.1.5.tgz#010d311bedd5a2884c1e9bb6aaaa4e6cc1d1d3b8" + integrity sha512-IPc4H/63bes0IZ1GJJozSEkSWcDyhNGtKFWUpJ+XtaLyQ1X3x7Mf6fWwWhDcpqlYEP+5WtAvfqcyEsyjP+ZhBQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-layout-effect" "0.1.0" + + "@radix-ui/react-label@0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-label/-/react-label-0.1.5.tgz#12cd965bfc983e0148121d4c99fb8e27a917c45c" + integrity sha512-Au9+n4/DhvjR0IHhvZ1LPdx/OW+3CGDie30ZyCkbSHIuLp4/CV4oPPGBwJ1vY99Jog3zyQhsGww9MXj8O9Aj/A== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "0.1.0" + "@radix-ui/react-context" "0.1.1" + "@radix-ui/react-id" "0.1.5" + "@radix-ui/react-primitive" "0.1.4" + + "@radix-ui/react-menu@0.1.6": + version "0.1.6" + resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-0.1.6.tgz#7f9521a10f6a9cd819b33b33d5ed9538d79b2e75" + integrity sha512-ho3+bhpr3oAFkOBJ8VkUb1BcGoiZBB3OmcWPqa6i5RTUKrzNX/d6rauochu2xDlWjiRtpVuiAcsTVOeIC4FbYQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "0.1.0" + "@radix-ui/react-collection" "0.1.4" + "@radix-ui/react-compose-refs" "0.1.0" + "@radix-ui/react-context" "0.1.1" + "@radix-ui/react-dismissable-layer" "0.1.5" + "@radix-ui/react-focus-guards" "0.1.0" + "@radix-ui/react-focus-scope" "0.1.4" + "@radix-ui/react-id" "0.1.5" + "@radix-ui/react-popper" "0.1.4" + "@radix-ui/react-portal" "0.1.4" + "@radix-ui/react-presence" "0.1.2" + "@radix-ui/react-primitive" "0.1.4" + "@radix-ui/react-roving-focus" "0.1.5" + "@radix-ui/react-use-callback-ref" "0.1.0" + "@radix-ui/react-use-direction" "0.1.0" + aria-hidden "^1.1.1" + react-remove-scroll "^2.4.0" + + "@radix-ui/react-popper@0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-0.1.4.tgz#dfc055dcd7dfae6a2eff7a70d333141d15a5d029" + integrity sha512-18gDYof97t8UQa7zwklG1Dr8jIdj3u+rVOQLzPi9f5i1YQak/pVGkaqw8aY+iDUknKKuZniTk/7jbAJUYlKyOw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/popper" "0.1.0" + "@radix-ui/react-arrow" "0.1.4" + "@radix-ui/react-compose-refs" "0.1.0" + "@radix-ui/react-context" "0.1.1" + "@radix-ui/react-primitive" "0.1.4" + "@radix-ui/react-use-rect" "0.1.1" + "@radix-ui/react-use-size" "0.1.1" + "@radix-ui/rect" "0.1.1" + + "@radix-ui/react-portal@0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-0.1.4.tgz#17bdce3d7f1a9a0b35cb5e935ab8bc562441a7d2" + integrity sha512-MO0wRy2eYRTZ/CyOri9NANCAtAtq89DEtg90gicaTlkCfdqCLEBsLb+/q66BZQTr3xX/Vq01nnVfc/TkCqoqvw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "0.1.4" + "@radix-ui/react-use-layout-effect" "0.1.0" + + "@radix-ui/react-presence@0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-0.1.2.tgz#9f11cce3df73cf65bc348e8b76d891f0d54c1fe3" + integrity sha512-3BRlFZraooIUfRlyN+b/Xs5hq1lanOOo/+3h6Pwu2GMFjkGKKa4Rd51fcqGqnVlbr3jYg+WLuGyAV4KlgqwrQw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "0.1.0" + "@radix-ui/react-use-layout-effect" "0.1.0" + + "@radix-ui/react-primitive@0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz#6c233cf08b0cb87fecd107e9efecb3f21861edc1" + integrity sha512-6gSl2IidySupIMJFjYnDIkIWRyQdbu/AHK7rbICPani+LW4b0XdxBXc46og/iZvuwW8pjCS8I2SadIerv84xYA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-slot" "0.1.2" + + "@radix-ui/react-radio-group@^0.1.1": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-radio-group/-/react-radio-group-0.1.5.tgz#ca8a676123a18b44804aff10af46129e2c2b37c3" + integrity sha512-ybgHsmh/V2crKvK6xZ56dpPul7b+vyxcq7obWqHbr5W6Ca11wdm0E7lS0i/Y6pgfIKYOWIARmZYDpRMEeRCPOw== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "0.1.0" + "@radix-ui/react-compose-refs" "0.1.0" + "@radix-ui/react-context" "0.1.1" + "@radix-ui/react-label" "0.1.5" + "@radix-ui/react-presence" "0.1.2" + "@radix-ui/react-primitive" "0.1.4" + "@radix-ui/react-roving-focus" "0.1.5" + "@radix-ui/react-use-controllable-state" "0.1.0" + "@radix-ui/react-use-previous" "0.1.1" + "@radix-ui/react-use-size" "0.1.1" + + "@radix-ui/react-roving-focus@0.1.5": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-0.1.5.tgz#cc48d17a36b56f253d54905b0fd60ee134cb97ee" + integrity sha512-ClwKPS5JZE+PaHCoW7eu1onvE61pDv4kO8W4t5Ra3qMFQiTJLZMdpBQUhksN//DaVygoLirz4Samdr5Y1x1FSA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "0.1.0" + "@radix-ui/react-collection" "0.1.4" + "@radix-ui/react-compose-refs" "0.1.0" + "@radix-ui/react-context" "0.1.1" + "@radix-ui/react-id" "0.1.5" + "@radix-ui/react-primitive" "0.1.4" + "@radix-ui/react-use-callback-ref" "0.1.0" + "@radix-ui/react-use-controllable-state" "0.1.0" + + "@radix-ui/react-slider@^0.1.0", "@radix-ui/react-slider@^0.1.1": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slider/-/react-slider-0.1.4.tgz#a7b7a480ee00158195794b08cd3f1583cf102518" + integrity sha512-0z3bCcdrAi+FIcoLXS6r0ESVWuuyMnUJoCsFm7tC7Rtv95x34YtaI8YfSyQmzuMVS4rTsNtCCTZ/s727uRaVkQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/number" "0.1.0" + "@radix-ui/primitive" "0.1.0" + "@radix-ui/react-collection" "0.1.4" + "@radix-ui/react-compose-refs" "0.1.0" + "@radix-ui/react-context" "0.1.1" + "@radix-ui/react-primitive" "0.1.4" + "@radix-ui/react-use-controllable-state" "0.1.0" + "@radix-ui/react-use-direction" "0.1.0" + "@radix-ui/react-use-layout-effect" "0.1.0" + "@radix-ui/react-use-previous" "0.1.1" + "@radix-ui/react-use-size" "0.1.1" + + "@radix-ui/react-slot@0.1.2": + version "0.1.2" + resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-0.1.2.tgz#e6f7ad9caa8ce81cc8d532c854c56f9b8b6307c8" + integrity sha512-ADkqfL+agEzEguU3yS26jfB50hRrwf7U4VTwAOZEmi/g+ITcBWe12yM46ueS/UCIMI9Py+gFUaAdxgxafFvY2Q== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-compose-refs" "0.1.0" + + "@radix-ui/react-switch@^0.1.1": + version "0.1.5" + resolved "https://registry.yarnpkg.com/@radix-ui/react-switch/-/react-switch-0.1.5.tgz#071ffa19a17a47fdc5c5e6f371bd5901c9fef2f4" + integrity sha512-ITtslJPK+Yi34iNf7K9LtsPaLD76oRIVzn0E8JpEO5HW8gpRBGb2NNI9mxKtEB30TVqIcdjdL10AmuIfOMwjtg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "0.1.0" + "@radix-ui/react-compose-refs" "0.1.0" + "@radix-ui/react-context" "0.1.1" + "@radix-ui/react-label" "0.1.5" + "@radix-ui/react-primitive" "0.1.4" + "@radix-ui/react-use-controllable-state" "0.1.0" + "@radix-ui/react-use-previous" "0.1.1" + "@radix-ui/react-use-size" "0.1.1" + + "@radix-ui/react-tooltip@^0.1.0": + version "0.1.7" + resolved "https://registry.yarnpkg.com/@radix-ui/react-tooltip/-/react-tooltip-0.1.7.tgz#6f8c00d6e489565d14abf209ce0fb8853c8c8ee3" + integrity sha512-eiBUsVOHenZ0JR16tl970bB0DafJBz6mFgSGfIGIVpflFj0LIsIDiLMsYyvYdx1KwwsIUDTEZtxcPm/sWjPzqA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/primitive" "0.1.0" + "@radix-ui/react-compose-refs" "0.1.0" + "@radix-ui/react-context" "0.1.1" + "@radix-ui/react-id" "0.1.5" + "@radix-ui/react-popper" "0.1.4" + "@radix-ui/react-portal" "0.1.4" + "@radix-ui/react-presence" "0.1.2" + "@radix-ui/react-primitive" "0.1.4" + "@radix-ui/react-slot" "0.1.2" + "@radix-ui/react-use-controllable-state" "0.1.0" + "@radix-ui/react-use-escape-keydown" "0.1.0" + "@radix-ui/react-use-previous" "0.1.1" + "@radix-ui/react-use-rect" "0.1.1" + "@radix-ui/react-visually-hidden" "0.1.4" + + "@radix-ui/react-use-body-pointer-events@0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-body-pointer-events/-/react-use-body-pointer-events-0.1.1.tgz#63e7fd81ca7ffd30841deb584cd2b7f460df2597" + integrity sha512-R8leV2AWmJokTmERM8cMXFHWSiv/fzOLhG/JLmRBhLTAzOj37EQizssq4oW0Z29VcZy2tODMi9Pk/htxwb+xpA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-layout-effect" "0.1.0" + + "@radix-ui/react-use-callback-ref@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-0.1.0.tgz#934b6e123330f5b3a6b116460e6662cbc663493f" + integrity sha512-Va041McOFFl+aV+sejvl0BS2aeHx86ND9X/rVFmEFQKTXCp6xgUK0NGUAGcgBlIjnJSbMYPGEk1xKSSlVcN2Aw== + dependencies: + "@babel/runtime" "^7.13.10" + + "@radix-ui/react-use-controllable-state@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-0.1.0.tgz#4fced164acfc69a4e34fb9d193afdab973a55de1" + integrity sha512-zv7CX/PgsRl46a52Tl45TwqwVJdmqnlQEQhaYMz/yBOD2sx2gCkCFSoF/z9mpnYWmS6DTLNTg5lIps3fV6EnXg== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-callback-ref" "0.1.0" + + "@radix-ui/react-use-direction@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-direction/-/react-use-direction-0.1.0.tgz#97ac1d52e497c974389e7988f809238ed72e7df7" + integrity sha512-NajpY/An9TCPSfOVkgWIdXJV+VuWl67PxB6kOKYmtNAFHvObzIoh8o0n9sAuwSAyFCZVq211FEf9gvVDRhOyiA== + dependencies: + "@babel/runtime" "^7.13.10" + + "@radix-ui/react-use-escape-keydown@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-0.1.0.tgz#dc80cb3753e9d1bd992adbad9a149fb6ea941874" + integrity sha512-tDLZbTGFmvXaazUXXv8kYbiCcbAE8yKgng9s95d8fCO+Eundv0Jngbn/hKPhDDs4jj9ChwRX5cDDnlaN+ugYYQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-use-callback-ref" "0.1.0" + + "@radix-ui/react-use-layout-effect@0.1.0": + version "0.1.0" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-0.1.0.tgz#ebf71bd6d2825de8f1fbb984abf2293823f0f223" + integrity sha512-+wdeS51Y+E1q1Wmd+1xSSbesZkpVj4jsg0BojCbopWvgq5iBvixw5vgemscdh58ep98BwUbsFYnrywFhV9yrVg== + dependencies: + "@babel/runtime" "^7.13.10" + + "@radix-ui/react-use-previous@0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-0.1.1.tgz#0226017f72267200f6e832a7103760e96a6db5d0" + integrity sha512-O/ZgrDBr11dR8rhO59ED8s5zIXBRFi8MiS+CmFGfi7MJYdLbfqVOmQU90Ghf87aifEgWe6380LA69KBneaShAg== + dependencies: + "@babel/runtime" "^7.13.10" + + "@radix-ui/react-use-rect@0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-0.1.1.tgz#6c15384beee59c086e75b89a7e66f3d2e583a856" + integrity sha512-kHNNXAsP3/PeszEmM/nxBBS9Jbo93sO+xuMTcRfwzXsmxT5gDXQzAiKbZQ0EecCPtJIzqvr7dlaQi/aP1PKYqQ== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/rect" "0.1.1" + + "@radix-ui/react-use-size@0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-0.1.1.tgz#f6b75272a5d41c3089ca78c8a2e48e5f204ef90f" + integrity sha512-pTgWM5qKBu6C7kfKxrKPoBI2zZYZmp2cSXzpUiGM3qEBQlMLtYhaY2JXdXUCxz+XmD1YEjc8oRwvyfsD4AG4WA== + dependencies: + "@babel/runtime" "^7.13.10" + + "@radix-ui/react-visually-hidden@0.1.4": + version "0.1.4" + resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-0.1.4.tgz#6c75eae34fb5d084b503506fbfc05587ced05f03" + integrity sha512-K/q6AEEzqeeEq/T0NPChvBqnwlp8Tl4NnQdrI/y8IOY7BRR+Ug0PEsVk6g48HJ7cA1//COugdxXXVVK/m0X1mA== + dependencies: + "@babel/runtime" "^7.13.10" + "@radix-ui/react-primitive" "0.1.4" + + "@radix-ui/rect@0.1.1": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-0.1.1.tgz#95b5ba51f469bea6b1b841e2d427e17e37d38419" + integrity sha512-g3hnE/UcOg7REdewduRPAK88EPuLZtaq7sA9ouu8S+YEtnyFRI16jgv6GZYe3VMoQLL1T171ebmEPtDjyxWLzw== + dependencies: + "@babel/runtime" "^7.13.10" + + "@reach/skip-nav@^0.11.2": + version "0.11.2" + resolved "https://registry.yarnpkg.com/@reach/skip-nav/-/skip-nav-0.11.2.tgz#015498b2125ad8ef1e48cb8ab33dca93925fcbc8" + integrity sha512-cXGQJodYcyUBLBv59oxB4ywwgFDHnoyt8+W+ZgdR1LR9eDxx6170shP0yPcwf/5KV2tXJtNF2McRUObkUW90+Q== + dependencies: + "@reach/utils" "0.11.2" + tslib "^2.0.0" + + "@reach/utils@0.11.2": + version "0.11.2" + resolved "https://registry.yarnpkg.com/@reach/utils/-/utils-0.11.2.tgz#be1f03650db56fd67a16d3fc70e5262cdb139cec" + integrity sha512-fBTolYj+rKTROXmf0zHO0rCWSvw7J0ALmYj5QxW4DmITMOH5uyRuWDWOfqohIGFbOtF/sum50WTB3tvx76d+Aw== + dependencies: + "@types/warning" "^3.0.0" + tslib "^2.0.0" + warning "^4.0.3" + + "@rollup/plugin-inject@^4.0.0": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@rollup/plugin-inject/-/plugin-inject-4.0.4.tgz#fbeee66e9a700782c4f65c8b0edbafe58678fbc2" + integrity sha512-4pbcU4J/nS+zuHk+c+OL3WtmEQhqxlZ9uqfjQMQDOHOPld7PsCd8k5LWs8h5wjwJN7MgnAn768F2sDxEP4eNFQ== + dependencies: + "@rollup/pluginutils" "^3.1.0" + estree-walker "^2.0.1" + magic-string "^0.25.7" + + "@rollup/pluginutils@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b" + integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg== + dependencies: + "@types/estree" "0.0.39" + estree-walker "^1.0.1" + picomatch "^2.2.2" + + "@rushstack/eslint-patch@^1.0.8": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.1.1.tgz#782fa5da44c4f38ae9fd38e9184b54e451936118" + integrity sha512-BUyKJGdDWqvWC5GEhyOiUrGNi9iJUr4CU0O2WxJL6QJhHeeA/NVBalH+FeK0r/x/W0rPymXt5s78TDS7d6lCwg== + + "@sindresorhus/is@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" + integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== + + "@sindresorhus/is@^0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" + integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== + + "@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@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40" + integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== + dependencies: + "@sinonjs/commons" "^1.7.0" + + "@sinonjs/fake-timers@^8.0.1": + version "8.1.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz#3fdc2b6cb58935b21bfb8d1625eb1300484316e7" + integrity sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg== + dependencies: + "@sinonjs/commons" "^1.7.0" + + "@socket.io/component-emitter@~3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.0.0.tgz#8863915676f837d9dad7b76f50cb500c1e9422e9" + integrity sha512-2pTGuibAXJswAPJjaKisthqS/NOK5ypG4LYT6tEAV0S/mxW0zOIvYvGK0V8w8+SHxAm6vRMSjqSalFXeBAqs+Q== + + "@sqltools/formatter@^1.2.2": + version "1.2.3" + resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.3.tgz#1185726610acc37317ddab11c3c7f9066966bd20" + integrity sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg== + + "@stripe/react-stripe-js@^1.4.1": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@stripe/react-stripe-js/-/react-stripe-js-1.7.0.tgz#83c993a09a903703205d556617f9729784a896c3" + integrity sha512-L20v8Jq0TDZFL2+y+uXD751t6q9SalSFkSYZpmZ2VWrGZGK7HAGfRQ804dzYSSr5fGenW6iz6y7U0YKfC/TK3g== + dependencies: + prop-types "^15.7.2" + + "@stripe/stripe-js@^1.16.0", "@stripe/stripe-js@^1.17.1": + version "1.24.0" + resolved "https://registry.yarnpkg.com/@stripe/stripe-js/-/stripe-js-1.24.0.tgz#d23977f364565981f8ab30b1b540e367f72abc5c" + integrity sha512-8CEILOpzoRhGwvgcf6y+BlPyEq1ZqxAv3gsX7LvokFYvbcyH72GRcHQMGXuZS3s7HqfYQuTSFrvZNL/qdkgA9Q== + + "@szmarczak/http-timer@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" + integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== + dependencies: + defer-to-connect "^1.0.1" + + "@tailwindcss/forms@^0.5.0": + version "0.5.0" + resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.5.0.tgz#d4bea2560a10aac642573e72d3b4d62a88960449" + integrity sha512-KzWugryEBFkmoaYcBE18rs6gthWCFHHO7cAZm2/hv3hwD67AzwP7udSCa22E7R1+CEJL/FfhYsJWrc0b1aeSzw== + dependencies: + mini-svg-data-uri "^1.2.3" + + "@tailwindcss/typography@^0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.2.tgz#24b069dab24d7a2467d01aca0dd432cb4b29f0ee" + integrity sha512-coq8DBABRPFcVhVIk6IbKyyHUt7YTEC/C992tatFB+yEx5WGBQrCgsSFjxHUr8AWXphWckadVJbominEduYBqw== + dependencies: + lodash.castarray "^4.4.0" + lodash.isplainobject "^4.0.6" + lodash.merge "^4.6.2" + + "@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + + "@trivago/prettier-plugin-sort-imports@3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-3.2.0.tgz#7a32b6b3085c436eda0143b2710c440a4a56db90" + integrity sha512-DnwLe+z8t/dZX5xBbYZV1+C5STkyK/P6SSq3Nk6NXlJZsgvDZX2eN4ND7bMFgGV/NL/YChWzcNf6ziGba1ktQQ== + dependencies: + "@babel/core" "7.13.10" + "@babel/generator" "7.13.9" + "@babel/parser" "7.14.6" + "@babel/traverse" "7.13.0" + "@babel/types" "7.13.0" + javascript-natural-sort "0.7.1" + lodash "4.17.21" + + "@trpc/client@^9.16.0": + version "9.20.1" + resolved "https://registry.yarnpkg.com/@trpc/client/-/client-9.20.1.tgz#a9a5e5e4ebceacb18f31950838942a02a37b9138" + integrity sha512-nsRToriDb6ny5UpgNGB/ux2NXGmSs4/cWh9QREXi8S3jbDogFjs++J+xRzq5Q5RHtchcyOile5wxtIy3iHVhtQ== + dependencies: + "@babel/runtime" "^7.9.0" + + "@trpc/next@^9.16.0": + version "9.20.1" + resolved "https://registry.yarnpkg.com/@trpc/next/-/next-9.20.1.tgz#16bee230db13f028444be03dfe6b4283d85d0ae7" + integrity sha512-gKNguAQ8Fbi2Yvdpm7t/qhP7ZZAqwmuJRpjpus+sM/j/fGf3p5vQSB0gUepAHv8DxDhqU9691ugGQRc9ltmTyg== + dependencies: + "@babel/runtime" "^7.9.0" + react-ssr-prepass "^1.5.0" + + "@trpc/react@^9.16.0": + version "9.20.1" + resolved "https://registry.yarnpkg.com/@trpc/react/-/react-9.20.1.tgz#64a97ec1892aba2ea9d38b28b6de1b6a90ba348b" + integrity sha512-hz03YP2nL6yTknEtNQkRK2fx2ZY1cWW708CxHAUuWlyUX9NPSiHVEN1qirhceOeLiBDSmXGD9+CunxBSMAci+A== + dependencies: + "@babel/runtime" "^7.9.0" + + "@trpc/server@^9.16.0": + version "9.20.1" + resolved "https://registry.yarnpkg.com/@trpc/server/-/server-9.20.1.tgz#e222283e64a2f2ded6aceba762a219976079f8ab" + integrity sha512-UsuDslmzWrhkv1JZ12/fK4Z/5lSaPj5UJg23j1EE1gkH5aSkQgY5CHzvNv+jkiAR6rR4K2HDOMpVF4Tz50YE9Q== + dependencies: + tslib "^2.1.0" + + "@ts-morph/common@~0.12.3": + version "0.12.3" + resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.12.3.tgz#a96e250217cd30e480ab22ec6a0ebbe65fd784ff" + integrity sha512-4tUmeLyXJnJWvTFOKtcNJ1yh0a3SsTLi2MUoyj8iUNznFRN1ZquaNe7Oukqrnki2FzZkm0J9adCNLDZxUzvj+w== + dependencies: + fast-glob "^3.2.7" + minimatch "^3.0.4" + mkdirp "^1.0.4" + path-browserify "^1.0.1" + + "@tsconfig/node10@^1.0.7": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" + integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== + + "@tsconfig/node12@^1.0.7": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" + integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== + + "@tsconfig/node14@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" + integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== + + "@tsconfig/node16@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" + integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== + + "@typeform/embed-react@^1.2.4": + version "1.13.0" + resolved "https://registry.yarnpkg.com/@typeform/embed-react/-/embed-react-1.13.0.tgz#9b50f0b880f212480b95d4ec2f1390998b2d3561" + integrity sha512-LSN7DQ1Eg9U7IvbfSfn152SspkkSaWlsWytEAGsqmau/HtH99T2ra/FoQ/zPajAObmWWpdH3p/jQiUL96vytPw== + dependencies: + "@typeform/embed" "1.34.1" + fast-deep-equal "^3.1.3" + + "@typeform/embed@1.34.1": + version "1.34.1" + resolved "https://registry.yarnpkg.com/@typeform/embed/-/embed-1.34.1.tgz#53f1f0b6fee7af24aa2446cf2e258c042df2e48f" + integrity sha512-FdteCw0TKHcNiSmz0t0CfFfK4xL7pc6jce/FWZJ9MLPTKcMzwaAvdaQ0Byll2kSG1RtNv+dfcBtth7xjhCKs3Q== + + "@types/accept-language-parser@1.5.2": + version "1.5.2" + resolved "https://registry.yarnpkg.com/@types/accept-language-parser/-/accept-language-parser-1.5.2.tgz#ea48ed07a3dc9d2ba6666d45c018ad1b5e59d665" + integrity sha512-G8NhvYQ4JVT0GhvgPSVDVskFwWhjFvjbTNou3rRkkDgB8dTBZtxZ1xcU9jqJSth5qTGCzbrKwRf+vKleKdrb7w== + + "@types/acorn@^4.0.0": + version "4.0.6" + resolved "https://registry.yarnpkg.com/@types/acorn/-/acorn-4.0.6.tgz#d61ca5480300ac41a7d973dd5b84d0a591154a22" + integrity sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ== + dependencies: + "@types/estree" "*" + + "@types/asn1js@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@types/asn1js/-/asn1js-2.0.2.tgz#bb1992291381b5f06e22a829f2ae009267cdf8c5" + integrity sha512-t4YHCgtD+ERvH0FyxvNlYwJ2ezhqw7t+Ygh4urQ7dJER8i185JPv6oIM3ey5YQmGN6Zp9EMbpohkjZi9t3UxwA== + + "@types/async@^3.2.10": + version "3.2.12" + resolved "https://registry.yarnpkg.com/@types/async/-/async-3.2.12.tgz#0ebbfaf3f249ffa0fdc50179b07705f69c90d70c" + integrity sha512-4i4w4tfNDo73BOjk0qHcB2YJ8A2SjITCrU4BTsgdJFTsVr6atPDXa0T9r0QZTrX3axtWwkqpZqF4B3gR0TqBGw== + + "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14", "@types/babel__core@^7.1.7": + version "7.1.18" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.18.tgz#1a29abcc411a9c05e2094c98f9a1b7da6cdf49f8" + integrity sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ== + 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.4", "@types/babel__traverse@^7.0.6": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" + integrity sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA== + dependencies: + "@babel/types" "^7.3.0" + + "@types/bcryptjs@^2.4.2": + version "2.4.2" + resolved "https://registry.yarnpkg.com/@types/bcryptjs/-/bcryptjs-2.4.2.tgz#e3530eac9dd136bfdfb0e43df2c4c5ce1f77dfae" + integrity sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ== + + "@types/bn.js@^4.11.5": + version "4.11.6" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" + integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== + dependencies: + "@types/node" "*" + + "@types/bn.js@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.0.tgz#32c5d271503a12653c62cf4d2b45e6eab8cebc68" + integrity sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA== + dependencies: + "@types/node" "*" + + "@types/chrome@^0.0.136": + version "0.0.136" + resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.136.tgz#7c011b9f997b0156f25a140188a0c5689d3f368f" + integrity sha512-XDEiRhLkMd+SB7Iw3ZUIj/fov3wLd4HyTdLltVszkgl1dBfc3Rb7oPMVZ2Mz2TLqnF7Ow+StbR8E7r9lqpb4DA== + dependencies: + "@types/filesystem" "*" + "@types/har-format" "*" + + "@types/cross-spawn@6.0.2": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@types/cross-spawn/-/cross-spawn-6.0.2.tgz#168309de311cd30a2b8ae720de6475c2fbf33ac7" + integrity sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw== + dependencies: + "@types/node" "*" + + "@types/debug@4.1.7", "@types/debug@^4.0.0": + version "4.1.7" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82" + integrity sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg== + dependencies: + "@types/ms" "*" + + "@types/engine.io@*": + version "3.1.7" + resolved "https://registry.yarnpkg.com/@types/engine.io/-/engine.io-3.1.7.tgz#86e541a5dc52fb7e97735383564a6ae4cfe2e8f5" + integrity sha512-qNjVXcrp+1sS8YpRUa714r0pgzOwESdW5UjHL7D/2ZFdBX0BXUXtg1LUrp+ylvqbvMcMWUy73YpRoxPN2VoKAQ== + dependencies: + "@types/node" "*" + + "@types/estree-jsx@^0.0.1": + version "0.0.1" + resolved "https://registry.yarnpkg.com/@types/estree-jsx/-/estree-jsx-0.0.1.tgz#c36d7a1afeb47a95a8ee0b7bc8bc705db38f919d" + integrity sha512-gcLAYiMfQklDCPjQegGn0TBAn9it05ISEsEhlKQUddIk7o2XDokOcTN7HBO8tznM0D9dGezvHEfRZBfZf6me0A== + dependencies: + "@types/estree" "*" + + "@types/estree@*": + version "0.0.51" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" + integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== + + "@types/estree@0.0.39": + version "0.0.39" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" + integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== + + "@types/estree@^0.0.46": + version "0.0.46" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.46.tgz#0fb6bfbbeabd7a30880504993369c4bf1deab1fe" + integrity sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg== + + "@types/estree@^0.0.50": + version "0.0.50" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" + integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== + + "@types/filesystem@*": + version "0.0.32" + resolved "https://registry.yarnpkg.com/@types/filesystem/-/filesystem-0.0.32.tgz#307df7cc084a2293c3c1a31151b178063e0a8edf" + integrity sha512-Yuf4jR5YYMR2DVgwuCiP11s0xuVRyPKmz8vo6HBY3CGdeMj8af93CFZX+T82+VD1+UqHOxTq31lO7MI7lepBtQ== + dependencies: + "@types/filewriter" "*" + + "@types/filewriter@*": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.29.tgz#a48795ecadf957f6c0d10e0c34af86c098fa5bee" + integrity sha512-BsPXH/irW0ht0Ji6iw/jJaK8Lj3FJemon2gvEqHKpCdDCeemHa+rI3WBGq5z7cDMZgoLjY40oninGxqk+8NzNQ== + + "@types/glidejs__glide@^3.4.1": + version "3.4.1" + resolved "https://registry.yarnpkg.com/@types/glidejs__glide/-/glidejs__glide-3.4.1.tgz#220bbce087500eda3700e476c728e17d096eb6f0" + integrity sha512-ib2VRchnLSXGOdiZFfCt6QEIYviw5g+Yey8Q2+kMzUxGXsnR9ZwZi1qPXI1ttrvR/AtUYZmSSHDVVSoIyt6LPw== + + "@types/graceful-fs@^4.1.2": + 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/har-format@*": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@types/har-format/-/har-format-1.2.8.tgz#e6908b76d4c88be3db642846bb8b455f0bfb1c4e" + integrity sha512-OP6L9VuZNdskgNN3zFQQ54ceYD8OLq5IbqO4VK91ORLfOm7WdT/CiT/pHEBSQEqCInJ2y3O6iCm/zGtPElpgJQ== + + "@types/hast@^2.0.0": + version "2.3.4" + resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.4.tgz#8aa5ef92c117d20d974a82bdfb6a648b08c0bafc" + integrity sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g== + dependencies: + "@types/unist" "*" + + "@types/hoist-non-react-statics@^3.3.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" + integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== + dependencies: + "@types/react" "*" + hoist-non-react-statics "^3.3.0" + + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" + integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== + + "@types/istanbul-lib-report@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + dependencies: + "@types/istanbul-lib-coverage" "*" + + "@types/istanbul-reports@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + dependencies: + "@types/istanbul-lib-report" "*" + + "@types/jest@^27.0.3": + version "27.4.1" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.4.1.tgz#185cbe2926eaaf9662d340cc02e548ce9e11ab6d" + integrity sha512-23iPJADSmicDVrWk+HT58LMJtzLAnB2AgIzplQuq/bSrGaxCrlvRFjGbXmamnnk/mAmCdLStiGqggu28ocUyiw== + dependencies: + jest-matcher-utils "^27.0.0" + pretty-format "^27.0.0" + + "@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= + + "@types/lodash@^4.14.175", "@types/lodash@^4.14.177": + version "4.14.179" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.179.tgz#490ec3288088c91295780237d2497a3aa9dfb5c5" + integrity sha512-uwc1x90yCKqGcIOAT6DwOSuxnrAbpkdPsUOZtwrXb4D/6wZs+6qG7QnIawDuZWg0sWpxl+ltIKCaLoMlna678w== + + "@types/mdast@^3.0.0": + version "3.0.10" + resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af" + integrity sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA== + dependencies: + "@types/unist" "*" + + "@types/mdurl@^1.0.0": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.2.tgz#e2ce9d83a613bacf284c7be7d491945e39e1f8e9" + integrity sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA== + + "@types/mdx@^2.0.0": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/mdx/-/mdx-2.0.1.tgz#e4c05d355d092d7b58db1abfe460e53f41102ac8" + integrity sha512-JPEv4iAl0I+o7g8yVWDwk30es8mfVrjkvh5UeVR2sYPpZCK44vrAPsbJpIS+rJAUxLgaSAMKTEH5Vn5qd9XsrQ== + + "@types/micro@7.3.6": + version "7.3.6" + resolved "https://registry.yarnpkg.com/@types/micro/-/micro-7.3.6.tgz#7d68eb5a780ac4761e3b80687b4ee7328ebc3f2e" + integrity sha512-rZHvZ3+Ev3cGJJSy/wtSiXZmafU8guI07PHXf4ku9sQLfDuFALHMCiV+LuH4VOaeMMMnRs8nqxU392gxfn661g== + dependencies: + "@types/node" "*" + "@types/socket.io" "2.1.13" + + "@types/micro@^7.3.6": + version "7.3.7" + resolved "https://registry.yarnpkg.com/@types/micro/-/micro-7.3.7.tgz#84bef63ef8cc113a70b9a64345ebea2d99946647" + integrity sha512-MFsX7eCj0Tg3TtphOQvANNvNtFpya+s/rYOCdV6o+DFjOQPFi2EVRbBALjbbgZTXUaJP1Q281MJiJOD40d0UxQ== + dependencies: + "@types/node" "*" + + "@types/module-alias@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@types/module-alias/-/module-alias-2.0.1.tgz#e5893236ce922152d57c5f3f978f764f4deeb45f" + integrity sha512-DN/CCT1HQG6HquBNJdLkvV+4v5l/oEuwOHUPLxI+Eub0NED+lk0YUfba04WGH90EINiUrNgClkNnwGmbICeWMQ== + + "@types/ms@*": + version "0.7.31" + resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" + integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== + + "@types/node@*", "@types/node@>=8.1.0": version "17.0.21" resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.21.tgz#864b987c0c68d07b4345845c3e63b75edd143644" integrity sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ== - caniuse-lite@^1.0.30001283: + "@types/node@^12.12.6": + version "12.20.47" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.47.tgz#ca9237d51f2a2557419688511dab1c8daf475188" + integrity sha512-BzcaRsnFuznzOItW1WpQrDHM7plAa7GIDMZ6b5pnMbkqEtM/6WCOhvZar39oeMQP79gwvFUWjjptE7/KGcNqFg== + + "@types/node@^16.11.24": + version "16.11.26" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.26.tgz#63d204d136c9916fb4dcd1b50f9740fe86884e47" + integrity sha512-GZ7bu5A6+4DtG7q9GsoHXy3ALcgeIHP4NnL0Vv2wu0uUB/yQex26v0tf6/na1mm0+bS9Uw+0DFex7aaKr2qawQ== + + "@types/nodemailer@^6.4.4": + version "6.4.4" + resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.4.4.tgz#c265f7e7a51df587597b3a49a023acaf0c741f4b" + integrity sha512-Ksw4t7iliXeYGvIQcSIgWQ5BLuC/mljIEbjf615svhZL10PE9t+ei8O9gDaD3FPCasUJn9KTLwz2JFJyiiyuqw== + dependencies: + "@types/node" "*" + + "@types/normalize-package-data@^2.4.0": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" + integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== + + "@types/parse-json@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== + + "@types/pbkdf2@^3.0.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@types/pbkdf2/-/pbkdf2-3.1.0.tgz#039a0e9b67da0cdc4ee5dab865caa6b267bb66b1" + integrity sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ== + dependencies: + "@types/node" "*" + + "@types/prettier@^2.0.0", "@types/prettier@^2.1.5": + version "2.4.4" + resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.4.tgz#5d9b63132df54d8909fce1c3f8ca260fdd693e17" + integrity sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA== + + "@types/prop-types@*": + version "15.7.4" + resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" + integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== + + "@types/qrcode@^1.4.1": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@types/qrcode/-/qrcode-1.4.2.tgz#7d7142d6fa9921f195db342ed08b539181546c74" + integrity sha512-7uNT9L4WQTNJejHTSTdaJhfBSCN73xtXaHFyBJ8TSwiLhe4PRuTue7Iph0s2nG9R/ifUaSnGhLUOZavlBEqDWQ== + dependencies: + "@types/node" "*" + + "@types/react-calendar@^3.0.0": + version "3.5.0" + resolved "https://registry.yarnpkg.com/@types/react-calendar/-/react-calendar-3.5.0.tgz#8195a33e20395e1f5171eea9c80156f3a5115b43" + integrity sha512-qVSA5M0+SwLRINpE81TMUTh0NwJVed8T+lplJ7v0XAe4EHlMyNeNlkN9suKBxlwIEZ/62QP/m0QjGNCwdOy8PQ== + dependencies: + "@types/react" "*" + + "@types/react-dom@^17.0.11": + version "17.0.13" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.13.tgz#a3323b974ee4280070982b3112351bb1952a7809" + integrity sha512-wEP+B8hzvy6ORDv1QBhcQia4j6ea4SFIBttHYpXKPFZRviBvknq0FRh3VrIxeXUmsPkwuXVZrVGG7KUVONmXCQ== + dependencies: + "@types/react" "*" + + "@types/react-phone-number-input@^3.0.13": + version "3.0.13" + resolved "https://registry.yarnpkg.com/@types/react-phone-number-input/-/react-phone-number-input-3.0.13.tgz#4eb7dcd278dcf9eb2a8d2ce2cb304657cbf1b4e5" + integrity sha512-27k7AvLbzCjpuRORFhehFdRHVan1q6RhSTV7dFiXwZ2ojnS/JMx77wd9OyAU464oN0GIlkfhc0njGzL97/xNcw== + dependencies: + "@types/react" "*" + + "@types/react-transition-group@^4.4.0": + version "4.4.4" + resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.4.tgz#acd4cceaa2be6b757db61ed7b432e103242d163e" + integrity sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug== + dependencies: + "@types/react" "*" + + "@types/react-virtualized-auto-sizer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@types/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.1.tgz#b3187dae1dfc4c15880c9cfc5b45f2719ea6ebd4" + integrity sha512-GH8sAnBEM5GV9LTeiz56r4ZhMOUSrP43tAQNSRVxNexDjcNKLCEtnxusAItg1owFUFE6k0NslV26gqVClVvong== + dependencies: + "@types/react" "*" + + "@types/react-window@^1.8.5": + version "1.8.5" + resolved "https://registry.yarnpkg.com/@types/react-window/-/react-window-1.8.5.tgz#285fcc5cea703eef78d90f499e1457e9b5c02fc1" + integrity sha512-V9q3CvhC9Jk9bWBOysPGaWy/Z0lxYcTXLtLipkt2cnRj1JOSFNF7wqGpkScSXMgBwC+fnVRg/7shwgddBG5ICw== + dependencies: + "@types/react" "*" + + "@types/react@*", "@types/react@16 || 17", "@types/react@^17.0.37": + version "17.0.40" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.40.tgz#dc010cee6254d5239a138083f3799a16638e6bad" + integrity sha512-UrXhD/JyLH+W70nNSufXqMZNuUD2cXHu6UjCllC6pmOQgBX4SGXOH8fjRka0O0Ee0HrFxapDD8Bwn81Kmiz6jQ== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + + "@types/react@17.0.20": + version "17.0.20" + resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.20.tgz#a4284b184d47975c71658cd69e759b6bd37c3b8c" + integrity sha512-wWZrPlihslrPpcKyCSlmIlruakxr57/buQN1RjlIeaaTWDLtJkTtRW429MoQJergvVKc4IWBpRhWw7YNh/7GVA== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + + "@types/scheduler@*": + version "0.16.2" + resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" + integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== + + "@types/secp256k1@^4.0.1": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@types/secp256k1/-/secp256k1-4.0.3.tgz#1b8e55d8e00f08ee7220b4d59a6abe89c37a901c" + integrity sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w== + dependencies: + "@types/node" "*" + + "@types/socket.io-parser@*": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/socket.io-parser/-/socket.io-parser-3.0.0.tgz#9726d3ab9235757a0a30dd5ccf8975dce54e5e2c" + integrity sha512-Ry/rbTE6HQNL9eu3LpL1Ocup5VexXu1bSSGlSho/IR5LuRc8YvxwSNJ3JxqTltVJEATLbZkMQETSbxfKNgp4Ew== + dependencies: + socket.io-parser "*" + + "@types/socket.io@2.1.13": + version "2.1.13" + resolved "https://registry.yarnpkg.com/@types/socket.io/-/socket.io-2.1.13.tgz#b6d694234e99956c96ff99e197eda824b6f9dc48" + integrity sha512-JRgH3nCgsWel4OPANkhH8TelpXvacAJ9VeryjuqCDiaVDMpLysd6sbt0dr6Z15pqH3p2YpOT3T1C5vQ+O/7uyg== + dependencies: + "@types/engine.io" "*" + "@types/node" "*" + "@types/socket.io-parser" "*" + + "@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/stripe@^8.0.417": + version "8.0.417" + resolved "https://registry.yarnpkg.com/@types/stripe/-/stripe-8.0.417.tgz#b651677a9fc33be8ce8fd5bceadd7ca077214244" + integrity sha512-PTuqskh9YKNENnOHGVJBm4sM0zE8B1jZw1JIskuGAPkMB+OH236QeN8scclhYGPA4nG6zTtPXgwpXdp+HPDTVw== + dependencies: + stripe "*" + + "@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" + integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== + + "@types/uuid@8.3.1": + version "8.3.1" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.1.tgz#1a32969cf8f0364b3d8c8af9cc3555b7805df14f" + integrity sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg== + + "@types/warning@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/warning/-/warning-3.0.0.tgz#0d2501268ad8f9962b740d387c4654f5f8e23e52" + integrity sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI= + + "@types/web@^0.0.55": + version "0.0.55" + resolved "https://registry.yarnpkg.com/@types/web/-/web-0.0.55.tgz#0677cd86c6a4dd8c3592bd5f36435aa7e1b99028" + integrity sha512-YMH9aZrSJIMRMioCUwrgauI3iS/w2wRFN45Xxm0FE9Tt3hqaqkvOzjDFGsNjyKZzz7GJC0ilb+0tv59ytSUbrQ== + + "@types/webidl-conversions@*": + version "6.1.1" + resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz#e33bc8ea812a01f63f90481c666334844b12a09e" + integrity sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q== + + "@types/whatwg-url@^8.2.1": + version "8.2.1" + resolved "https://registry.yarnpkg.com/@types/whatwg-url/-/whatwg-url-8.2.1.tgz#f1aac222dab7c59e011663a0cb0a3117b2ef05d4" + integrity sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ== + dependencies: + "@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@^15.0.0": + version "15.0.14" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06" + integrity sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ== + dependencies: + "@types/yargs-parser" "*" + + "@types/yargs@^16.0.0": + version "16.0.4" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" + integrity sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw== + dependencies: + "@types/yargs-parser" "*" + + "@types/yauzl@^2.9.1": + version "2.9.2" + resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.9.2.tgz#c48e5d56aff1444409e39fa164b0b4d4552a7b7a" + integrity sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA== + dependencies: + "@types/node" "*" + + "@types/zen-observable@0.8.3": + version "0.8.3" + resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.3.tgz#781d360c282436494b32fe7d9f7f8e64b3118aa3" + integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw== + + "@typescript-eslint/parser@^5.0.0": + version "5.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.14.0.tgz#7c79f898aa3cff0ceee6f1d34eeed0f034fb9ef3" + integrity sha512-aHJN8/FuIy1Zvqk4U/gcO/fxeMKyoSv/rS46UXMXOJKVsLQ+iYPuXNbpbH7cBLcpSbmyyFbwrniLx5+kutu1pw== + dependencies: + "@typescript-eslint/scope-manager" "5.14.0" + "@typescript-eslint/types" "5.14.0" + "@typescript-eslint/typescript-estree" "5.14.0" + debug "^4.3.2" + + "@typescript-eslint/scope-manager@5.14.0": + version "5.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.14.0.tgz#ea518962b42db8ed0a55152ea959c218cb53ca7b" + integrity sha512-LazdcMlGnv+xUc5R4qIlqH0OWARyl2kaP8pVCS39qSL3Pd1F7mI10DbdXeARcE62sVQE4fHNvEqMWsypWO+yEw== + dependencies: + "@typescript-eslint/types" "5.14.0" + "@typescript-eslint/visitor-keys" "5.14.0" + + "@typescript-eslint/types@5.14.0": + version "5.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.14.0.tgz#96317cf116cea4befabc0defef371a1013f8ab11" + integrity sha512-BR6Y9eE9360LNnW3eEUqAg6HxS9Q35kSIs4rp4vNHRdfg0s+/PgHgskvu5DFTM7G5VKAVjuyaN476LCPrdA7Mw== + + "@typescript-eslint/typescript-estree@5.14.0": + version "5.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.14.0.tgz#78b7f7385d5b6f2748aacea5c9b7f6ae62058314" + integrity sha512-QGnxvROrCVtLQ1724GLTHBTR0lZVu13izOp9njRvMkCBgWX26PKvmMP8k82nmXBRD3DQcFFq2oj3cKDwr0FaUA== + dependencies: + "@typescript-eslint/types" "5.14.0" + "@typescript-eslint/visitor-keys" "5.14.0" + debug "^4.3.2" + globby "^11.0.4" + is-glob "^4.0.3" + semver "^7.3.5" + tsutils "^3.21.0" + + "@typescript-eslint/visitor-keys@5.14.0": + version "5.14.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.14.0.tgz#1927005b3434ccd0d3ae1b2ecf60e65943c36986" + integrity sha512-yL0XxfzR94UEkjBqyymMLgCBdojzEuy/eim7N9/RIcTNxpJudAcqsU8eRyfzBbcEzGoPWfdM3AGak3cN08WOIw== + dependencies: + "@typescript-eslint/types" "5.14.0" + eslint-visitor-keys "^3.0.0" + + "@vercel/edge-functions-ui@^0.2.1": + version "0.2.1" + resolved "https://registry.yarnpkg.com/@vercel/edge-functions-ui/-/edge-functions-ui-0.2.1.tgz#8af0a5d8d4d544364fa79c4d075564e3a5bd972e" + integrity sha512-dBomNbO5IuWGEP0OB8deIpjNm+ZeG7Ex5WXIUsVfJihE6CtBXoZi0zWDOlyWxRW1rogqFLnSjgItzDA7G4ADkg== + dependencies: + clsx "^1.1.1" + next-transpile-modules "^8.0.0" + + "@wojtekmaj/date-utils@^1.0.2", "@wojtekmaj/date-utils@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@wojtekmaj/date-utils/-/date-utils-1.0.3.tgz#2dcfd92881425c5923e429c2aec86fb3609032a1" + integrity sha512-1VPkkTBk07gMR1fjpBtse4G+oJqpmE+0gUFB0dg3VIL7qJmUVaBoD/vlzMm/jNeOPfvlmerl1lpnsZyBUFIRuw== + + "@wojtekmaj/react-daterange-picker@^3.3.1": + version "3.4.0" + resolved "https://registry.yarnpkg.com/@wojtekmaj/react-daterange-picker/-/react-daterange-picker-3.4.0.tgz#bd85e980b16200f6066895961c518a327a830f3a" + integrity sha512-2ONcCSx10YP3+EOfg+1YrOO+Taa0iBdvfOJ5n8ZDW6fwS+9eyzYwWfRfPk78F2xZ7T7CR41ApBQlqM/2DT2Brw== + dependencies: + make-event-props "^1.1.0" + merge-class-names "^1.1.1" + prop-types "^15.6.0" + react-calendar "^3.3.1" + react-date-picker "^8.4.0" + react-fit "^1.4.0" + + "@xmldom/xmldom@0.7.5", "@xmldom/xmldom@^0.7.0": + version "0.7.5" + resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.5.tgz#09fa51e356d07d0be200642b0e4f91d8e6dd408d" + integrity sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A== + + abab@^2.0.3, abab@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" + integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== + + abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + + abstract-leveldown@~0.12.0, abstract-leveldown@~0.12.1: + version "0.12.4" + resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-0.12.4.tgz#29e18e632e60e4e221d5810247852a63d7b2e410" + integrity sha1-KeGOYy5g5OIh1YECR4UqY9ey5BA= + dependencies: + xtend "~3.0.0" + + accept-language-parser@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/accept-language-parser/-/accept-language-parser-1.5.0.tgz#8877c54040a8dcb59e0a07d9c1fde42298334791" + integrity sha1-iHfFQECo3LWeCgfZwf3kIpgzR5E= + + accepts@^1.3.7, accepts@~1.3.7, accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + + acorn-globals@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" + integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== + dependencies: + acorn "^7.1.1" + acorn-walk "^7.1.1" + + acorn-jsx@^5.0.0, acorn-jsx@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + + acorn-node@^1.6.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" + integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A== + dependencies: + acorn "^7.0.0" + acorn-walk "^7.0.0" + xtend "^4.0.2" + + acorn-walk@^7.0.0, acorn-walk@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + + acorn-walk@^8.0.0, acorn-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + + acorn@^7.0.0, acorn@^7.1.1: + version "7.4.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" + integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== + + acorn@^8.0.0, acorn@^8.0.4, acorn@^8.2.4, acorn@^8.4.1, acorn@^8.7.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" + integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== + + agent-base@6, agent-base@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + + aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + + ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + + 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== + dependencies: + type-fest "^0.21.3" + + ansi-regex@^5.0.0, ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + + ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + + ansi-styles@^3.1.0, ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + + ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + + ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + + ansi-styles@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.1.0.tgz#87313c102b8118abd57371afab34618bf7350ed3" + integrity sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ== + + any-base@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/any-base/-/any-base-1.1.0.tgz#ae101a62bc08a597b4c9ab5b7089d456630549fe" + integrity sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg== + + any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= + + anymatch@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== + dependencies: + micromatch "^3.1.4" + normalize-path "^2.1.1" + + anymatch@^3.0.3, anymatch@~3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + + app-root-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad" + integrity sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw== + + arch@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" + integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== + + archive-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/archive-type/-/archive-type-4.0.0.tgz#f92e72233056dfc6969472749c267bdb046b1d70" + integrity sha1-+S5yIzBW38aWlHJ0nCZ72wRrHXA= + dependencies: + file-type "^4.2.0" + + arg@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/arg/-/arg-1.0.0.tgz#444d885a4e25b121640b55155ef7cd03975d6050" + integrity sha512-Wk7TEzl1KqvTGs/uyhmHO/3XLd3t1UeU4IstvPXVzGPM522cTjqjNZ99esCkcL52sjqjo8e8CTBcWhkxvGzoAw== + + arg@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.0.tgz#583c518199419e0037abb74062c37f8519e575f0" + integrity sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg== + + arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + + arg@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.1.tgz#eb0c9a8f77786cad2af8ff2b862899842d7b6adb" + integrity sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA== + + argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + + argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + + aria-hidden@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.1.3.tgz#bb48de18dc84787a3c6eee113709c473c64ec254" + integrity sha512-RhVWFtKH5BiGMycI72q2RAFMLQi8JP9bLuQXgR5a8Znp7P5KOIADSJeyfI8PCVxLEp067B2HbP5JIiI/PXIZeA== + dependencies: + tslib "^1.0.0" + + aria-query@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b" + integrity sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA== + dependencies: + "@babel/runtime" "^7.10.2" + "@babel/runtime-corejs3" "^7.10.2" + + arr-diff@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= + + arr-flatten@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== + + arr-union@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= + + array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + + array-includes@^3.1.3, array-includes@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" + integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + get-intrinsic "^1.1.1" + is-string "^1.0.7" + + array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + + array-unique@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= + + array.prototype.flat@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13" + integrity sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.0" + + array.prototype.flatmap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz#908dc82d8a406930fdf38598d51e7411d18d4446" + integrity sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + es-abstract "^1.19.0" + + arrify@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" + integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== + + asn1.js@^5.2.0: + version "5.4.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" + integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + safer-buffer "^2.1.0" + + asn1@~0.2.3: + version "0.2.6" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== + dependencies: + safer-buffer "~2.1.0" + + asn1js@^2.1.1, asn1js@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-2.2.0.tgz#d890fcdda86b8a005693df14a986bfb2c2069c57" + integrity sha512-oagLNqpfNv7CvmyMoexMDNyVDSiq1rya0AEUgcLlNHdHgNl6U/hi8xY370n5y+ZIFEXOx0J4B1qF2NDjMRxklA== + dependencies: + pvutils latest + + assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + + assign-symbols@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= + + ast-types-flow@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" + integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= + + astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + + astring@^1.6.0: + version "1.8.1" + resolved "https://registry.yarnpkg.com/astring/-/astring-1.8.1.tgz#a91c4afd4af3523e11f31242a3d5d9af62bb6cc6" + integrity sha512-Aj3mbwVzj7Vve4I/v2JYOPFkCGM2YS7OqQTNSxmUR+LECRpokuPgAYghePgr6SALDo5bD5DlfbSaYjOzGJZOLQ== + + async-limiter@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" + integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== + + async@^3.2.1: + version "3.2.3" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.3.tgz#ac53dafd3f4720ee9e8a160628f18ea91df196c9" + integrity sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g== + + asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= + + atob@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== + + autoprefixer@^10.3.4: + version "10.4.4" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.4.tgz#3e85a245b32da876a893d3ac2ea19f01e7ea5a1e" + integrity sha512-Tm8JxsB286VweiZ5F0anmbyGiNI3v3wGv3mz9W+cxEDYB/6jbnj6GM9H9mK3wIL8ftgl+C07Lcwb8PG5PCCPzA== + dependencies: + browserslist "^4.20.2" + caniuse-lite "^1.0.30001317" + fraction.js "^4.2.0" + normalize-range "^0.1.2" + picocolors "^1.0.0" + postcss-value-parser "^4.2.0" + + autoprefixer@^10.4.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.3.tgz#d4b9358be607c30d1900c1412d0d668f98bb5a6a" + integrity sha512-3EIK6tHl2SyJWCoPsQzL3NEqKOdjCWbPzoOInjVAQYo/y/OCEFG9KwB5162dehG5GadiGfgxu7nrWCpExCfRFQ== + dependencies: + browserslist "^4.20.2" + caniuse-lite "^1.0.30001317" + fraction.js "^4.2.0" + normalize-range "^0.1.2" + picocolors "^1.0.0" + postcss-value-parser "^4.2.0" + + available-typed-arrays@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" + integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== + + aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + + aws4@^1.8.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" + integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== + + axe-core@^4.3.5: + version "4.4.1" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.1.tgz#7dbdc25989298f9ad006645cd396782443757413" + integrity sha512-gd1kmb21kwNuWr6BQz8fv6GNECPBnUasepcoLbekws23NVBLODdsClRZ+bQ8+9Uomf3Sm3+Vwn0oYG9NvwnJCw== + + axobject-query@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" + integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA== + + babel-jest@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" + integrity sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA== + dependencies: + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/babel__core" "^7.1.7" + babel-plugin-istanbul "^6.0.0" + babel-preset-jest "^26.6.2" + chalk "^4.0.0" + graceful-fs "^4.2.4" + slash "^3.0.0" + + babel-jest@^27.3.1, babel-jest@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444" + integrity sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg== + dependencies: + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^27.5.1" + 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.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" + integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== + dependencies: + object.assign "^4.1.0" + + babel-plugin-istanbul@^6.0.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@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz#8185bd030348d254c6d7dd974355e6a28b21e62d" + integrity sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" + "@types/babel__traverse" "^7.0.6" + + babel-plugin-jest-hoist@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz#9be98ecf28c331eb9f5df9c72d6f89deb8181c2e" + integrity sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" + "@types/babel__traverse" "^7.0.6" + + babel-plugin-macros@^2.6.1: + version "2.8.0" + resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" + integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== + dependencies: + "@babel/runtime" "^7.7.2" + cosmiconfig "^6.0.0" + resolve "^1.12.0" + + 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.1" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz#440f1b70ccfaabc6b676d196239b138f8a2cfba5" + integrity sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w== + dependencies: + "@babel/compat-data" "^7.13.11" + "@babel/helper-define-polyfill-provider" "^0.3.1" + semver "^6.1.1" + + babel-plugin-polyfill-corejs3@^0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz#aabe4b2fa04a6e038b688c5e55d44e78cd3a5f72" + integrity sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.1" + core-js-compat "^3.21.0" + + babel-plugin-polyfill-regenerator@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz#2c0678ea47c75c8cc2fbb1852278d8fb68233990" + integrity sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A== + dependencies: + "@babel/helper-define-polyfill-provider" "^0.3.1" + + babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + + babel-preset-jest@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz#747872b1171df032252426586881d62d31798fee" + integrity sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ== + dependencies: + babel-plugin-jest-hoist "^26.6.2" + babel-preset-current-node-syntax "^1.0.0" + + babel-preset-jest@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz#91f10f58034cb7989cb4f962b69fa6eef6a6bc81" + integrity sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag== + dependencies: + babel-plugin-jest-hoist "^27.5.1" + babel-preset-current-node-syntax "^1.0.0" + + bail@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" + integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ== + + bail@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/bail/-/bail-2.0.2.tgz#d26f5cd8fe5d6f832a31517b9f7c356040ba6d5d" + integrity sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw== + + balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + + base-64@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base-64/-/base-64-1.0.0.tgz#09d0f2084e32a3fd08c2475b973788eee6ae8f4a" + integrity sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg== + + base-x@^3.0.2, base-x@^3.0.8: + version "3.0.9" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" + integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== + dependencies: + safe-buffer "^5.0.1" + + base64-js@^1.3.0, base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + + base@^0.11.1: + version "0.11.2" + resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== + dependencies: + cache-base "^1.0.1" + class-utils "^0.3.5" + component-emitter "^1.2.1" + define-property "^1.0.0" + isobject "^3.0.1" + mixin-deep "^1.2.0" + pascalcase "^0.1.1" + + bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + dependencies: + tweetnacl "^0.14.3" + + bcryptjs@^2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb" + integrity sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms= + + big-integer@^1.6.16: + version "1.6.51" + resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" + integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== + + big.js@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== + + bignumber.js@^9.0.0: + version "9.0.2" + resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.2.tgz#71c6c6bed38de64e24a65ebe16cfcf23ae693673" + integrity sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw== + + binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + + bl@^1.0.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7" + integrity sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww== + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + + bl@~0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/bl/-/bl-0.8.2.tgz#c9b6bca08d1bc2ea00fc8afb4f1a5fd1e1c66e4e" + integrity sha1-yba8oI0bwuoA/Ir7Txpf0eHGbk4= + dependencies: + readable-stream "~1.0.26" + + blakejs@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.1.tgz#bf313053978b2cd4c444a48795710be05c785702" + integrity sha512-bLG6PHOCZJKNshTjGRBvET0vTciwQE6zFKOKKXPDJfwFBd4Ac0yBfPZqcGvGJap50l7ktvlpFqc2jGVaUgbJgg== + + bluebird@^3.5.0: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + + bmp-js@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/bmp-js/-/bmp-js-0.1.0.tgz#e05a63f796a6c1ff25f4771ec7adadc148c07233" + integrity sha1-4Fpj95amwf8l9Hcex62twUjAcjM= + + bn.js@4.11.6: + version "4.11.6" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" + integrity sha1-UzRK2xRhehP26N0s4okF0cC6MhU= + + bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.6, bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + + bn.js@^5.0.0, bn.js@^5.1.1, bn.js@^5.1.2, bn.js@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" + integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== + + body-parser@1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.1.tgz#1499abbaa9274af3ecc9f6f10396c995943e31d4" + integrity sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA== + dependencies: + bytes "3.1.1" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.8.1" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.9.6" + raw-body "2.4.2" + type-is "~1.6.18" + + body-parser@1.19.2, body-parser@^1.16.0: + version "1.19.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.2.tgz#4714ccd9c157d44797b8b5607d72c0b89952f26e" + integrity sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw== + dependencies: + bytes "3.1.2" + content-type "~1.0.4" + debug "2.6.9" + depd "~1.1.2" + http-errors "1.8.1" + iconv-lite "0.4.24" + on-finished "~2.3.0" + qs "6.9.7" + raw-body "2.4.3" + type-is "~1.6.18" + + bowser@^2.8.1: + version "2.11.0" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f" + integrity sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA== + + brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + + braces@^2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== + dependencies: + arr-flatten "^1.1.0" + array-unique "^0.3.2" + extend-shallow "^2.0.1" + fill-range "^4.0.0" + isobject "^3.0.1" + repeat-element "^1.1.2" + snapdragon "^0.8.1" + snapdragon-node "^2.0.1" + split-string "^3.0.2" + to-regex "^3.0.1" + + braces@^3.0.1, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + + broadcast-channel@^3.4.1: + version "3.7.0" + resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.7.0.tgz#2dfa5c7b4289547ac3f6705f9c00af8723889937" + integrity sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg== + dependencies: + "@babel/runtime" "^7.7.2" + detect-node "^2.1.0" + js-sha3 "0.8.0" + microseconds "0.2.0" + nano-time "1.0.0" + oblivious-set "1.0.0" + rimraf "3.0.2" + unload "2.2.0" + + brorand@^1.0.1, brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + + browser-process-hrtime@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + + browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + + browserify-cipher@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + + browserify-des@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + + browserify-fs@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browserify-fs/-/browserify-fs-1.0.0.tgz#f075aa8a729d4d1716d066620e386fcc1311a96f" + integrity sha1-8HWqinKdTRcW0GZiDjhvzBMRqW8= + dependencies: + level-filesystem "^1.0.1" + level-js "^2.1.3" + levelup "^0.18.2" + + browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" + integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== + dependencies: + bn.js "^5.0.0" + randombytes "^2.0.1" + + browserify-sign@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" + integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== + dependencies: + bn.js "^5.1.1" + browserify-rsa "^4.0.1" + create-hash "^1.2.0" + create-hmac "^1.1.7" + elliptic "^6.5.3" + inherits "^2.0.4" + parse-asn1 "^5.1.5" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + + browserslist@^4.17.5: + version "4.20.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.0.tgz#35951e3541078c125d36df76056e94738a52ebe9" + integrity sha512-bnpOoa+DownbciXj0jVGENf8VYQnE2LNWomhYuCsMmmx9Jd9lwq0WXODuwpSsp8AVdKM2/HorrzxAfbKvWTByQ== + dependencies: + caniuse-lite "^1.0.30001313" + electron-to-chromium "^1.4.76" + escalade "^3.1.1" + node-releases "^2.0.2" + picocolors "^1.0.0" + + browserslist@^4.19.1, browserslist@^4.20.2: + version "4.20.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.2.tgz#567b41508757ecd904dab4d1c646c612cd3d4f88" + integrity sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA== + dependencies: + caniuse-lite "^1.0.30001317" + electron-to-chromium "^1.4.84" + escalade "^3.1.1" + node-releases "^2.0.2" + picocolors "^1.0.0" + + bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + + bs58@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" + integrity sha1-vhYedsNU9veIrkBx9j806MTwpCo= + dependencies: + base-x "^3.0.2" + + bs58check@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" + integrity sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA== + dependencies: + bs58 "^4.0.0" + create-hash "^1.1.0" + safe-buffer "^5.1.2" + + 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.6.1: + version "4.6.1" + resolved "https://registry.yarnpkg.com/bson/-/bson-4.6.1.tgz#2b5da517539bb0f7f3ffb54ac70a384ca899641c" + integrity sha512-I1LQ7Hz5zgwR4QquilLNZwbhPw0Apx7i7X9kGMBTsqPdml/03Q9NBtD9nt/19ahjlphktQImrnderxqpzeVDjw== + dependencies: + buffer "^5.6.0" + + buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== + + buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + + buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= + + buffer-equal-constant-time@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" + integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= + + buffer-equal@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-0.0.1.tgz#91bc74b11ea405bc916bc6aa908faafa5b4aac4b" + integrity sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs= + + buffer-es6@^4.9.2: + version "4.9.3" + resolved "https://registry.yarnpkg.com/buffer-es6/-/buffer-es6-4.9.3.tgz#f26347b82df76fd37e18bcb5288c4970cfd5c404" + integrity sha1-8mNHuC33b9N+GLy1KIxJcM/VxAQ= + + buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= + + buffer-from@1.x, buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + + buffer-to-arraybuffer@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz#6064a40fa76eb43c723aba9ef8f6e1216d10511a" + integrity sha1-YGSkD6dutDxyOrqe+PbhIW0QURo= + + buffer-writer@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" + integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw== + + buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= + + buffer@^5.0.5, buffer@^5.2.0, buffer@^5.2.1, buffer@^5.5.0, buffer@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + + buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + + bufferutil@^4.0.1: + version "4.0.6" + resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.6.tgz#ebd6c67c7922a0e902f053e5d8be5ec850e48433" + integrity sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw== + dependencies: + node-gyp-build "^4.3.0" + + bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + + bytes@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.1.tgz#3f018291cb4cbad9accb6e6970bca9c8889e879a" + integrity sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg== + + bytes@3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + + cache-base@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== + dependencies: + collection-visit "^1.0.0" + component-emitter "^1.2.1" + get-value "^2.0.6" + has-value "^1.0.0" + isobject "^3.0.1" + set-value "^2.0.0" + to-object-path "^0.3.0" + union-value "^1.0.0" + unset-value "^1.0.0" + + cacheable-request@^2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" + integrity sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0= + dependencies: + clone-response "1.0.2" + get-stream "3.0.0" + http-cache-semantics "3.8.1" + keyv "3.0.0" + lowercase-keys "1.0.0" + normalize-url "2.0.1" + responselike "1.0.2" + + cacheable-request@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" + integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== + dependencies: + clone-response "^1.0.2" + get-stream "^5.1.0" + http-cache-semantics "^4.0.0" + keyv "^3.0.0" + lowercase-keys "^2.0.0" + normalize-url "^4.1.0" + responselike "^1.0.2" + + call-bind@^1.0.0, call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + + callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + + camelcase-css@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" + integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== + + camelcase@^5.0.0, camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + + camelcase@^6.0.0, camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + + caniuse-lite@^1.0.30001283, caniuse-lite@^1.0.30001313: + version "1.0.30001315" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001315.tgz#f1b1efd1171ee1170d52709a7252632dacbd7c77" + integrity sha512-5v7LFQU4Sb/qvkz7JcZkvtSH1Ko+1x2kgo3ocdBeMGZSOFpuE1kkm0kpTwLtWeFrw5qw08ulLxJjVIXIS8MkiQ== + + caniuse-lite@^1.0.30001317: version "1.0.30001317" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001317.tgz#0548fb28fd5bc259a70b8c1ffdbe598037666a1b" integrity sha512-xIZLh8gBm4dqNX0gkzrBeyI86J2eCjWzYAs40q88smG844YIrN4tVQl/RhquHvKEKImWWFIVh1Lxe5n1G/N+GQ== - nanoid@^3.1.30: + capture-exit@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" + integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== + dependencies: + rsvp "^4.8.4" + + caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + + ccount@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.1.0.tgz#246687debb6014735131be8abab2d93898f8d043" + integrity sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg== + + ccount@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5" + integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg== + + chalk@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba" + integrity sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q== + dependencies: + ansi-styles "^3.1.0" + escape-string-regexp "^1.0.5" + supports-color "^4.0.0" + + chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + + chalk@^2.0.0, chalk@^2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + + 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== + + character-entities-html4@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-2.1.0.tgz#1f1adb940c971a4b22ba39ddca6b618dc6e56b2b" + integrity sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA== + + character-entities-legacy@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" + integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== + + character-entities-legacy@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz#76bc83a90738901d7bc223a9e93759fdd560125b" + integrity sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ== + + character-entities@^1.0.0: + version "1.2.4" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" + integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== + + character-entities@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.1.tgz#98724833e1e27990dee0bd0f2b8a859c3476aac7" + integrity sha512-OzmutCf2Kmc+6DrFrrPS8/tDh2+DpnrfzdICHWhcVC9eOd0N1PXmQEE1a8iM4IziIAG+8tmTq3K+oo0ubH6RRQ== + + character-reference-invalid@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" + integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== + + character-reference-invalid@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz#85c66b041e43b47210faf401278abf808ac45cb9" + integrity sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw== + + chokidar@^3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + + chownr@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== + + ci-info@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== + + ci-info@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" + integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== + + cids@^0.7.1: + version "0.7.5" + resolved "https://registry.yarnpkg.com/cids/-/cids-0.7.5.tgz#60a08138a99bfb69b6be4ceb63bfef7a396b28b2" + integrity sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA== + dependencies: + buffer "^5.5.0" + class-is "^1.1.0" + multibase "~0.6.0" + multicodec "^1.0.0" + multihashes "~0.4.15" + + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + + cjs-module-lexer@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz#4186fcca0eae175970aee870b9fe2d6cf8d5655f" + integrity sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw== + + 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== + + class-is@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/class-is/-/class-is-1.1.0.tgz#9d3c0fba0440d211d843cec3dedfa48055005825" + integrity sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw== + + class-utils@^0.3.5: + version "0.3.6" + resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== + dependencies: + arr-union "^3.1.0" + define-property "^0.2.5" + isobject "^3.0.0" + static-extend "^0.1.1" + + classnames@^2.2.5, classnames@^2.2.6, classnames@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" + integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== + + clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + + cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + + cli-highlight@^2.1.11: + version "2.1.11" + resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" + integrity sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg== + dependencies: + chalk "^4.0.0" + highlight.js "^10.7.1" + mz "^2.4.0" + parse5 "^5.1.1" + parse5-htmlparser2-tree-adapter "^6.0.0" + yargs "^16.0.0" + + cli-truncate@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" + integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== + dependencies: + slice-ansi "^3.0.0" + string-width "^4.2.0" + + cli-truncate@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-3.1.0.tgz#3f23ab12535e3d73e839bb43e73c9de487db1389" + integrity sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA== + dependencies: + slice-ansi "^5.0.0" + string-width "^5.0.0" + + clipboardy@1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-1.2.2.tgz#2ce320b9ed9be1514f79878b53ff9765420903e2" + integrity sha512-16KrBOV7bHmHdxcQiCvfUFYVFyEah4FI8vYT1Fr7CGSA4G+xBWMEfUEQJS1hxeHGtI9ju1Bzs9uXSbj5HZKArw== + dependencies: + arch "^2.1.0" + execa "^0.8.0" + + cliui@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^6.2.0" + + cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + + clone-response@1.0.2, clone-response@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" + integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= + dependencies: + mimic-response "^1.0.0" + + clone@~0.1.9: + version "0.1.19" + resolved "https://registry.yarnpkg.com/clone/-/clone-0.1.19.tgz#613fb68639b26a494ac53253e15b1a6bd88ada85" + integrity sha1-YT+2hjmyaklKxTJT4Vsaa9iK2oU= + + clsx@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" + integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== + + cluster-key-slot@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" + integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== + + co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= + + cobe@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/cobe/-/cobe-0.4.1.tgz#d79846e05700c4da2915dd9ce3ef3b9f282f9328" + integrity sha512-hXVsSFXUisSQONxkBD5YC+z73ucBCbI/0Jw1h7OOwjo001X93HpSSGkYfoidCruxbNYYss/tpT40RZ8N1VIwhw== + dependencies: + phenomenon "^1.6.0" + + code-block-writer@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-11.0.0.tgz#5956fb186617f6740e2c3257757fea79315dd7d4" + integrity sha512-GEqWvEWWsOvER+g9keO4ohFoD3ymwyCnqY3hoTr7GZipYFwEhMHJw+TtV0rfgRhNImM6QWZGO2XYjlJVyYT62w== + dependencies: + tslib "2.3.1" + + 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== + + collection-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= + dependencies: + map-visit "^1.0.0" + object-visit "^1.0.0" + + color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + + color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + + color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= + + color-name@^1.1.4, color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + + colorette@^2.0.16: + version "2.0.16" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da" + integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g== + + colors@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== + + combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + + comma-separated-tokens@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.2.tgz#d4c25abb679b7751c880be623c1179780fe1dd98" + integrity sha512-G5yTt3KQN4Yn7Yk4ed73hlZ1evrFKXeUW3086p3PRFNp7m2vIjI6Pg+Kgb+oyzhd9F2qdcoj67+y3SdxL5XWsg== + + commander@8.3.0, commander@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" + integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== + + commander@^2.8.1: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + + commander@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" + integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== + + commander@^6.2.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" + integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== + + component-emitter@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== + + concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + + concat-stream@^1.4.4: + version "1.6.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== + dependencies: + buffer-from "^1.0.0" + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + + content-disposition@0.5.4, content-disposition@^0.5.2, content-disposition@^0.5.3: + version "0.5.4" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + + content-hash@^2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/content-hash/-/content-hash-2.5.2.tgz#bbc2655e7c21f14fd3bfc7b7d4bfe6e454c9e211" + integrity sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw== + dependencies: + cids "^0.7.1" + multicodec "^0.5.5" + multihashes "^0.4.15" + + content-type@1.0.4, content-type@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" + integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + + convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + + cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + + cookie@0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" + integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== + + cookie@0.4.2, cookie@^0.4.1: + version "0.4.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" + integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== + + cookiejar@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.3.tgz#fc7a6216e408e74414b90230050842dacda75acc" + integrity sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ== + + copy-descriptor@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= + + core-js-compat@^3.20.2, core-js-compat@^3.21.0: + version "3.21.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.21.1.tgz#cac369f67c8d134ff8f9bd1623e3bc2c42068c82" + integrity sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g== + dependencies: + browserslist "^4.19.1" + semver "7.0.0" + + core-js-pure@^3.20.2: + version "3.21.1" + resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.21.1.tgz#8c4d1e78839f5f46208de7230cebfb72bc3bdb51" + integrity sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ== + + core-js@^3: + version "3.21.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.21.1.tgz#f2e0ddc1fc43da6f904706e8e955bc19d06a0d94" + integrity sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig== + + core-util-is@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + + core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + + cors@2.8.5, cors@^2.8.1: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + + cosmiconfig@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" + integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.1.0" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.7.2" + + cosmiconfig@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" + integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== + dependencies: + "@types/parse-json" "^4.0.0" + import-fresh "^3.2.1" + parse-json "^5.0.0" + path-type "^4.0.0" + yaml "^1.10.0" + + country-flag-icons@^1.0.2: + version "1.4.21" + resolved "https://registry.yarnpkg.com/country-flag-icons/-/country-flag-icons-1.4.21.tgz#0c00f57894890f5f41c8b632bcf5293cce80af02" + integrity sha512-bA9jDr+T5li7EsKdDx0xVnO0bdMdoT8IA3BNbeT2XSWUygR1okhiZ2+eYiC1EKLrFZhI4aEHni2w03lUlOjogg== + + crc-32@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.1.tgz#436d2bcaad27bcb6bd073a2587139d3024a16460" + integrity sha512-Dn/xm/1vFFgs3nfrpEVScHoIslO9NZRITWGz/1E/St6u4xw99vfZzVkW0OSnzx2h9egej9xwMCEut6sqwokM/w== + dependencies: + exit-on-epipe "~1.0.1" + printj "~1.3.1" + + create-ecdh@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" + integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== + dependencies: + bn.js "^4.1.0" + elliptic "^6.5.3" + + create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + + create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + + create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + + cross-fetch@3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" + integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== + dependencies: + node-fetch "2.6.7" + + cross-spawn@7.0.3, cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + + cross-spawn@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + + cross-spawn@^6.0.0, cross-spawn@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== + dependencies: + nice-try "^1.0.4" + path-key "^2.0.1" + semver "^5.5.0" + shebang-command "^1.2.0" + which "^1.2.9" + + crypto-browserify@3.12.0, crypto-browserify@^3.11.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + randomfill "^1.0.3" + + cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + + cssom@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" + integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== + + cssom@~0.3.6: + version "0.3.8" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== + + cssstyle@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== + dependencies: + cssom "~0.3.6" + + csstype@^3.0.2, csstype@^3.0.4: + version "3.0.11" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33" + integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw== + + d@1, d@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" + integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== + dependencies: + es5-ext "^0.10.50" + type "^1.0.1" + + damerau-levenshtein@^1.0.7: + version "1.0.8" + resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" + integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== + + dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + dependencies: + assert-plus "^1.0.0" + + data-urls@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== + dependencies: + abab "^2.0.3" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" + + dayjs-business-time@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/dayjs-business-time/-/dayjs-business-time-1.0.4.tgz#2970b80e832e92bbaa27a06ea62772b0d970b75b" + integrity sha512-v/0ynVV0Ih9Qw/pqJdScVHfoIaHkxLSom8j9+jO+VUOPnxC0fj5QGpDAZ94LUFd7jBkq2UO8C1LrVY+EHFx3aA== + dependencies: + dayjs "^1.10.4" + + dayjs@^1.10.4: + version "1.10.8" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.8.tgz#267df4bc6276fcb33c04a6735287e3f429abec41" + integrity sha512-wbNwDfBHHur9UOzNUjeKUOJ0fCb0a52Wx0xInmQ7Y8FstyajiV1NmK1e00cxsr9YrE9r7yAChE0VvpuY5Rnlow== + + debounce@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" + integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== + + debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: + version "2.6.9" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + + debug@4, debug@4.3.3, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@~4.3.1: + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + dependencies: + ms "2.1.2" + + debug@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + + decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + + decimal.js@^10.2.1: + version "10.3.1" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" + integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== + + decode-named-character-reference@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.0.1.tgz#57b2bd9112659cacbc449d3577d7dadb8e1f3d1b" + integrity sha512-YV/0HQHreRwKb7uBopyIkLG17jG6Sv2qUchk9qSoVJ2f+flwRsPNBO0hAnjt6mTNYUT+vw9Gy2ihXg4sUWPi2w== + dependencies: + character-entities "^2.0.0" + + decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + + decompress-response@^3.2.0, decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= + dependencies: + mimic-response "^1.0.0" + + decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1" + integrity sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ== + dependencies: + file-type "^5.2.0" + is-stream "^1.1.0" + tar-stream "^1.5.2" + + decompress-tarbz2@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b" + integrity sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A== + dependencies: + decompress-tar "^4.1.0" + file-type "^6.1.0" + is-stream "^1.1.0" + seek-bzip "^1.0.5" + unbzip2-stream "^1.0.9" + + decompress-targz@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee" + integrity sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w== + dependencies: + decompress-tar "^4.1.1" + file-type "^5.2.0" + is-stream "^1.1.0" + + decompress-unzip@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69" + integrity sha1-3qrM39FK6vhVePczroIQ+bSEj2k= + dependencies: + file-type "^3.8.0" + get-stream "^2.2.0" + pify "^2.3.0" + yauzl "^2.4.2" + + decompress@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/decompress/-/decompress-4.2.1.tgz#007f55cc6a62c055afa37c07eb6a4ee1b773f118" + integrity sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ== + dependencies: + decompress-tar "^4.0.0" + decompress-tarbz2 "^4.0.0" + decompress-targz "^4.0.0" + decompress-unzip "^4.0.1" + graceful-fs "^4.1.10" + make-dir "^1.0.0" + pify "^2.3.0" + strip-dirs "^2.0.0" + + dedent@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" + integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= + + deep-is@^0.1.3, deep-is@~0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + + deepmerge@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== + + defer-to-connect@^1.0.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" + integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== + + deferred-leveldown@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-0.2.0.tgz#2cef1f111e1c57870d8bbb8af2650e587cd2f5b4" + integrity sha1-LO8fER4cV4cNi7uK8mUOWHzS9bQ= + dependencies: + abstract-leveldown "~0.12.1" + + define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + + define-properties@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" + integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== + dependencies: + object-keys "^1.0.12" + + define-property@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= + dependencies: + is-descriptor "^0.1.0" + + define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= + dependencies: + is-descriptor "^1.0.0" + + define-property@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== + dependencies: + is-descriptor "^1.0.2" + isobject "^3.0.1" + + defined@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM= + + delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + + denque@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/denque/-/denque-2.0.1.tgz#bcef4c1b80dc32efe97515744f21a4229ab8934a" + integrity sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ== + + depd@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" + integrity sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k= + + depd@^1.1.0, depd@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + + dequal@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.2.tgz#85ca22025e3a87e65ef75a7a437b35284a7e319d" + integrity sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug== + + des.js@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" + integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + + destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + + detect-browser@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.3.0.tgz#9705ef2bddf46072d0f7265a1fe300e36fe7ceca" + integrity sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w== + + detect-element-overflow@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/detect-element-overflow/-/detect-element-overflow-1.2.0.tgz#86e504292ffedc3aef813395fbdf0261aaf6afa9" + integrity sha512-Jtr9ivYPhpd9OJux+hjL0QjUKiS1Ghgy8tvIufUjFslQgIWvgGr4mn57H190APbKkiOmXnmtMI6ytaKzMusecg== + + 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== + + detect-node-es@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" + integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== + + detect-node@^2.0.4, detect-node@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" + integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== + + detective@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.0.tgz#feb2a77e85b904ecdea459ad897cc90a99bd2a7b" + integrity sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg== + dependencies: + acorn-node "^1.6.1" + defined "^1.0.0" + minimist "^1.1.1" + + didyoumean@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" + integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== + + diff-sequences@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" + integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== + + diff-sequences@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" + integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== + + diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + + diff@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + + diffie-hellman@^5.0.0: + version "5.0.3" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + + dijkstrajs@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.2.tgz#2e48c0d3b825462afe75ab4ad5e829c8ece36257" + integrity sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg== + + dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + + dlv@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" + integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== + + doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + + doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + + dom-helpers@^5.0.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" + integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== + dependencies: + "@babel/runtime" "^7.8.7" + csstype "^3.0.2" + + dom-walk@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" + integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== + + domexception@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== + dependencies: + webidl-conversions "^5.0.0" + + dotenv@^8.2.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" + integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== + + download@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/download/-/download-8.0.0.tgz#afc0b309730811731aae9f5371c9f46be73e51b1" + integrity sha512-ASRY5QhDk7FK+XrQtQyvhpDKanLluEEQtWl/J7Lxuf/b+i8RYh997QeXvL85xitrmRKVlx9c7eTrcRdq2GS4eA== + dependencies: + archive-type "^4.0.0" + content-disposition "^0.5.2" + decompress "^4.2.1" + ext-name "^5.0.0" + file-type "^11.1.0" + filenamify "^3.0.0" + get-stream "^4.1.0" + got "^8.3.1" + make-dir "^2.1.0" + p-event "^2.1.0" + pify "^4.0.1" + + duplexer3@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" + integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= + + duplexer@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== + + eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + + ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + + ecdsa-sig-formatter@1.0.11, ecdsa-sig-formatter@^1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" + integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== + dependencies: + safe-buffer "^5.0.1" + + ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + + electron-to-chromium@^1.4.76: + version "1.4.82" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.82.tgz#51e123ca434b1eba8c434ece2b54f095b304a651" + integrity sha512-Ks+ANzLoIrFDUOJdjxYMH6CMKB8UQo5modAwvSZTxgF+vEs/U7G5IbWFUp6dS4klPkTDVdxbORuk8xAXXhMsWw== + + electron-to-chromium@^1.4.84: + version "1.4.85" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.85.tgz#a3666ba42147026b9f34d4d8d4caf0740e80f751" + integrity sha512-K9AsQ41WS2bjZUFpRWfvaS4RjEcRCamEkBJN1Z1TQILBfP1H8QnJ9ti0wiLiMv0sRjX3EHKzgs9jDnmGFx2jXg== + + elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.3, elliptic@^6.5.4: + version "6.5.4" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + + emittery@^0.7.1: + version "0.7.2" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" + integrity sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ== + + emittery@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" + integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== + + emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + + emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + + emojis-list@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== + + encode-utf8@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/encode-utf8/-/encode-utf8-1.0.3.tgz#f30fdd31da07fb596f281beb2f6b027851994cda" + integrity sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw== + + encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" + integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + + end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.4: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + + enhanced-resolve@^5.7.0: + version "5.9.2" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz#0224dcd6a43389ebfb2d55efee517e5466772dd9" + integrity sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + + env-cmd@10.1.0, env-cmd@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/env-cmd/-/env-cmd-10.1.0.tgz#c7f5d3b550c9519f137fdac4dd8fb6866a8c8c4b" + integrity sha512-mMdWTT9XKN7yNth/6N6g2GuKuJTsKMDHlQFUDacb/heQRRWOTIZ42t1rMHnQu4jYxU1ajdTeJM+9eEETlqToMA== + dependencies: + commander "^4.0.0" + cross-spawn "^7.0.0" + + errno@^0.1.1, errno@~0.1.1: + version "0.1.8" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" + integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== + dependencies: + prr "~1.0.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.18.5, es-abstract@^1.19.0, es-abstract@^1.19.1: + version "1.19.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" + integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.1.1" + get-symbol-description "^1.0.0" + has "^1.0.3" + has-symbols "^1.0.2" + internal-slot "^1.0.3" + is-callable "^1.2.4" + is-negative-zero "^2.0.1" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.1" + is-string "^1.0.7" + is-weakref "^1.0.1" + object-inspect "^1.11.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.4" + string.prototype.trimstart "^1.0.4" + unbox-primitive "^1.0.1" + + es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" + + es5-ext@^0.10.35, es5-ext@^0.10.50: + version "0.10.58" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.58.tgz#5b97d94236285fb87c8ffc782cf42eb0a25d2ae0" + integrity sha512-LHO+KBBaHGwjy32ibSaMY+ZzjpC4K4I5bPoijICMBL7gXEXfrEUrzssmNP+KigbQEp1dRUnGkry/vUnxOqptLQ== + dependencies: + es6-iterator "^2.0.3" + es6-symbol "^3.1.3" + next-tick "^1.1.0" + + es6-iterator@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" + integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= + dependencies: + d "1" + es5-ext "^0.10.35" + es6-symbol "^3.1.1" + + es6-symbol@^3.1.1, es6-symbol@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" + integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== + dependencies: + d "^1.0.1" + ext "^1.1.2" + + escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + + escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + + escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity 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" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + + escodegen@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" + integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + + eslint-config-next@^12.0.8: + version "12.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-12.1.0.tgz#8ace680dc5207e6ab6c915f3989adec122f582e7" + integrity sha512-tBhuUgoDITcdcM7xFvensi9I5WTI4dnvH4ETGRg1U8ZKpXrZsWQFdOKIDzR3RLP5HR3xXrLviaMM4c3zVoE/pA== + dependencies: + "@next/eslint-plugin-next" "12.1.0" + "@rushstack/eslint-patch" "^1.0.8" + "@typescript-eslint/parser" "^5.0.0" + eslint-import-resolver-node "^0.3.4" + eslint-import-resolver-typescript "^2.4.0" + eslint-plugin-import "^2.25.2" + eslint-plugin-jsx-a11y "^6.5.1" + eslint-plugin-react "^7.27.0" + eslint-plugin-react-hooks "^4.3.0" + + eslint-config-prettier@^8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz#5a81680ec934beca02c7b1a61cf8ca34b66feab1" + integrity sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q== + + eslint-import-resolver-node@^0.3.4, eslint-import-resolver-node@^0.3.6: + version "0.3.6" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" + integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== + dependencies: + debug "^3.2.7" + resolve "^1.20.0" + + eslint-import-resolver-typescript@^2.4.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.5.0.tgz#07661966b272d14ba97f597b51e1a588f9722f0a" + integrity sha512-qZ6e5CFr+I7K4VVhQu3M/9xGv9/YmwsEXrsm3nimw8vWaVHRDrQRp26BgCypTxBp3vUp4o5aVEJRiy0F2DFddQ== + dependencies: + debug "^4.3.1" + glob "^7.1.7" + is-glob "^4.0.1" + resolve "^1.20.0" + tsconfig-paths "^3.9.0" + + eslint-module-utils@2.7.3, eslint-module-utils@^2.7.2: + version "2.7.3" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee" + integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ== + dependencies: + debug "^3.2.7" + find-up "^2.1.0" + + eslint-plugin-import@^2.25.2: + version "2.25.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz#322f3f916a4e9e991ac7af32032c25ce313209f1" + integrity sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA== + dependencies: + array-includes "^3.1.4" + array.prototype.flat "^1.2.5" + debug "^2.6.9" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.6" + eslint-module-utils "^2.7.2" + has "^1.0.3" + is-core-module "^2.8.0" + is-glob "^4.0.3" + minimatch "^3.0.4" + object.values "^1.1.5" + resolve "^1.20.0" + tsconfig-paths "^3.12.0" + + eslint-plugin-jsx-a11y@^6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz#cdbf2df901040ca140b6ec14715c988889c2a6d8" + integrity sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g== + dependencies: + "@babel/runtime" "^7.16.3" + aria-query "^4.2.2" + array-includes "^3.1.4" + ast-types-flow "^0.0.7" + axe-core "^4.3.5" + axobject-query "^2.2.0" + damerau-levenshtein "^1.0.7" + emoji-regex "^9.2.2" + has "^1.0.3" + jsx-ast-utils "^3.2.1" + language-tags "^1.0.5" + minimatch "^3.0.4" + + eslint-plugin-playwright@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-playwright/-/eslint-plugin-playwright-0.8.0.tgz#7aa3729c7d841d82c5279772000c69b1262f8e43" + integrity sha512-9uJH25m6H3jwU5O7bHD5M8cLx46L72EnIUe3dZqTox6M+WzOFzeUWaDJHHCdLGXZ8XlAU4mbCZnP7uhjKepfRA== + + eslint-plugin-prettier@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz#8b99d1e4b8b24a762472b4567992023619cb98e0" + integrity sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ== + dependencies: + prettier-linter-helpers "^1.0.0" + + eslint-plugin-react-hooks@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz#318dbf312e06fab1c835a4abef00121751ac1172" + integrity sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA== + + eslint-plugin-react@^7.27.0: + version "7.29.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.29.3.tgz#f4eab757f2756d25d6d4c2a58a9e20b004791f05" + integrity sha512-MzW6TuCnDOcta67CkpDyRfRsEVx9FNMDV8wZsDqe1luHPdGTrQIUaUXD27Ja3gHsdOIs/cXzNchWGlqm+qRVRg== + dependencies: + array-includes "^3.1.4" + array.prototype.flatmap "^1.2.5" + doctrine "^2.1.0" + estraverse "^5.3.0" + jsx-ast-utils "^2.4.1 || ^3.0.0" + minimatch "^3.1.2" + object.entries "^1.1.5" + object.fromentries "^2.0.5" + object.hasown "^1.1.0" + object.values "^1.1.5" + prop-types "^15.8.1" + resolve "^2.0.0-next.3" + semver "^6.3.0" + string.prototype.matchall "^4.0.6" + + eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + + eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + + eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + + eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + + eslint@^8.10.0: + version "8.11.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.11.0.tgz#88b91cfba1356fc10bb9eb592958457dfe09fb37" + integrity sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA== + dependencies: + "@eslint/eslintrc" "^1.2.1" + "@humanwhocodes/config-array" "^0.9.2" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.1.1" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.3.0" + espree "^9.3.1" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^6.0.1" + globals "^13.6.0" + ignore "^5.2.0" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.0.4" + natural-compare "^1.4.0" + optionator "^0.9.1" + regexpp "^3.2.0" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + + espree@^9.3.1: + version "9.3.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.1.tgz#8793b4bc27ea4c778c19908e0719e7b8f4115bcd" + integrity sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ== + dependencies: + acorn "^8.7.0" + acorn-jsx "^5.3.1" + eslint-visitor-keys "^3.3.0" + + esprima@^4.0.0, esprima@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + + esquery@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + dependencies: + estraverse "^5.1.0" + + esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + + estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + + estree-util-attach-comments@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/estree-util-attach-comments/-/estree-util-attach-comments-2.0.0.tgz#2c06d484dfcf841b5946bcb84d5412cbcd544e22" + integrity sha512-kT9YVRvlt2ewPp9BazfIIgXMGsXOEpOm57bK8aa4F3eOEndMml2JAETjWaG3SZYHmC6axSNIzHGY718dYwIuVg== + dependencies: + "@types/estree" "^0.0.46" + + estree-util-build-jsx@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/estree-util-build-jsx/-/estree-util-build-jsx-2.0.0.tgz#4903e2a923ebc791f86e78ec3687d01715dec902" + integrity sha512-d49hPGqBCJF/bF06g1Ywg7zjH1mrrUdPPrixBlKBxcX4WvMYlUUJ8BkrwlzWc8/fm6XqGgk5jilhgeZBDEGwOQ== + dependencies: + "@types/estree-jsx" "^0.0.1" + estree-util-is-identifier-name "^2.0.0" + estree-walker "^3.0.0" + + estree-util-is-identifier-name@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/estree-util-is-identifier-name/-/estree-util-is-identifier-name-2.0.0.tgz#e2d3d2ae3032c017b2112832bfc5d8ba938c8010" + integrity sha512-aXXZFVMnBBDRP81vS4YtAYJ0hUkgEsXea7lNKWCOeaAquGb1Jm2rcONPB5fpzwgbNxulTvrWuKnp9UElUGAKeQ== + + estree-util-visit@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/estree-util-visit/-/estree-util-visit-1.1.0.tgz#c0ea7942c40ac7889a77b57a11e92f987744bc6f" + integrity sha512-3lXJ4Us9j8TUif9cWcQy81t9p5OLasnDuuhrFiqb+XstmKC1d1LmrQWYsY49/9URcfHE64mPypDBaNK9NwWDPQ== + dependencies: + "@types/estree-jsx" "^0.0.1" + "@types/unist" "^2.0.0" + + estree-walker@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" + integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== + + estree-walker@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + + estree-walker@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.1.tgz#c2a9fb4a30232f5039b7c030b37ead691932debd" + integrity sha512-woY0RUD87WzMBUiZLx8NsYr23N5BKsOMZHhu2hoNRVh6NXGfoiT1KOL8G3UHlJAnEDGmfa5ubNA/AacfG+Kb0g== + + esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + + etag@~1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + + eth-ens-namehash@2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz#229ac46eca86d52e0c991e7cb2aef83ff0f68bcf" + integrity sha1-IprEbsqG1S4MmR58sq74P/D2i88= + dependencies: + idna-uts46-hx "^2.3.1" + js-sha3 "^0.5.7" + + eth-lib@0.2.8: + version "0.2.8" + resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.8.tgz#b194058bef4b220ad12ea497431d6cb6aa0623c8" + integrity sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw== + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + xhr-request-promise "^0.1.2" + + eth-lib@^0.1.26: + version "0.1.29" + resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.1.29.tgz#0c11f5060d42da9f931eab6199084734f4dbd1d9" + integrity sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ== + dependencies: + bn.js "^4.11.6" + elliptic "^6.4.0" + nano-json-stream-parser "^0.1.2" + servify "^0.1.12" + ws "^3.0.0" + xhr-request-promise "^0.1.2" + + eth-rpc-errors@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/eth-rpc-errors/-/eth-rpc-errors-4.0.3.tgz#6ddb6190a4bf360afda82790bb7d9d5e724f423a" + integrity sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg== + dependencies: + fast-safe-stringify "^2.0.6" + + ethereum-bloom-filters@^1.0.6: + version "1.0.10" + resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz#3ca07f4aed698e75bd134584850260246a5fed8a" + integrity sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA== + dependencies: + js-sha3 "^0.8.0" + + ethereum-cryptography@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz#8d6143cfc3d74bf79bbd8edecdf29e4ae20dd191" + integrity sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ== + dependencies: + "@types/pbkdf2" "^3.0.0" + "@types/secp256k1" "^4.0.1" + blakejs "^1.1.0" + browserify-aes "^1.2.0" + bs58check "^2.1.2" + create-hash "^1.2.0" + create-hmac "^1.1.7" + hash.js "^1.1.7" + keccak "^3.0.0" + pbkdf2 "^3.0.17" + randombytes "^2.1.0" + safe-buffer "^5.1.2" + scrypt-js "^3.0.0" + secp256k1 "^4.0.1" + setimmediate "^1.0.5" + + ethereumjs-util@^7.0.10, ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.4: + version "7.1.4" + resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.4.tgz#a6885bcdd92045b06f596c7626c3e89ab3312458" + integrity sha512-p6KmuPCX4mZIqsQzXfmSx9Y0l2hqf+VkAiwSisW3UKUFdk8ZkAt+AYaor83z2nSi6CU2zSsXMlD80hAbNEGM0A== + dependencies: + "@types/bn.js" "^5.1.0" + bn.js "^5.1.2" + create-hash "^1.1.2" + ethereum-cryptography "^0.1.3" + rlp "^2.2.4" + + ethjs-unit@0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" + integrity sha1-xmWSHkduh7ziqdWIpv4EBbLEFpk= + dependencies: + bn.js "4.11.6" + number-to-bn "1.7.0" + + event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + + eventemitter3@4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" + integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ== + + events@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + + evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + + exec-sh@^0.3.2: + version "0.3.6" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" + integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w== + + execa@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da" + integrity sha1-2NdrvBtVIX7RkP1t1J08d07PyNo= + dependencies: + cross-spawn "^5.0.1" + get-stream "^3.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + + execa@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== + dependencies: + cross-spawn "^6.0.0" + get-stream "^4.0.0" + is-stream "^1.1.0" + npm-run-path "^2.0.0" + p-finally "^1.0.0" + signal-exit "^3.0.0" + strip-eof "^1.0.0" + + execa@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" + integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + + execa@^5.0.0, execa@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + + exif-parser@^0.1.12: + version "0.1.12" + resolved "https://registry.yarnpkg.com/exif-parser/-/exif-parser-0.1.12.tgz#58a9d2d72c02c1f6f02a0ef4a9166272b7760922" + integrity sha1-WKnS1ywCwfbwKg70qRZicrd2CSI= + + exit-on-epipe@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692" + integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw== + + exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= + + expand-brackets@^2.1.4: + version "2.1.4" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= + dependencies: + debug "^2.3.3" + define-property "^0.2.5" + extend-shallow "^2.0.1" + posix-character-classes "^0.1.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + + expect@27.2.5: + version "27.2.5" + resolved "https://registry.yarnpkg.com/expect/-/expect-27.2.5.tgz#16154aaa60b4d9a5b0adacfea3e4d6178f4b93fd" + integrity sha512-ZrO0w7bo8BgGoP/bLz+HDCI+0Hfei9jUSZs5yI/Wyn9VkG9w8oJ7rHRgYj+MA7yqqFa0IwHA3flJzZtYugShJA== + dependencies: + "@jest/types" "^27.2.5" + ansi-styles "^5.0.0" + jest-get-type "^27.0.6" + jest-matcher-utils "^27.2.5" + jest-message-util "^27.2.5" + jest-regex-util "^27.0.6" + + expect@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" + integrity sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA== + dependencies: + "@jest/types" "^26.6.2" + ansi-styles "^4.0.0" + jest-get-type "^26.3.0" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-regex-util "^26.0.0" + + expect@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/expect/-/expect-27.5.1.tgz#83ce59f1e5bdf5f9d2b94b61d2050db48f3fef74" + integrity sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw== + dependencies: + "@jest/types" "^27.5.1" + jest-get-type "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + + express@4.17.2: + version "4.17.2" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.2.tgz#c18369f265297319beed4e5558753cc8c1364cb3" + integrity sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg== + dependencies: + accepts "~1.3.7" + array-flatten "1.1.1" + body-parser "1.19.1" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.4.1" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.9.6" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.17.2" + serve-static "1.14.2" + setprototypeof "1.2.0" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + + express@^4.14.0: + version "4.17.3" + resolved "https://registry.yarnpkg.com/express/-/express-4.17.3.tgz#f6c7302194a4fb54271b73a1fe7a06478c8f85a1" + integrity sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.19.2" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.4.2" + cookie-signature "1.0.6" + debug "2.6.9" + depd "~1.1.2" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "~1.1.2" + fresh "0.5.2" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.9.7" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.17.2" + serve-static "1.14.2" + setprototypeof "1.2.0" + statuses "~1.5.0" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + + ext-list@^2.0.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37" + integrity sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA== + dependencies: + mime-db "^1.28.0" + + ext-name@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/ext-name/-/ext-name-5.0.0.tgz#70781981d183ee15d13993c8822045c506c8f0a6" + integrity sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ== + dependencies: + ext-list "^2.0.0" + sort-keys-length "^1.0.0" + + ext@^1.1.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/ext/-/ext-1.6.0.tgz#3871d50641e874cc172e2b53f919842d19db4c52" + integrity sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg== + dependencies: + type "^2.5.0" + + extend-shallow@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= + dependencies: + is-extendable "^0.1.0" + + extend-shallow@^3.0.0, extend-shallow@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= + dependencies: + assign-symbols "^1.0.0" + is-extendable "^1.0.1" + + extend@^3.0.0, extend@^3.0.2, extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + + extension-port-stream@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extension-port-stream/-/extension-port-stream-2.0.1.tgz#d374820c581418c2275d3c4439ade0b82c4cfac6" + integrity sha512-ltrv4Dh/979I04+D4Te6TFygfRSOc5EBzzlHRldWMS8v73V80qWluxH88hqF0qyUsBXTb8NmzlmSipcre6a+rg== + dependencies: + webextension-polyfill-ts "^0.22.0" + + extglob@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== + dependencies: + array-unique "^0.3.2" + define-property "^1.0.0" + expand-brackets "^2.1.4" + extend-shallow "^2.0.1" + fragment-cache "^0.2.1" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + + extract-zip@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" + integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== + dependencies: + debug "^4.1.1" + get-stream "^5.1.0" + yauzl "^2.10.0" + optionalDependencies: + "@types/yauzl" "^2.9.1" + + extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + + extsprintf@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" + integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== + + fast-deep-equal@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" + integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= + + fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + + fast-diff@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + + fast-equals@^1.6.3: + version "1.6.3" + resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-1.6.3.tgz#84839a1ce20627c463e1892f2ae316380c81b459" + integrity sha512-4WKW0AL5+WEqO0zWavAfYGY1qwLsBgE//DN4TTcVEN2UlINgkv9b3vm2iHicoenWKSX9mKWmGOsU/iI5IST7pQ== + + fast-glob@^3.2.11, fast-glob@^3.2.7, fast-glob@^3.2.9: + version "3.2.11" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + + fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + + fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + + fast-safe-stringify@^2.0.6: + version "2.1.1" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" + integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== + + fast-text-encoding@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz#ec02ac8e01ab8a319af182dae2681213cfe9ce53" + integrity sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig== + + fastq@^1.6.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" + integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== + dependencies: + reusify "^1.0.4" + + 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" + + fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= + dependencies: + pend "~1.2.0" + + file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + + file-type@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-11.1.0.tgz#93780f3fed98b599755d846b99a1617a2ad063b8" + integrity sha512-rM0UO7Qm9K7TWTtA6AShI/t7H5BPjDeGVDaNyg9BjHAj3PysKy7+8C8D137R88jnR3rFJZQB/tFgydl5sN5m7g== + + file-type@^3.8.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" + integrity sha1-JXoHg4TR24CHvESdEH1SpSZyuek= + + file-type@^4.2.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-4.4.0.tgz#1b600e5fca1fbdc6e80c0a70c71c8dba5f7906c5" + integrity sha1-G2AOX8ofvcboDApwxxyNul95BsU= + + file-type@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6" + integrity sha1-LdvqfHP/42No365J3DOMBYwritY= + + file-type@^6.1.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919" + integrity sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg== + + file-type@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/file-type/-/file-type-9.0.0.tgz#a68d5ad07f486414dfb2c8866f73161946714a18" + integrity sha512-Qe/5NJrgIOlwijpq3B7BEpzPFcgzggOTagZmkXQY4LA6bsXKTUstK7Wp12lEJ/mLKTpvIZxmIuRcLYWT6ov9lw== + + filename-reserved-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229" + integrity sha1-q/c9+rc10EVECr/qLZHzieu/oik= + + filenamify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-3.0.0.tgz#9603eb688179f8c5d40d828626dcbb92c3a4672c" + integrity sha512-5EFZ//MsvJgXjBAFJ+Bh2YaCTRF/VP1YOmGrgt+KJ4SFRLjI87EIdwLLuT6wQX0I4F9W41xutobzczjsOKlI/g== + dependencies: + filename-reserved-regex "^2.0.0" + strip-outer "^1.0.0" + trim-repeated "^1.0.0" + + fill-range@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= + dependencies: + extend-shallow "^2.0.1" + is-number "^3.0.0" + repeat-string "^1.6.1" + to-regex-range "^2.1.0" + + fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + + finalhandler@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" + integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.3" + 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-root@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" + integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== + + find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= + dependencies: + locate-path "^2.0.0" + + find-up@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== + dependencies: + locate-path "^3.0.0" + + find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + + flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + + flatted@^3.1.0: + version "3.2.5" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" + integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== + + focus-visible@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/focus-visible/-/focus-visible-5.2.0.tgz#3a9e41fccf587bd25dcc2ef045508284f0a4d6b3" + integrity sha512-Rwix9pBtC1Nuy5wysTmKy+UjbDJpIfg8eHjw0rjZ1mX4GNLz1Bmd16uDpI3Gk1i70Fgcs8Csg2lPm8HULFg9DQ== + + for-in@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= + + foreach@^2.0.5, foreach@~2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= + + forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + + form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + + form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + + forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + + fraction.js@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" + integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== + + fragment-cache@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= + dependencies: + map-cache "^0.2.2" + + fresh@0.5.2, fresh@^0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" + integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + + from2@^2.1.1: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + + fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + + fs-extra@^4.0.2: + version "4.0.3" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" + integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + + fs-extra@^8.0.1: + version "8.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^4.0.0" + universalify "^0.1.0" + + fs-minipass@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" + integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== + dependencies: + minipass "^2.6.0" + + fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + + fsevents@^2.1.2, fsevents@^2.3.2, fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + + function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + + functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= + + fwd-stream@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/fwd-stream/-/fwd-stream-1.0.4.tgz#ed281cabed46feecf921ee32dc4c50b372ac7cfa" + integrity sha1-7Sgcq+1G/uz5Ie4y3ExQs3KsfPo= + dependencies: + readable-stream "~1.0.26-4" + + gaxios@^4.0.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/gaxios/-/gaxios-4.3.2.tgz#845827c2dc25a0213c8ab4155c7a28910f5be83f" + integrity sha512-T+ap6GM6UZ0c4E6yb1y/hy2UB6hTrqhglp3XfmU9qbLCGRYhLVV5aRPpC4EmoG8N8zOnkYCgoBz+ScvGAARY6Q== + dependencies: + abort-controller "^3.0.0" + extend "^3.0.2" + https-proxy-agent "^5.0.0" + is-stream "^2.0.0" + node-fetch "^2.6.1" + + gcp-metadata@^4.2.0: + version "4.3.1" + resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-4.3.1.tgz#fb205fe6a90fef2fd9c85e6ba06e5559ee1eefa9" + integrity sha512-x850LS5N7V1F3UcV7PoupzGsyD6iVwTVvsh3tbXfkctZnBnjW5yu5z1/3k3SehF7TyoTIe78rJs02GMMy+LF+A== + dependencies: + gaxios "^4.0.0" + json-bigint "^1.0.0" + + generate-function@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" + integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ== + dependencies: + is-property "^1.0.2" + + generic-pool@3.8.2: + version "3.8.2" + resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.8.2.tgz#aab4f280adb522fdfbdc5e5b64d718d3683f04e9" + integrity sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg== + + gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + + get-caller-file@^2.0.1, get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + + get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + + get-nonce@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3" + integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q== + + 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@3.0.0, get-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" + integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= + + get-stream@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" + integrity sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4= + dependencies: + object-assign "^4.0.1" + pinkie-promise "^2.0.0" + + get-stream@^4.0.0, get-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== + dependencies: + pump "^3.0.0" + + get-stream@^5.0.0, get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + + get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + + get-symbol-description@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" + integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.1" + + get-user-locale@^1.2.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/get-user-locale/-/get-user-locale-1.4.0.tgz#a2c4b5da46feec9f03c9b07d197b1620490a5370" + integrity sha512-gQo03lP1OArHLKlnoglqrGGl7b04u2EP9Xutmp72cMdtrrSD7ZgIsCsUKZynYWLDkVJW33Cj3pliP7uP0UonHQ== + dependencies: + lodash.once "^4.1.1" + + get-value@^2.0.3, get-value@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= + + getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + dependencies: + assert-plus "^1.0.0" + + gifwrap@^0.9.2: + version "0.9.3" + resolved "https://registry.yarnpkg.com/gifwrap/-/gifwrap-0.9.3.tgz#66d939219bb038d19745abf6024a8ab231786bdb" + integrity sha512-HSLpe3qhAdAoIBbwuTjKnxMGemj80uRpr55IhDv1Xf25h1E0SrKr8nIBFXysKUlYm8ZCkDhAuvX7/hRQnE9rLw== + dependencies: + image-q "^1.1.1" + omggif "^1.0.10" + + github-slugger@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-1.4.0.tgz#206eb96cdb22ee56fdc53a28d5a302338463444e" + integrity sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ== + + glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + + glob-parent@^6.0.1, glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + + glob@7.1.7: + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + + glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.1.7: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + + global@~4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" + integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== + dependencies: + min-document "^2.19.0" + process "^0.11.10" + + globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + + globals@^13.6.0, globals@^13.9.0: + version "13.13.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.13.0.tgz#ac32261060d8070e2719dd6998406e27d2b5727b" + integrity sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A== + dependencies: + type-fest "^0.20.2" + + globby@^11.0.4: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + + goober@^2.1.1: + version "2.1.8" + resolved "https://registry.yarnpkg.com/goober/-/goober-2.1.8.tgz#e592c04d093cb38f77b38cfcb012b7811c85765e" + integrity sha512-S0C85gCzcfFCMSdjD/CxyQMt1rbf2qEg6hmDzxk2FfD7+7Ogk55m8ZFUMtqNaZM4VVX/qaU9AzSORG+Gf4ZpAQ== + + google-auth-library@^7.0.2, google-auth-library@^7.14.0: + version "7.14.0" + resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-7.14.0.tgz#9d6a20592f7b4d4c463cd3e93934c4b1711d5dc6" + integrity sha512-or8r7qUqGVI3W8lVSdPh0ZpeFyQHeE73g5c0p+bLNTTUFXJ+GSeDQmZRZ2p4H8cF/RJYa4PNvi/A1ar1uVNLFA== + dependencies: + arrify "^2.0.0" + base64-js "^1.3.0" + ecdsa-sig-formatter "^1.0.11" + fast-text-encoding "^1.0.0" + gaxios "^4.0.0" + gcp-metadata "^4.2.0" + gtoken "^5.0.4" + jws "^4.0.0" + lru-cache "^6.0.0" + + google-p12-pem@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-3.1.3.tgz#5497998798ee86c2fc1f4bb1f92b7729baf37537" + integrity sha512-MC0jISvzymxePDVembypNefkAQp+DRP7dBE+zNUPaIjEspIlYg0++OrsNr248V9tPbz6iqtZ7rX1hxWA5B8qBQ== + dependencies: + node-forge "^1.0.0" + + googleapis-common@^5.0.2: + version "5.1.0" + resolved "https://registry.yarnpkg.com/googleapis-common/-/googleapis-common-5.1.0.tgz#845a79471c787e522e03c50d415467140e9e356a" + integrity sha512-RXrif+Gzhq1QAzfjxulbGvAY3FPj8zq/CYcvgjzDbaBNCD6bUl+86I7mUs4DKWHGruuK26ijjR/eDpWIDgNROA== + dependencies: + extend "^3.0.2" + gaxios "^4.0.0" + google-auth-library "^7.14.0" + qs "^6.7.0" + url-template "^2.0.8" + uuid "^8.0.0" + + googleapis@^84.0.0: + version "84.0.0" + resolved "https://registry.yarnpkg.com/googleapis/-/googleapis-84.0.0.tgz#55b534b234c2df1af0b0f33c0394f31ac23a20d0" + integrity sha512-5WWLwmraulw3p55lu0gNpLz2FME1gcuR7QxgmUdAVHMiVN4LEasYjJV9p36gxcf2TMe6bn6+PgQ/63+CvBEgoQ== + dependencies: + google-auth-library "^7.0.2" + googleapis-common "^5.0.2" + + got@9.6.0: + version "9.6.0" + resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" + integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== + dependencies: + "@sindresorhus/is" "^0.14.0" + "@szmarczak/http-timer" "^1.1.2" + cacheable-request "^6.0.0" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^4.1.0" + lowercase-keys "^1.0.1" + mimic-response "^1.0.1" + p-cancelable "^1.0.0" + to-readable-stream "^1.0.0" + url-parse-lax "^3.0.0" + + got@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" + integrity sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw== + dependencies: + decompress-response "^3.2.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + is-plain-obj "^1.1.0" + is-retry-allowed "^1.0.0" + is-stream "^1.0.0" + isurl "^1.0.0-alpha5" + lowercase-keys "^1.0.0" + p-cancelable "^0.3.0" + p-timeout "^1.1.1" + safe-buffer "^5.0.1" + timed-out "^4.0.0" + url-parse-lax "^1.0.0" + url-to-options "^1.0.1" + + got@^8.3.1: + version "8.3.2" + resolved "https://registry.yarnpkg.com/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937" + integrity sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw== + dependencies: + "@sindresorhus/is" "^0.7.0" + cacheable-request "^2.1.1" + decompress-response "^3.3.0" + duplexer3 "^0.1.4" + get-stream "^3.0.0" + into-stream "^3.1.0" + is-retry-allowed "^1.1.0" + isurl "^1.0.0-alpha5" + lowercase-keys "^1.0.0" + mimic-response "^1.0.0" + p-cancelable "^0.4.0" + p-timeout "^2.0.1" + pify "^3.0.0" + safe-buffer "^5.1.1" + timed-out "^4.0.1" + url-parse-lax "^3.0.0" + url-to-options "^1.0.1" + + graceful-fs@^4.1.10, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: + version "4.2.9" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" + integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== + + grapheme-splitter@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" + integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== + + gray-matter@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/gray-matter/-/gray-matter-4.0.3.tgz#e893c064825de73ea1f5f7d88c7a9f7274288798" + integrity sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q== + dependencies: + js-yaml "^3.13.1" + kind-of "^6.0.2" + section-matter "^1.0.0" + strip-bom-string "^1.0.0" + + growly@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= + + gtoken@^5.0.4: + version "5.3.2" + resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-5.3.2.tgz#deb7dc876abe002178e0515e383382ea9446d58f" + integrity sha512-gkvEKREW7dXWF8NV8pVrKfW7WqReAmjjkMBh6lNCCGOM4ucS0r0YyXXl0r/9Yj8wcW/32ISkfc8h5mPTDbtifQ== + dependencies: + gaxios "^4.0.0" + google-p12-pem "^3.1.3" + jws "^4.0.0" + + gzip-size@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462" + integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q== + dependencies: + duplexer "^0.1.2" + + handlebars@^4.7.7: + version "4.7.7" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" + integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== + dependencies: + minimist "^1.2.5" + neo-async "^2.6.0" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + + har-schema@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + + har-validator@~5.1.3: + version "5.1.5" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" + integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== + dependencies: + ajv "^6.12.3" + har-schema "^2.0.0" + + has-bigints@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" + integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== + + has-flag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + integrity sha1-6CB68cx7MNRGzHC3NLXovhj4jVE= + + has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + + has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + + has-symbol-support-x@^1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" + integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== + + has-symbols@^1.0.1, has-symbols@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + + has-to-string-tag-x@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" + integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw== + dependencies: + has-symbol-support-x "^1.4.1" + + has-tostringtag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" + integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== + dependencies: + has-symbols "^1.0.2" + + has-value@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= + dependencies: + get-value "^2.0.3" + has-values "^0.1.4" + isobject "^2.0.0" + + has-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= + dependencies: + get-value "^2.0.6" + has-values "^1.0.0" + isobject "^3.0.0" + + has-values@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= + + has-values@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= + dependencies: + is-number "^3.0.0" + kind-of "^4.0.0" + + has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + + hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + + hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + + hast-util-is-element@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/hast-util-is-element/-/hast-util-is-element-2.1.2.tgz#fc0b0dc7cef3895e839b8d66979d57b0338c68f3" + integrity sha512-thjnlGAnwP8ef/GSO1Q8BfVk2gundnc2peGQqEg2kUt/IqesiGg/5mSwN2fE7nLzy61pg88NG6xV+UrGOrx9EA== + dependencies: + "@types/hast" "^2.0.0" + "@types/unist" "^2.0.0" + + hast-util-sanitize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/hast-util-sanitize/-/hast-util-sanitize-4.0.0.tgz#71a02ca2e50d04b852a5500846418070ca364f60" + integrity sha512-pw56+69jq+QSr/coADNvWTmBPDy+XsmwaF5KnUys4/wM1jt/fZdl7GPxhXXXYdXnz3Gj3qMkbUCH2uKjvX0MgQ== + dependencies: + "@types/hast" "^2.0.0" + + hast-util-to-estree@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hast-util-to-estree/-/hast-util-to-estree-2.0.2.tgz#79c5bf588915610b3f0d47ca83a74dc0269c7dc2" + integrity sha512-UQrZVeBj6A9od0lpFvqHKNSH9zvDrNoyWKbveu1a2oSCXEDUI+3bnd6BoiQLPnLrcXXn/jzJ6y9hmJTTlvf8lQ== + dependencies: + "@types/estree-jsx" "^0.0.1" + "@types/hast" "^2.0.0" + "@types/unist" "^2.0.0" + comma-separated-tokens "^2.0.0" + estree-util-attach-comments "^2.0.0" + estree-util-is-identifier-name "^2.0.0" + hast-util-whitespace "^2.0.0" + mdast-util-mdx-expression "^1.0.0" + mdast-util-mdxjs-esm "^1.0.0" + property-information "^6.0.0" + space-separated-tokens "^2.0.0" + style-to-object "^0.3.0" + unist-util-position "^4.0.0" + zwitch "^2.0.0" + + hast-util-to-html@^8.0.0: + version "8.0.3" + resolved "https://registry.yarnpkg.com/hast-util-to-html/-/hast-util-to-html-8.0.3.tgz#4e37580872e143ea9ce0dba87918b19e4ea997e3" + integrity sha512-/D/E5ymdPYhHpPkuTHOUkSatxr4w1ZKrZsG0Zv/3C2SRVT0JFJG53VS45AMrBtYk0wp5A7ksEhiC8QaOZM95+A== + dependencies: + "@types/hast" "^2.0.0" + ccount "^2.0.0" + comma-separated-tokens "^2.0.0" + hast-util-is-element "^2.0.0" + hast-util-whitespace "^2.0.0" + html-void-elements "^2.0.0" + property-information "^6.0.0" + space-separated-tokens "^2.0.0" + stringify-entities "^4.0.2" + unist-util-is "^5.0.0" + + hast-util-whitespace@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-2.0.0.tgz#4fc1086467cc1ef5ba20673cb6b03cec3a970f1c" + integrity sha512-Pkw+xBHuV6xFeJprJe2BBEoDV+AvQySaz3pPDRUs5PNZEMQjpXJJueqrpcHIXxnWTcAGi/UOCgVShlkY6kLoqg== + + highlight.js@^10.7.1: + version "10.7.3" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" + integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== + + history@^4.9.0: + version "4.10.1" + resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" + integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== + dependencies: + "@babel/runtime" "^7.1.2" + loose-envify "^1.2.0" + resolve-pathname "^3.0.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + value-equal "^1.0.1" + + hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + + hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.2.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + + hosted-git-info@^2.1.4: + version "2.8.9" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== + + html-encoding-sniffer@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" + integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== + dependencies: + whatwg-encoding "^1.0.5" + + html-escaper@^2.0.0, html-escaper@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + + html-parse-stringify@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2" + integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg== + dependencies: + void-elements "3.1.0" + + html-void-elements@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-2.0.1.tgz#29459b8b05c200b6c5ee98743c41b979d577549f" + integrity sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A== + + http-cache-semantics@3.8.1: + version "3.8.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" + integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== + + http-cache-semantics@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" + integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== + + http-errors@1.6.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" + integrity sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY= + dependencies: + depd "1.1.1" + inherits "2.0.3" + setprototypeof "1.0.3" + statuses ">= 1.3.1 < 2" + + http-errors@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" + integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.1" + + http-https@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b" + integrity sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs= + + http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + + http-signature@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + dependencies: + assert-plus "^1.0.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + + https-proxy-agent@5.0.0, https-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== + dependencies: + agent-base "6" + debug "4" + + human-signals@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== + + human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + + husky@^7.0.1, husky@^7.0.4: + version "7.0.4" + resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.4.tgz#242048245dc49c8fb1bf0cc7cfb98dd722531535" + integrity sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ== + + i18next-fs-backend@^1.0.7: + version "1.1.4" + resolved "https://registry.yarnpkg.com/i18next-fs-backend/-/i18next-fs-backend-1.1.4.tgz#d0e9b9ed2fa7a0f11002d82b9fa69c3c3d6482da" + integrity sha512-/MfAGMP0jHonV966uFf9PkWWuDjPYLIcsipnSO3NxpNtAgRUKLTwvm85fEmsF6hGeu0zbZiCQ3W74jwO6K9uXA== + + i18next@^20.1.0: + version "20.6.1" + resolved "https://registry.yarnpkg.com/i18next/-/i18next-20.6.1.tgz#535e5f6e5baeb685c7d25df70db63bf3cc0aa345" + integrity sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A== + dependencies: + "@babel/runtime" "^7.12.0" + + ical.js@^1.4.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/ical.js/-/ical.js-1.5.0.tgz#23213accd1d8f7248d01705acb06270a70d20662" + integrity sha512-7ZxMkogUkkaCx810yp0ZGKvq1ZpRgJeornPttpoxe6nYZ3NLesZe1wWMXDdwTkj/b5NtXT+Y16Aakph/ao98ZQ== + + iconv-lite@0.4.19: + version "0.4.19" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" + integrity sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ== + + iconv-lite@0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + + iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + + ics@^2.31.0: + version "2.35.0" + resolved "https://registry.yarnpkg.com/ics/-/ics-2.35.0.tgz#9cf3d7bcc9526f78d838b119613adb2a3baf19b8" + integrity sha512-uxHoiu9VnE/1RUIWoUqn9GVswUzrejHFa5Gk20gGySw+2FO8xzgJe7GLFk+hzmevHViG/6zANLhjVY6kFWctKQ== + dependencies: + nanoid "^3.1.23" + yup "^0.32.9" + + idb-wrapper@^1.5.0: + version "1.7.2" + resolved "https://registry.yarnpkg.com/idb-wrapper/-/idb-wrapper-1.7.2.tgz#8251afd5e77fe95568b1c16152eb44b396767ea2" + integrity sha512-zfNREywMuf0NzDo9mVsL0yegjsirJxHpKHvWcyRozIqQy89g0a3U+oBPOCN4cc0oCiOuYgZHimzaW/R46G1Mpg== + + idna-uts46-hx@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz#a1dc5c4df37eee522bf66d969cc980e00e8711f9" + integrity sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA== + dependencies: + punycode "2.1.0" + + ieee754@^1.1.13, ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + + iframe-resizer-react@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/iframe-resizer-react/-/iframe-resizer-react-1.1.0.tgz#5009e019b7a5c7f1c009bff5bcdf0dbf33557465" + integrity sha512-FrytSq91AIJaDgE+6uK/Vdd6IR8CrwLoZ6eGmL2qQMPTzF0xlSV2jaSzRRUh5V2fttD7vzl21jvBl97bV40eBw== + dependencies: + iframe-resizer "^4.3.0" + warning "^4.0.3" + + iframe-resizer@^4.3.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/iframe-resizer/-/iframe-resizer-4.3.2.tgz#42dd88345d18b9e377b6044dddb98c664ab0ce6b" + integrity sha512-gOWo2hmdPjMQsQ+zTKbses08mDfDEMh4NneGQNP4qwePYujY1lguqP6gnbeJkf154gojWlBhIltlgnMfYjGHWA== + + ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + + image-q@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/image-q/-/image-q-1.1.1.tgz#fc84099664460b90ca862d9300b6bfbbbfbf8056" + integrity sha1-/IQJlmRGC5DKhi2TALa/u7+/gFY= + + import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + + import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + + imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + + indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + + indexof@~0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= + + inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + dependencies: + once "^1.3.0" + wrappy "1" + + inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + + inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + + inline-style-parser@0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1" + integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q== + + input-format@^0.3.7: + version "0.3.7" + resolved "https://registry.yarnpkg.com/input-format/-/input-format-0.3.7.tgz#08d63fc629985d604d1910e1d1a220b7a521bdc3" + integrity sha512-hgwiCjV7MnhFvX4Hwrvk7hB2a2rcB2CQb7Ex7GlK1ISbEXuLtflwBUnadFSA1rVNDPFh9yWBaJJ4/o1XkzhPIg== + dependencies: + prop-types "^15.7.2" + + internal-slot@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" + integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== + dependencies: + get-intrinsic "^1.1.0" + has "^1.0.3" + side-channel "^1.0.4" + + intersection-observer@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.12.0.tgz#6c84628f67ce8698e5f9ccf857d97718745837aa" + integrity sha512-2Vkz8z46Dv401zTWudDGwO7KiGHNDkMv417T5ItcNYfmvHR/1qCTVBO9vwH8zZmQ0WkA/1ARwpysR9bsnop4NQ== + + intl-messageformat@9.11.4: + version "9.11.4" + resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-9.11.4.tgz#0f9030bc6d10e6a48592142f88e646d88f05f1f2" + integrity sha512-77TSkNubIy/hsapz6LQpyR6OADcxhWdhSaboPb5flMaALCVkPvAIxr48AlPqaMl4r1anNcvR9rpLWVdwUY1IKg== + dependencies: + "@formatjs/ecma402-abstract" "1.11.3" + "@formatjs/fast-memoize" "1.2.1" + "@formatjs/icu-messageformat-parser" "2.0.18" + tslib "^2.1.0" + + into-stream@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" + integrity sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY= + dependencies: + from2 "^2.1.1" + p-is-promise "^1.1.0" + + invariant@^2.2.4: + version "2.2.4" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" + integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== + dependencies: + loose-envify "^1.0.0" + + ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + + ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + + ipaddr.js@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0" + integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== + + is-accessor-descriptor@^0.1.6: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= + dependencies: + kind-of "^3.0.2" + + is-accessor-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== + dependencies: + kind-of "^6.0.0" + + is-alphabetical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" + integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== + + is-alphabetical@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-2.0.1.tgz#01072053ea7c1036df3c7d19a6daaec7f19e789b" + integrity sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ== + + is-alphanumerical@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" + integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== + dependencies: + is-alphabetical "^1.0.0" + is-decimal "^1.0.0" + + is-alphanumerical@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz#7c03fbe96e3e931113e57f964b0a368cc2dfd875" + integrity sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw== + dependencies: + is-alphabetical "^2.0.0" + is-decimal "^2.0.0" + + is-arguments@^1.0.4: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" + integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + + is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + + is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + + is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + + is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + + is-buffer@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== + + is-buffer@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" + integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== + + is-callable@^1.1.4, is-callable@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" + integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== + + is-ci@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== + dependencies: + ci-info "^2.0.0" + + is-core-module@^2.2.0, is-core-module@^2.8.0, is-core-module@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" + integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== + dependencies: + has "^1.0.3" + + is-data-descriptor@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= + dependencies: + kind-of "^3.0.2" + + is-data-descriptor@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== + dependencies: + kind-of "^6.0.0" + + is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + + is-decimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" + integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== + + is-decimal@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-2.0.1.tgz#9469d2dc190d0214fd87d78b78caecc0cc14eef7" + integrity sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A== + + is-descriptor@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== + dependencies: + is-accessor-descriptor "^0.1.6" + is-data-descriptor "^0.1.4" + kind-of "^5.0.0" + + is-descriptor@^1.0.0, is-descriptor@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== + dependencies: + is-accessor-descriptor "^1.0.0" + is-data-descriptor "^1.0.0" + kind-of "^6.0.2" + + is-docker@^2.0.0, is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + + is-extendable@^0.1.0, is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= + + is-extendable@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== + dependencies: + is-plain-object "^2.0.4" + + is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + + is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + + is-fullwidth-code-point@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" + integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== + + is-function@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" + integrity sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ== + + is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + + is-generator-function@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" + + is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + + is-hex-prefixed@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" + integrity sha1-fY035q135dEnFIkTxXPggtd39VQ= + + is-hexadecimal@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" + integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== + + is-hexadecimal@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz#86b5bf668fca307498d319dfc03289d781a90027" + integrity sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg== + + is-natural-number@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8" + integrity sha1-q5124dtM7VHjXeDHLr7PCfc0zeg= + + is-negative-zero@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + + is-number-object@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" + integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== + dependencies: + has-tostringtag "^1.0.0" + + is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= + dependencies: + kind-of "^3.0.2" + + is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + + is-object@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf" + integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA== + + is-object@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/is-object/-/is-object-0.1.2.tgz#00efbc08816c33cfc4ac8251d132e10dc65098d7" + integrity sha1-AO+8CIFsM8/ErIJR0TLhDcZQmNc= + + is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + + is-plain-obj@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + + is-plain-obj@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.0.0.tgz#06c0999fd7574edf5a906ba5644ad0feb3a84d22" + integrity sha512-NXRbBtUdBioI73y/HmOhogw/U5msYPC9DAtGkJXeFcFWSFZw0mCUsPxk/snTuJHzNKA8kLBK4rH97RMB1BfCXw== + + is-plain-object@^2.0.3, is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + + is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + + is-property@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + integrity sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ= + + is-reference@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-3.0.0.tgz#b1380c03d96ddf7089709781e3208fceb0c92cd6" + integrity sha512-Eo1W3wUoHWoCoVM4GVl/a+K0IgiqE5aIo4kJABFyMum1ZORlPkC+UC357sSQUL5w5QCE5kCC9upl75b7+7CY/Q== + dependencies: + "@types/estree" "*" + + is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + + is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" + integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== + + is-shared-array-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" + integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== + + is-stream@1.1.0, is-stream@^1.0.0, is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= + + 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-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + + is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + + is-typed-array@^1.1.3, is-typed-array@^1.1.7: + version "1.1.8" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.8.tgz#cbaa6585dc7db43318bc5b89523ea384a6f65e79" + integrity sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-abstract "^1.18.5" + foreach "^2.0.5" + has-tostringtag "^1.0.0" + + is-typedarray@^1.0.0, is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + + is-weakref@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + + is-windows@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== + + is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + + is@~0.2.6: + version "0.2.7" + resolved "https://registry.yarnpkg.com/is/-/is-0.2.7.tgz#3b34a2c48f359972f35042849193ae7264b63562" + integrity sha1-OzSixI81mXLzUEKEkZOucmS2NWI= + + isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= + + isarray@1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + + isbuffer@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/isbuffer/-/isbuffer-0.0.0.tgz#38c146d9df528b8bf9b0701c3d43cf12df3fc39b" + integrity sha1-OMFG2d9Si4v5sHAcPUPPEt8/w5s= + + isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + + isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= + dependencies: + isarray "1.0.0" + + isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + + isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + + istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + + istanbul-lib-instrument@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" + integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== + dependencies: + "@babel/core" "^7.7.5" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.0.0" + semver "^6.3.0" + + istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz#7b49198b657b27a730b8e9cb601f1e1bff24c59a" + integrity sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q== + 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.0.2, istanbul-reports@^3.1.3: + version "3.1.4" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.4.tgz#1b6f068ecbc6c331040aab5741991273e609e40c" + integrity sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + + isurl@^1.0.0-alpha5: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" + integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w== + dependencies: + has-to-string-tag-x "^1.2.0" + is-object "^1.0.1" + + javascript-natural-sort@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz#f9e2303d4507f6d74355a73664d1440fb5a0ef59" + integrity sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k= + + jest-changed-files@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.6.2.tgz#f6198479e1cc66f22f9ae1e22acaa0b429c042d0" + integrity sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ== + dependencies: + "@jest/types" "^26.6.2" + execa "^4.0.0" + throat "^5.0.0" + + jest-changed-files@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.5.1.tgz#a348aed00ec9bf671cc58a66fcbe7c3dfd6a68f5" + integrity sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw== + dependencies: + "@jest/types" "^27.5.1" + execa "^5.0.0" + throat "^6.0.1" + + jest-circus@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.5.1.tgz#37a5a4459b7bf4406e53d637b49d22c65d125ecc" + integrity sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^0.7.0" + expect "^27.5.1" + is-generator-fn "^2.0.0" + jest-each "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + slash "^3.0.0" + stack-utils "^2.0.3" + throat "^6.0.1" + + jest-cli@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.6.3.tgz#43117cfef24bc4cd691a174a8796a532e135e92a" + integrity sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg== + dependencies: + "@jest/core" "^26.6.3" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.4" + import-local "^3.0.2" + is-ci "^2.0.0" + jest-config "^26.6.3" + jest-util "^26.6.2" + jest-validate "^26.6.2" + prompts "^2.0.1" + yargs "^15.4.1" + + jest-cli@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.5.1.tgz#278794a6e6458ea8029547e6c6cbf673bd30b145" + integrity sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw== + dependencies: + "@jest/core" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + import-local "^3.0.2" + jest-config "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + prompts "^2.0.1" + yargs "^16.2.0" + + jest-config@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.6.3.tgz#64f41444eef9eb03dc51d5c53b75c8c71f645349" + integrity sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg== + dependencies: + "@babel/core" "^7.1.0" + "@jest/test-sequencer" "^26.6.3" + "@jest/types" "^26.6.2" + babel-jest "^26.6.3" + chalk "^4.0.0" + deepmerge "^4.2.2" + glob "^7.1.1" + graceful-fs "^4.2.4" + jest-environment-jsdom "^26.6.2" + jest-environment-node "^26.6.2" + jest-get-type "^26.3.0" + jest-jasmine2 "^26.6.3" + jest-regex-util "^26.0.0" + jest-resolve "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" + micromatch "^4.0.2" + pretty-format "^26.6.2" + + jest-config@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.5.1.tgz#5c387de33dca3f99ad6357ddeccd91bf3a0e4a41" + integrity sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA== + dependencies: + "@babel/core" "^7.8.0" + "@jest/test-sequencer" "^27.5.1" + "@jest/types" "^27.5.1" + babel-jest "^27.5.1" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.1" + graceful-fs "^4.2.9" + jest-circus "^27.5.1" + jest-environment-jsdom "^27.5.1" + jest-environment-node "^27.5.1" + jest-get-type "^27.5.1" + jest-jasmine2 "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-runner "^27.5.1" + jest-util "^27.5.1" + jest-validate "^27.5.1" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^27.5.1" + slash "^3.0.0" + strip-json-comments "^3.1.1" + + jest-diff@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" + integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== + dependencies: + chalk "^4.0.0" + diff-sequences "^26.6.2" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" + + jest-diff@^27.2.5, jest-diff@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def" + integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw== + dependencies: + chalk "^4.0.0" + diff-sequences "^27.5.1" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + + jest-docblock@^26.0.0: + version "26.0.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" + integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w== + dependencies: + detect-newline "^3.0.0" + + jest-docblock@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.5.1.tgz#14092f364a42c6108d42c33c8cf30e058e25f6c0" + integrity sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ== + dependencies: + detect-newline "^3.0.0" + + jest-each@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.6.2.tgz#02526438a77a67401c8a6382dfe5999952c167cb" + integrity sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A== + dependencies: + "@jest/types" "^26.6.2" + chalk "^4.0.0" + jest-get-type "^26.3.0" + jest-util "^26.6.2" + pretty-format "^26.6.2" + + jest-each@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.5.1.tgz#5bc87016f45ed9507fed6e4702a5b468a5b2c44e" + integrity sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ== + dependencies: + "@jest/types" "^27.5.1" + chalk "^4.0.0" + jest-get-type "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + + jest-environment-jsdom@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz#78d09fe9cf019a357009b9b7e1f101d23bd1da3e" + integrity sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q== + dependencies: + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" + jest-util "^26.6.2" + jsdom "^16.4.0" + + jest-environment-jsdom@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz#ea9ccd1fc610209655a77898f86b2b559516a546" + integrity sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" + jest-util "^27.5.1" + jsdom "^16.6.0" + + jest-environment-node@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.6.2.tgz#824e4c7fb4944646356f11ac75b229b0035f2b0c" + integrity sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag== + dependencies: + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + jest-mock "^26.6.2" + jest-util "^26.6.2" + + jest-environment-node@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.5.1.tgz#dedc2cfe52fab6b8f5714b4808aefa85357a365e" + integrity sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + jest-mock "^27.5.1" + jest-util "^27.5.1" + + jest-get-type@^26.3.0: + version "26.3.0" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" + integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== + + jest-get-type@^27.0.6, jest-get-type@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" + integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== + + jest-haste-map@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" + integrity sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w== + dependencies: + "@jest/types" "^26.6.2" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.4" + jest-regex-util "^26.0.0" + jest-serializer "^26.6.2" + jest-util "^26.6.2" + jest-worker "^26.6.2" + micromatch "^4.0.2" + sane "^4.0.3" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.1.2" + + jest-haste-map@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.1.tgz#9fd8bd7e7b4fa502d9c6164c5640512b4e811e7f" + integrity sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng== + dependencies: + "@jest/types" "^27.5.1" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^27.5.1" + jest-serializer "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" + micromatch "^4.0.4" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.3.2" + + jest-jasmine2@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz#adc3cf915deacb5212c93b9f3547cd12958f2edd" + integrity sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg== + dependencies: + "@babel/traverse" "^7.1.0" + "@jest/environment" "^26.6.2" + "@jest/source-map" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + expect "^26.6.2" + is-generator-fn "^2.0.0" + jest-each "^26.6.2" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-runtime "^26.6.3" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + pretty-format "^26.6.2" + throat "^5.0.0" + + jest-jasmine2@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz#a037b0034ef49a9f3d71c4375a796f3b230d1ac4" + integrity sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/source-map" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + expect "^27.5.1" + is-generator-fn "^2.0.0" + jest-each "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-runtime "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + pretty-format "^27.5.1" + throat "^6.0.1" + + jest-leak-detector@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz#7717cf118b92238f2eba65054c8a0c9c653a91af" + integrity sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg== + dependencies: + jest-get-type "^26.3.0" + pretty-format "^26.6.2" + + jest-leak-detector@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz#6ec9d54c3579dd6e3e66d70e3498adf80fde3fb8" + integrity sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ== + dependencies: + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + + jest-matcher-utils@27.2.5: + version "27.2.5" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.2.5.tgz#4684faaa8eb32bf15e6edaead6834031897e2980" + integrity sha512-qNR/kh6bz0Dyv3m68Ck2g1fLW5KlSOUNcFQh87VXHZwWc/gY6XwnKofx76Qytz3x5LDWT09/2+yXndTkaG4aWg== + dependencies: + chalk "^4.0.0" + jest-diff "^27.2.5" + jest-get-type "^27.0.6" + pretty-format "^27.2.5" + + jest-matcher-utils@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz#8e6fd6e863c8b2d31ac6472eeb237bc595e53e7a" + integrity sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw== + dependencies: + chalk "^4.0.0" + jest-diff "^26.6.2" + jest-get-type "^26.3.0" + pretty-format "^26.6.2" + + jest-matcher-utils@^27.0.0, jest-matcher-utils@^27.2.5, jest-matcher-utils@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab" + integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw== + dependencies: + chalk "^4.0.0" + jest-diff "^27.5.1" + jest-get-type "^27.5.1" + pretty-format "^27.5.1" + + jest-message-util@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07" + integrity sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA== + dependencies: + "@babel/code-frame" "^7.0.0" + "@jest/types" "^26.6.2" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.4" + micromatch "^4.0.2" + pretty-format "^26.6.2" + slash "^3.0.0" + stack-utils "^2.0.2" + + jest-message-util@^27.2.5, jest-message-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf" + integrity sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^27.5.1" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^27.5.1" + slash "^3.0.0" + stack-utils "^2.0.3" + + jest-mock@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.6.2.tgz#d6cb712b041ed47fe0d9b6fc3474bc6543feb302" + integrity sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew== + dependencies: + "@jest/types" "^26.6.2" + "@types/node" "*" + + jest-mock@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.5.1.tgz#19948336d49ef4d9c52021d34ac7b5f36ff967d6" + integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og== + dependencies: + "@jest/types" "^27.5.1" + "@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@^26.0.0: + version "26.0.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" + integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== + + jest-regex-util@^27.0.6, jest-regex-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95" + integrity sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg== + + jest-resolve-dependencies@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz#6680859ee5d22ee5dcd961fe4871f59f4c784fb6" + integrity sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg== + dependencies: + "@jest/types" "^26.6.2" + jest-regex-util "^26.0.0" + jest-snapshot "^26.6.2" + + jest-resolve-dependencies@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz#d811ecc8305e731cc86dd79741ee98fed06f1da8" + integrity sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg== + dependencies: + "@jest/types" "^27.5.1" + jest-regex-util "^27.5.1" + jest-snapshot "^27.5.1" + + jest-resolve@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.6.2.tgz#a3ab1517217f469b504f1b56603c5bb541fbb507" + integrity sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ== + dependencies: + "@jest/types" "^26.6.2" + chalk "^4.0.0" + graceful-fs "^4.2.4" + jest-pnp-resolver "^1.2.2" + jest-util "^26.6.2" + read-pkg-up "^7.0.1" + resolve "^1.18.1" + slash "^3.0.0" + + jest-resolve@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.5.1.tgz#a2f1c5a0796ec18fe9eb1536ac3814c23617b384" + integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw== + dependencies: + "@jest/types" "^27.5.1" + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^27.5.1" + jest-pnp-resolver "^1.2.2" + jest-util "^27.5.1" + jest-validate "^27.5.1" + resolve "^1.20.0" + resolve.exports "^1.1.0" + slash "^3.0.0" + + jest-runner@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.6.3.tgz#2d1fed3d46e10f233fd1dbd3bfaa3fe8924be159" + integrity sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ== + dependencies: + "@jest/console" "^26.6.2" + "@jest/environment" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.7.1" + exit "^0.1.2" + graceful-fs "^4.2.4" + jest-config "^26.6.3" + jest-docblock "^26.0.0" + jest-haste-map "^26.6.2" + jest-leak-detector "^26.6.2" + jest-message-util "^26.6.2" + jest-resolve "^26.6.2" + jest-runtime "^26.6.3" + jest-util "^26.6.2" + jest-worker "^26.6.2" + source-map-support "^0.5.6" + throat "^5.0.0" + + jest-runner@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.5.1.tgz#071b27c1fa30d90540805c5645a0ec167c7b62e5" + integrity sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ== + dependencies: + "@jest/console" "^27.5.1" + "@jest/environment" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.8.1" + graceful-fs "^4.2.9" + jest-docblock "^27.5.1" + jest-environment-jsdom "^27.5.1" + jest-environment-node "^27.5.1" + jest-haste-map "^27.5.1" + jest-leak-detector "^27.5.1" + jest-message-util "^27.5.1" + jest-resolve "^27.5.1" + jest-runtime "^27.5.1" + jest-util "^27.5.1" + jest-worker "^27.5.1" + source-map-support "^0.5.6" + throat "^6.0.1" + + jest-runtime@^26.6.3: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.6.3.tgz#4f64efbcfac398331b74b4b3c82d27d401b8fa2b" + integrity sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw== + dependencies: + "@jest/console" "^26.6.2" + "@jest/environment" "^26.6.2" + "@jest/fake-timers" "^26.6.2" + "@jest/globals" "^26.6.2" + "@jest/source-map" "^26.6.2" + "@jest/test-result" "^26.6.2" + "@jest/transform" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/yargs" "^15.0.0" + chalk "^4.0.0" + cjs-module-lexer "^0.6.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.4" + jest-config "^26.6.3" + jest-haste-map "^26.6.2" + jest-message-util "^26.6.2" + jest-mock "^26.6.2" + jest-regex-util "^26.0.0" + jest-resolve "^26.6.2" + jest-snapshot "^26.6.2" + jest-util "^26.6.2" + jest-validate "^26.6.2" + slash "^3.0.0" + strip-bom "^4.0.0" + yargs "^15.4.1" + + jest-runtime@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.5.1.tgz#4896003d7a334f7e8e4a53ba93fb9bcd3db0a1af" + integrity sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A== + dependencies: + "@jest/environment" "^27.5.1" + "@jest/fake-timers" "^27.5.1" + "@jest/globals" "^27.5.1" + "@jest/source-map" "^27.5.1" + "@jest/test-result" "^27.5.1" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + 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 "^27.5.1" + jest-message-util "^27.5.1" + jest-mock "^27.5.1" + jest-regex-util "^27.5.1" + jest-resolve "^27.5.1" + jest-snapshot "^27.5.1" + jest-util "^27.5.1" + slash "^3.0.0" + strip-bom "^4.0.0" + + jest-serializer@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" + integrity sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g== + dependencies: + "@types/node" "*" + graceful-fs "^4.2.4" + + jest-serializer@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.1.tgz#81438410a30ea66fd57ff730835123dea1fb1f64" + integrity sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w== + dependencies: + "@types/node" "*" + graceful-fs "^4.2.9" + + jest-snapshot@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.6.2.tgz#f3b0af1acb223316850bd14e1beea9837fb39c84" + integrity sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og== + dependencies: + "@babel/types" "^7.0.0" + "@jest/types" "^26.6.2" + "@types/babel__traverse" "^7.0.4" + "@types/prettier" "^2.0.0" + chalk "^4.0.0" + expect "^26.6.2" + graceful-fs "^4.2.4" + jest-diff "^26.6.2" + jest-get-type "^26.3.0" + jest-haste-map "^26.6.2" + jest-matcher-utils "^26.6.2" + jest-message-util "^26.6.2" + jest-resolve "^26.6.2" + natural-compare "^1.4.0" + pretty-format "^26.6.2" + semver "^7.3.2" + + jest-snapshot@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.5.1.tgz#b668d50d23d38054a51b42c4039cab59ae6eb6a1" + integrity sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA== + dependencies: + "@babel/core" "^7.7.2" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/traverse" "^7.7.2" + "@babel/types" "^7.0.0" + "@jest/transform" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/babel__traverse" "^7.0.4" + "@types/prettier" "^2.1.5" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^27.5.1" + graceful-fs "^4.2.9" + jest-diff "^27.5.1" + jest-get-type "^27.5.1" + jest-haste-map "^27.5.1" + jest-matcher-utils "^27.5.1" + jest-message-util "^27.5.1" + jest-util "^27.5.1" + natural-compare "^1.4.0" + pretty-format "^27.5.1" + semver "^7.3.2" + + jest-util@^26.1.0, jest-util@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" + integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== + dependencies: + "@jest/types" "^26.6.2" + "@types/node" "*" + chalk "^4.0.0" + graceful-fs "^4.2.4" + is-ci "^2.0.0" + micromatch "^4.0.2" + + jest-util@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9" + integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw== + dependencies: + "@jest/types" "^27.5.1" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + + jest-validate@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec" + integrity sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ== + dependencies: + "@jest/types" "^26.6.2" + camelcase "^6.0.0" + chalk "^4.0.0" + jest-get-type "^26.3.0" + leven "^3.1.0" + pretty-format "^26.6.2" + + jest-validate@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.5.1.tgz#9197d54dc0bdb52260b8db40b46ae668e04df067" + integrity sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ== + dependencies: + "@jest/types" "^27.5.1" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^27.5.1" + leven "^3.1.0" + pretty-format "^27.5.1" + + jest-watcher@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.6.2.tgz#a5b683b8f9d68dbcb1d7dae32172d2cca0592975" + integrity sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ== + dependencies: + "@jest/test-result" "^26.6.2" + "@jest/types" "^26.6.2" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + jest-util "^26.6.2" + string-length "^4.0.1" + + jest-watcher@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.5.1.tgz#71bd85fb9bde3a2c2ec4dc353437971c43c642a2" + integrity sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw== + dependencies: + "@jest/test-result" "^27.5.1" + "@jest/types" "^27.5.1" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + jest-util "^27.5.1" + string-length "^4.0.1" + + jest-worker@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" + integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^7.0.0" + + jest-worker@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" + integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + + jest@^26.0.0: + version "26.6.3" + resolved "https://registry.yarnpkg.com/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef" + integrity sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q== + dependencies: + "@jest/core" "^26.6.3" + import-local "^3.0.2" + jest-cli "^26.6.3" + + jest@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/jest/-/jest-27.5.1.tgz#dadf33ba70a779be7a6fc33015843b51494f63fc" + integrity sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ== + dependencies: + "@jest/core" "^27.5.1" + import-local "^3.0.2" + jest-cli "^27.5.1" + + jimp@^0.16.1: + version "0.16.1" + resolved "https://registry.yarnpkg.com/jimp/-/jimp-0.16.1.tgz#192f851a30e5ca11112a3d0aa53137659a78ca7a" + integrity sha512-+EKVxbR36Td7Hfd23wKGIeEyHbxShZDX6L8uJkgVW3ESA9GiTEPK08tG1XI2r/0w5Ch0HyJF5kPqF9K7EmGjaw== + dependencies: + "@babel/runtime" "^7.7.2" + "@jimp/custom" "^0.16.1" + "@jimp/plugins" "^0.16.1" + "@jimp/types" "^0.16.1" + regenerator-runtime "^0.13.3" + + jose@^4.1.4, jose@^4.3.7: + version "4.6.0" + resolved "https://registry.yarnpkg.com/jose/-/jose-4.6.0.tgz#f3ff007ddcbce462c091d3d41b7af2e35dec348c" + integrity sha512-0hNAkhMBNi4soKSAX4zYOFV+aqJlEz/4j4fregvasJzEVtjDChvWqRjPvHwLqr5hx28Ayr6bsOs1Kuj87V0O8w== + + jpeg-js@0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.2.tgz#8b345b1ae4abde64c2da2fe67ea216a114ac279d" + integrity sha512-+az2gi/hvex7eLTMTlbRLOhH6P6WFdk2ITI8HJsaH2VqYO0I594zXSYEP+tf4FW+8Cy68ScDXoAsQdyQanv3sw== + + jpeg-js@0.4.3: + version "0.4.3" + resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.3.tgz#6158e09f1983ad773813704be80680550eff977b" + integrity sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q== + + js-sha3@0.8.0, js-sha3@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + + js-sha3@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" + integrity sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc= + + "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + + js-yaml@^3.13.1: + 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.0.0, js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + + jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + + jsdom@^16.4.0, jsdom@^16.6.0: + version "16.7.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" + integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== + dependencies: + abab "^2.0.5" + acorn "^8.2.4" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.3.0" + data-urls "^2.0.0" + decimal.js "^10.2.1" + domexception "^2.0.1" + escodegen "^2.0.0" + form-data "^3.0.0" + html-encoding-sniffer "^2.0.1" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.0" + parse5 "6.0.1" + saxes "^5.0.1" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.5.0" + ws "^7.4.6" + xml-name-validator "^3.0.0" + + jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + + jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + + json-bigint@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-bigint/-/json-bigint-1.0.0.tgz#ae547823ac0cad8398667f8cd9ef4730f5b01ff1" + integrity sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ== + dependencies: + bignumber.js "^9.0.0" + + json-buffer@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" + integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= + + json-parse-better-errors@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== + + json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + + json-rpc-engine@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-6.1.0.tgz#bf5ff7d029e1c1bf20cb6c0e9f348dcd8be5a393" + integrity sha512-NEdLrtrq1jUZyfjkr9OCz9EzCNhnRyWtt1PAnvnhwy6e8XETS0Dtc+ZNCO2gvuAoKsIn2+vCSowXTYE4CkgnAQ== + dependencies: + "@metamask/safe-event-emitter" "^2.0.0" + eth-rpc-errors "^4.0.2" + + json-rpc-middleware-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/json-rpc-middleware-stream/-/json-rpc-middleware-stream-3.0.0.tgz#8540331d884f36b9e0ad31054cc68ac6b5a89b52" + integrity sha512-JmZmlehE0xF3swwORpLHny/GvW3MZxCsb2uFNBrn8TOqMqivzCfz232NSDLLOtIQlrPlgyEjiYpyzyOPFOzClw== + dependencies: + "@metamask/safe-event-emitter" "^2.0.0" + readable-stream "^2.3.3" + + json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + + json-schema@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== + + json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= + + json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + + json5@2.2.0, json5@2.x, json5@^2.1.2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" + integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== + dependencies: + minimist "^1.2.5" + + json5@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= + + json5@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== + dependencies: + minimist "^1.2.0" + + jsonfile@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= + optionalDependencies: + graceful-fs "^4.1.6" + + jsonfile@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-5.0.0.tgz#e6b718f73da420d612823996fdf14a03f6ff6922" + integrity sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w== + dependencies: + universalify "^0.1.2" + optionalDependencies: + graceful-fs "^4.1.6" + + jsprim@^1.2.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" + integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.4.0" + verror "1.10.0" + + "jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz#720b97bfe7d901b927d87c3773637ae8ea48781b" + integrity sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA== + dependencies: + array-includes "^3.1.3" + object.assign "^4.1.2" + + jwa@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/jwa/-/jwa-2.0.0.tgz#a7e9c3f29dae94027ebcaf49975c9345593410fc" + integrity sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA== + dependencies: + buffer-equal-constant-time "1.0.1" + ecdsa-sig-formatter "1.0.11" + safe-buffer "^5.0.1" + + jws@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jws/-/jws-4.0.0.tgz#2d4e8cf6a318ffaa12615e9dec7e86e6c97310f4" + integrity sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg== + dependencies: + jwa "^2.0.0" + safe-buffer "^5.0.1" + + keccak@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.2.tgz#4c2c6e8c54e04f2670ee49fa734eb9da152206e0" + integrity sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ== + dependencies: + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + readable-stream "^3.6.0" + + keyv@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" + integrity sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA== + dependencies: + json-buffer "3.0.0" + + keyv@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" + integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== + dependencies: + json-buffer "3.0.0" + + kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= + dependencies: + is-buffer "^1.1.5" + + kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= + dependencies: + is-buffer "^1.1.5" + + kind-of@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== + + kind-of@^6.0.0, kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + + kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + + kleur@^4.0.3: + version "4.1.4" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.4.tgz#8c202987d7e577766d039a8cd461934c01cda04d" + integrity sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA== + + language-subtag-registry@~0.3.2: + version "0.3.21" + resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a" + integrity sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg== + + language-tags@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.5.tgz#d321dbc4da30ba8bf3024e040fa5c14661f9193a" + integrity sha1-0yHbxNowuovzAk4ED6XBRmH5GTo= + dependencies: + language-subtag-registry "~0.3.2" + + level-blobs@^0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/level-blobs/-/level-blobs-0.1.7.tgz#9ab9b97bb99f1edbf9f78a3433e21ed56386bdaf" + integrity sha1-mrm5e7mfHtv594o0M+Ie1WOGva8= + dependencies: + level-peek "1.0.6" + once "^1.3.0" + readable-stream "^1.0.26-4" + + level-filesystem@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/level-filesystem/-/level-filesystem-1.2.0.tgz#a00aca9919c4a4dfafdca6a8108d225aadff63b3" + integrity sha1-oArKmRnEpN+v3KaoEI0iWq3/Y7M= + dependencies: + concat-stream "^1.4.4" + errno "^0.1.1" + fwd-stream "^1.0.4" + level-blobs "^0.1.7" + level-peek "^1.0.6" + level-sublevel "^5.2.0" + octal "^1.0.0" + once "^1.3.0" + xtend "^2.2.0" + + level-fix-range@2.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/level-fix-range/-/level-fix-range-2.0.0.tgz#c417d62159442151a19d9a2367868f1724c2d548" + integrity sha1-xBfWIVlEIVGhnZojZ4aPFyTC1Ug= + dependencies: + clone "~0.1.9" + + level-fix-range@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/level-fix-range/-/level-fix-range-1.0.2.tgz#bf15b915ae36d8470c821e883ddf79cd16420828" + integrity sha1-vxW5Fa422EcMgh6IPd95zRZCCCg= + + "level-hooks@>=4.4.0 <5": + version "4.5.0" + resolved "https://registry.yarnpkg.com/level-hooks/-/level-hooks-4.5.0.tgz#1b9ae61922930f3305d1a61fc4d83c8102c0dd93" + integrity sha1-G5rmGSKTDzMF0aYfxNg8gQLA3ZM= + dependencies: + string-range "~1.2" + + level-js@^2.1.3: + version "2.2.4" + resolved "https://registry.yarnpkg.com/level-js/-/level-js-2.2.4.tgz#bc055f4180635d4489b561c9486fa370e8c11697" + integrity sha1-vAVfQYBjXUSJtWHJSG+jcOjBFpc= + dependencies: + abstract-leveldown "~0.12.0" + idb-wrapper "^1.5.0" + isbuffer "~0.0.0" + ltgt "^2.1.2" + typedarray-to-buffer "~1.0.0" + xtend "~2.1.2" + + level-peek@1.0.6, level-peek@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/level-peek/-/level-peek-1.0.6.tgz#bec51c72a82ee464d336434c7c876c3fcbcce77f" + integrity sha1-vsUccqgu5GTTNkNMfIdsP8vM538= + dependencies: + level-fix-range "~1.0.2" + + level-sublevel@^5.2.0: + version "5.2.3" + resolved "https://registry.yarnpkg.com/level-sublevel/-/level-sublevel-5.2.3.tgz#744c12c72d2e72be78dde3b9b5cd84d62191413a" + integrity sha1-dEwSxy0ucr543eO5tc2E1iGRQTo= + dependencies: + level-fix-range "2.0" + level-hooks ">=4.4.0 <5" + string-range "~1.2.1" + xtend "~2.0.4" + + levelup@^0.18.2: + version "0.18.6" + resolved "https://registry.yarnpkg.com/levelup/-/levelup-0.18.6.tgz#e6a01cb089616c8ecc0291c2a9bd3f0c44e3e5eb" + integrity sha1-5qAcsIlhbI7MApHCqb0/DETj5es= + dependencies: + bl "~0.8.1" + deferred-leveldown "~0.2.0" + errno "~0.1.1" + prr "~0.0.0" + readable-stream "~1.0.26" + semver "~2.3.1" + xtend "~3.0.0" + + leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + + levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + + levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + + libphonenumber-js@^1.9.47: + version "1.9.49" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.9.49.tgz#d431703cd699be2ccced5b95f26182a7c50a9227" + integrity sha512-/wEOIONcVboFky+lWlCaF7glm1FhBz11M5PHeCApA+xDdVfmhKjHktHS8KjyGxouV5CSXIr4f3GvLSpJa4qMSg== + + lilconfig@2.0.4, lilconfig@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.4.tgz#f4507d043d7058b380b6a8f5cb7bcd4b34cee082" + integrity sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA== + + 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@^12.3.5: + version "12.3.5" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-12.3.5.tgz#8048ce048c3cac12f57200a06344a54dc91c8fa9" + integrity sha512-oOH36RUs1It7b9U/C7Nl/a0sLfoIBcMB8ramiB3nuJ6brBqzsWiUAFSR5DQ3yyP/OR7XKMpijtgKl2DV1lQ3lA== + dependencies: + cli-truncate "^3.1.0" + colorette "^2.0.16" + commander "^8.3.0" + debug "^4.3.3" + execa "^5.1.1" + lilconfig "2.0.4" + listr2 "^4.0.1" + micromatch "^4.0.4" + normalize-path "^3.0.0" + object-inspect "^1.12.0" + string-argv "^0.3.1" + supports-color "^9.2.1" + yaml "^1.10.2" + + listr2@^4.0.1: + version "4.0.5" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-4.0.5.tgz#9dcc50221583e8b4c71c43f9c7dfd0ef546b75d5" + integrity sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA== + dependencies: + cli-truncate "^2.1.0" + colorette "^2.0.16" + log-update "^4.0.0" + p-map "^4.0.0" + rfdc "^1.3.0" + rxjs "^7.5.5" + through "^2.3.8" + wrap-ansi "^7.0.0" + + load-bmfont@^1.3.1, load-bmfont@^1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/load-bmfont/-/load-bmfont-1.4.1.tgz#c0f5f4711a1e2ccff725a7b6078087ccfcddd3e9" + integrity sha512-8UyQoYmdRDy81Brz6aLAUhfZLwr5zV0L3taTQ4hju7m6biuwiWiJXjPhBJxbUQJA8PrkvJ/7Enqmwk2sM14soA== + dependencies: + buffer-equal "0.0.1" + mime "^1.3.4" + parse-bmfont-ascii "^1.0.3" + parse-bmfont-binary "^1.0.5" + parse-bmfont-xml "^1.1.4" + phin "^2.9.1" + xhr "^2.0.1" + xtend "^4.0.0" + + load-json-file@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" + integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= + dependencies: + graceful-fs "^4.1.2" + parse-json "^4.0.0" + pify "^3.0.0" + strip-bom "^3.0.0" + + loader-utils@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129" + integrity sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A== + dependencies: + big.js "^5.2.2" + emojis-list "^3.0.0" + json5 "^2.1.2" + + locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + + locate-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== + dependencies: + p-locate "^3.0.0" + path-exists "^3.0.0" + + locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + + lodash-es@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + + lodash.castarray@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115" + integrity sha1-wCUTUV4wna3dTCTGDP3c9ZdtkRU= + + lodash.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= + + lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + + lodash.isequal@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" + integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= + + lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" + integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= + + lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + + lodash.once@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= + + lodash@4.17.21, lodash@4.x, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + + log-update@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" + integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== + dependencies: + ansi-escapes "^4.3.0" + cli-cursor "^3.1.0" + slice-ansi "^4.0.0" + wrap-ansi "^6.2.0" + + long@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" + integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== + + longest-streak@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4" + integrity sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg== + + longest-streak@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.0.1.tgz#c97315b7afa0e7d9525db9a5a2953651432bdc5d" + integrity sha512-cHlYSUpL2s7Fb3394mYxwTYj8niTaNHUCLr0qdiCXQfSjfuA7CKofpX2uSwEfFDQ0EB7JcnMnm+GjbqqoinYYg== + + loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + + lowercase-keys@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" + integrity sha1-TjNms55/VFfjXxMkvfb4jQv8cwY= + + lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" + integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== + + lowercase-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" + integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== + + lru-cache@^4.0.1, lru-cache@^4.1.3: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + + lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + + ltgt@^2.1.2: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" + integrity sha1-81ypHEk/e3PaDgdJUwTxezH4fuU= + + magic-string@^0.25.7: + version "0.25.9" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" + integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== + dependencies: + sourcemap-codec "^1.4.8" + + make-dir@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" + integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== + dependencies: + pify "^3.0.0" + + make-dir@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== + dependencies: + pify "^4.0.1" + semver "^5.6.0" + + make-dir@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + + make-error@1.x, make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + + make-event-props@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-event-props/-/make-event-props-1.3.0.tgz#2434cb390d58bcf40898d009ef5b1f936de9671b" + integrity sha512-oWiDZMcVB1/A487251hEWza1xzgCzl6MXxe9aF24l5Bt9N9UEbqTqKumEfuuLhmlhRZYnc+suVvW4vUs8bwO7Q== + + makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + + map-cache@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= + + map-visit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= + dependencies: + object-visit "^1.0.0" + + markdown-extensions@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/markdown-extensions/-/markdown-extensions-1.1.1.tgz#fea03b539faeaee9b4ef02a3769b455b189f7fc3" + integrity sha512-WWC0ZuMzCyDHYCasEGs4IPvLyTGftYwh6wIEOULOF0HXcqZlhwRzrK0w2VUlxWA98xnvb/jszw4ZSkJ6ADpM6Q== + + markdown-table@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-2.0.0.tgz#194a90ced26d31fe753d8b9434430214c011865b" + integrity sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A== + dependencies: + repeat-string "^1.0.0" + + match-sorter@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-4.2.1.tgz#575b4b3737185ba9518b67612b66877ea0b37358" + integrity sha512-s+3h9TiZU9U1pWhIERHf8/f4LmBN6IXaRgo2CI17+XGByGS1GvG5VvXK9pcGyCjGe3WM3mSYRC3ipGrd5UEVgw== + dependencies: + "@babel/runtime" "^7.10.5" + remove-accents "0.4.2" + + match-sorter@^6.0.2: + version "6.3.1" + resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.1.tgz#98cc37fda756093424ddf3cbc62bfe9c75b92bda" + integrity sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw== + dependencies: + "@babel/runtime" "^7.12.5" + remove-accents "0.4.2" + + md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + + mdast-util-definitions@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-5.1.0.tgz#b6d10ef00a3c4cf191e8d9a5fa58d7f4a366f817" + integrity sha512-5hcR7FL2EuZ4q6lLMUK5w4lHT2H3vqL9quPvYZ/Ku5iifrirfMHiGdhxdXMUbUkDmz5I+TYMd7nbaxUhbQkfpQ== + dependencies: + "@types/mdast" "^3.0.0" + "@types/unist" "^2.0.0" + unist-util-visit "^3.0.0" + + mdast-util-find-and-replace@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/mdast-util-find-and-replace/-/mdast-util-find-and-replace-1.1.1.tgz#b7db1e873f96f66588c321f1363069abf607d1b5" + integrity sha512-9cKl33Y21lyckGzpSmEQnIDjEfeeWelN5s1kUW1LwdB0Fkuq2u+4GdqcGEygYxJE8GVqCl0741bYXHgamfWAZA== + dependencies: + escape-string-regexp "^4.0.0" + unist-util-is "^4.0.0" + unist-util-visit-parents "^3.0.0" + + mdast-util-from-markdown@^0.8.0: + version "0.8.5" + resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz#d1ef2ca42bc377ecb0463a987910dae89bd9a28c" + integrity sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ== + dependencies: + "@types/mdast" "^3.0.0" + mdast-util-to-string "^2.0.0" + micromark "~2.11.0" + parse-entities "^2.0.0" + unist-util-stringify-position "^2.0.0" + + mdast-util-from-markdown@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz#84df2924ccc6c995dec1e2368b2b208ad0a76268" + integrity sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q== + dependencies: + "@types/mdast" "^3.0.0" + "@types/unist" "^2.0.0" + decode-named-character-reference "^1.0.0" + mdast-util-to-string "^3.1.0" + micromark "^3.0.0" + micromark-util-decode-numeric-character-reference "^1.0.0" + micromark-util-decode-string "^1.0.0" + micromark-util-normalize-identifier "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + unist-util-stringify-position "^3.0.0" + uvu "^0.5.0" + + mdast-util-gfm-autolink-literal@^0.1.0: + version "0.1.3" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-0.1.3.tgz#9c4ff399c5ddd2ece40bd3b13e5447d84e385fb7" + integrity sha512-GjmLjWrXg1wqMIO9+ZsRik/s7PLwTaeCHVB7vRxUwLntZc8mzmTsLVr6HW1yLokcnhfURsn5zmSVdi3/xWWu1A== + dependencies: + ccount "^1.0.0" + mdast-util-find-and-replace "^1.1.0" + micromark "^2.11.3" + + mdast-util-gfm-strikethrough@^0.2.0: + version "0.2.3" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-0.2.3.tgz#45eea337b7fff0755a291844fbea79996c322890" + integrity sha512-5OQLXpt6qdbttcDG/UxYY7Yjj3e8P7X16LzvpX8pIQPYJ/C2Z1qFGMmcw+1PZMUM3Z8wt8NRfYTvCni93mgsgA== + dependencies: + mdast-util-to-markdown "^0.6.0" + + mdast-util-gfm-table@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-table/-/mdast-util-gfm-table-0.1.6.tgz#af05aeadc8e5ee004eeddfb324b2ad8c029b6ecf" + integrity sha512-j4yDxQ66AJSBwGkbpFEp9uG/LS1tZV3P33fN1gkyRB2LoRL+RR3f76m0HPHaby6F4Z5xr9Fv1URmATlRRUIpRQ== + dependencies: + markdown-table "^2.0.0" + mdast-util-to-markdown "~0.6.0" + + mdast-util-gfm-task-list-item@^0.1.0: + version "0.1.6" + resolved "https://registry.yarnpkg.com/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-0.1.6.tgz#70c885e6b9f543ddd7e6b41f9703ee55b084af10" + integrity sha512-/d51FFIfPsSmCIRNp7E6pozM9z1GYPIkSy1urQ8s/o4TC22BZ7DqfHFWiqBD23bc7J3vV1Fc9O4QIHBlfuit8A== + dependencies: + mdast-util-to-markdown "~0.6.0" + + mdast-util-gfm@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/mdast-util-gfm/-/mdast-util-gfm-0.1.2.tgz#8ecddafe57d266540f6881f5c57ff19725bd351c" + integrity sha512-NNkhDx/qYcuOWB7xHUGWZYVXvjPFFd6afg6/e2g+SV4r9q5XUcCbV4Wfa3DLYIiD+xAEZc6K4MGaE/m0KDcPwQ== + dependencies: + mdast-util-gfm-autolink-literal "^0.1.0" + mdast-util-gfm-strikethrough "^0.2.0" + mdast-util-gfm-table "^0.1.0" + mdast-util-gfm-task-list-item "^0.1.0" + mdast-util-to-markdown "^0.6.1" + + mdast-util-mdx-expression@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mdast-util-mdx-expression/-/mdast-util-mdx-expression-1.2.0.tgz#3e927afe27943956dc5d1c64cb949652062f71ff" + integrity sha512-wb36oi09XxqO9RVqgfD+xo8a7xaNgS+01+k3v0GKW0X0bYbeBmUZz22Z/IJ8SuphVlG+DNgNo9VoEaUJ3PKfJQ== + dependencies: + "@types/estree-jsx" "^0.0.1" + "@types/hast" "^2.0.0" + "@types/mdast" "^3.0.0" + mdast-util-from-markdown "^1.0.0" + mdast-util-to-markdown "^1.0.0" + + mdast-util-mdx-jsx@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-2.0.1.tgz#03d003c8b0b4bd94ab092d876c0f92d2b0c83b0b" + integrity sha512-oPC7/smPBf7vxnvIYH5y3fPo2lw1rdrswFfSb4i0GTAXRUQv7JUU/t/hbp07dgGdUFTSDOHm5DNamhNg/s2Hrg== + dependencies: + "@types/estree-jsx" "^0.0.1" + "@types/hast" "^2.0.0" + "@types/mdast" "^3.0.0" + ccount "^2.0.0" + mdast-util-to-markdown "^1.3.0" + parse-entities "^4.0.0" + stringify-entities "^4.0.0" + unist-util-remove-position "^4.0.0" + unist-util-stringify-position "^3.0.0" + vfile-message "^3.0.0" + + mdast-util-mdx@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-mdx/-/mdast-util-mdx-2.0.0.tgz#dd4f6c993cf27da32725e50a04874f595b7b63fb" + integrity sha512-M09lW0CcBT1VrJUaF/PYxemxxHa7SLDHdSn94Q9FhxjCQfuW7nMAWKWimTmA3OyDMSTH981NN1csW1X+HPSluw== + dependencies: + mdast-util-mdx-expression "^1.0.0" + mdast-util-mdx-jsx "^2.0.0" + mdast-util-mdxjs-esm "^1.0.0" + + mdast-util-mdxjs-esm@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-1.2.0.tgz#eca8b985f091c2d65a72c19d2740cefbc209aa63" + integrity sha512-IPpX9GBzAIbIRCjbyeLDpMhACFb0wxTIujuR3YElB8LWbducUdMgRJuqs/Vg8xQ1bIAMm7lw8L+YNtua0xKXRw== + dependencies: + "@types/estree-jsx" "^0.0.1" + "@types/hast" "^2.0.0" + "@types/mdast" "^3.0.0" + mdast-util-from-markdown "^1.0.0" + mdast-util-to-markdown "^1.0.0" + + mdast-util-to-hast@^11.0.0: + version "11.3.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-11.3.0.tgz#ea9220617a710e80aa5cc3ac7cc9d4bb0440ae7a" + integrity sha512-4o3Cli3hXPmm1LhB+6rqhfsIUBjnKFlIUZvudaermXB+4/KONdd/W4saWWkC+LBLbPMqhFSSTSRgafHsT5fVJw== + dependencies: + "@types/hast" "^2.0.0" + "@types/mdast" "^3.0.0" + "@types/mdurl" "^1.0.0" + mdast-util-definitions "^5.0.0" + mdurl "^1.0.0" + unist-builder "^3.0.0" + unist-util-generated "^2.0.0" + unist-util-position "^4.0.0" + unist-util-visit "^4.0.0" + + mdast-util-to-hast@^12.1.0: + version "12.1.1" + resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-12.1.1.tgz#89a2bb405eaf3b05eb8bf45157678f35eef5dbca" + integrity sha512-qE09zD6ylVP14jV4mjLIhDBOrpFdShHZcEsYvvKGABlr9mGbV7mTlRWdoFxL/EYSTNDiC9GZXy7y8Shgb9Dtzw== + dependencies: + "@types/hast" "^2.0.0" + "@types/mdast" "^3.0.0" + "@types/mdurl" "^1.0.0" + mdast-util-definitions "^5.0.0" + mdurl "^1.0.0" + micromark-util-sanitize-uri "^1.0.0" + unist-builder "^3.0.0" + unist-util-generated "^2.0.0" + unist-util-position "^4.0.0" + unist-util-visit "^4.0.0" + + mdast-util-to-markdown@^0.6.0, mdast-util-to-markdown@^0.6.1, mdast-util-to-markdown@~0.6.0: + version "0.6.5" + resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz#b33f67ca820d69e6cc527a93d4039249b504bebe" + integrity sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ== + dependencies: + "@types/unist" "^2.0.0" + longest-streak "^2.0.0" + mdast-util-to-string "^2.0.0" + parse-entities "^2.0.0" + repeat-string "^1.0.0" + zwitch "^1.0.0" + + mdast-util-to-markdown@^1.0.0, mdast-util-to-markdown@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-1.3.0.tgz#38b6cdc8dc417de642a469c4fc2abdf8c931bd1e" + integrity sha512-6tUSs4r+KK4JGTTiQ7FfHmVOaDrLQJPmpjD6wPMlHGUVXoG9Vjc3jIeP+uyBWRf8clwB2blM+W7+KrlMYQnftA== + dependencies: + "@types/mdast" "^3.0.0" + "@types/unist" "^2.0.0" + longest-streak "^3.0.0" + mdast-util-to-string "^3.0.0" + micromark-util-decode-string "^1.0.0" + unist-util-visit "^4.0.0" + zwitch "^2.0.0" + + mdast-util-to-string@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz#b8cfe6a713e1091cb5b728fc48885a4767f8b97b" + integrity sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w== + + mdast-util-to-string@^3.0.0, mdast-util-to-string@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz#56c506d065fbf769515235e577b5a261552d56e9" + integrity sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA== + + mdurl@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= + + media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + + "memoize-one@>=3.1.1 <6", memoize-one@^5.0.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" + integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== + + memory-pager@^1.0.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" + integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== + + memorystream@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" + integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI= + + merge-class-names@^1.1.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/merge-class-names/-/merge-class-names-1.4.2.tgz#78d6d95ab259e7e647252a7988fd25a27d5a8835" + integrity sha512-bOl98VzwCGi25Gcn3xKxnR5p/WrhWFQB59MS/aGENcmUc6iSm96yrFDF0XSNurX9qN4LbJm0R9kfvsQ17i8zCw== + + merge-descriptors@1.0.1, merge-descriptors@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + + merge-refs@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/merge-refs/-/merge-refs-1.0.0.tgz#388348bce22e623782c6df9d3c4fc55888276120" + integrity sha512-WZ4S5wqD9FCR9hxkLgvcHJCBxzXzy3VVE6p8W2OzxRzB+hLRlcadGE2bW9xp2KSzk10rvp4y+pwwKO6JQVguMg== + + merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + + merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + + methods@^1.1.2, methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + + micro@9.3.4, micro@^9.3.4: + version "9.3.4" + resolved "https://registry.yarnpkg.com/micro/-/micro-9.3.4.tgz#745a494e53c8916f64fb6a729f8cbf2a506b35ad" + integrity sha512-smz9naZwTG7qaFnEZ2vn248YZq9XR+XoOH3auieZbkhDL4xLOxiE+KqG8qqnBeKfXA9c1uEFGCxPN1D+nT6N7w== + dependencies: + arg "4.1.0" + content-type "1.0.4" + is-stream "1.1.0" + raw-body "2.3.2" + + micromark-core-commonmark@^1.0.0, micromark-core-commonmark@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz#edff4c72e5993d93724a3c206970f5a15b0585ad" + integrity sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA== + dependencies: + decode-named-character-reference "^1.0.0" + micromark-factory-destination "^1.0.0" + micromark-factory-label "^1.0.0" + micromark-factory-space "^1.0.0" + micromark-factory-title "^1.0.0" + micromark-factory-whitespace "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-chunked "^1.0.0" + micromark-util-classify-character "^1.0.0" + micromark-util-html-tag-name "^1.0.0" + micromark-util-normalize-identifier "^1.0.0" + micromark-util-resolve-all "^1.0.0" + micromark-util-subtokenize "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.1" + uvu "^0.5.0" + + micromark-extension-gfm-autolink-literal@~0.5.0: + version "0.5.7" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-0.5.7.tgz#53866c1f0c7ef940ae7ca1f72c6faef8fed9f204" + integrity sha512-ePiDGH0/lhcngCe8FtH4ARFoxKTUelMp4L7Gg2pujYD5CSMb9PbblnyL+AAMud/SNMyusbS2XDSiPIRcQoNFAw== + dependencies: + micromark "~2.11.3" + + micromark-extension-gfm-strikethrough@~0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-0.6.5.tgz#96cb83356ff87bf31670eefb7ad7bba73e6514d1" + integrity sha512-PpOKlgokpQRwUesRwWEp+fHjGGkZEejj83k9gU5iXCbDG+XBA92BqnRKYJdfqfkrRcZRgGuPuXb7DaK/DmxOhw== + dependencies: + micromark "~2.11.0" + + micromark-extension-gfm-table@~0.4.0: + version "0.4.3" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-0.4.3.tgz#4d49f1ce0ca84996c853880b9446698947f1802b" + integrity sha512-hVGvESPq0fk6ALWtomcwmgLvH8ZSVpcPjzi0AjPclB9FsVRgMtGZkUcpE0zgjOCFAznKepF4z3hX8z6e3HODdA== + dependencies: + micromark "~2.11.0" + + micromark-extension-gfm-tagfilter@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-0.3.0.tgz#d9f26a65adee984c9ccdd7e182220493562841ad" + integrity sha512-9GU0xBatryXifL//FJH+tAZ6i240xQuFrSL7mYi8f4oZSbc+NvXjkrHemeYP0+L4ZUT+Ptz3b95zhUZnMtoi/Q== + + micromark-extension-gfm-task-list-item@~0.3.0: + version "0.3.3" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-0.3.3.tgz#d90c755f2533ed55a718129cee11257f136283b8" + integrity sha512-0zvM5iSLKrc/NQl84pZSjGo66aTGd57C1idmlWmE87lkMcXrTxg1uXa/nXomxJytoje9trP0NDLvw4bZ/Z/XCQ== + dependencies: + micromark "~2.11.0" + + micromark-extension-gfm@^0.3.0: + version "0.3.3" + resolved "https://registry.yarnpkg.com/micromark-extension-gfm/-/micromark-extension-gfm-0.3.3.tgz#36d1a4c089ca8bdfd978c9bd2bf1a0cb24e2acfe" + integrity sha512-oVN4zv5/tAIA+l3GbMi7lWeYpJ14oQyJ3uEim20ktYFAcfX1x3LNlFGGlmrZHt7u9YlKExmyJdDGaTt6cMSR/A== + dependencies: + micromark "~2.11.0" + micromark-extension-gfm-autolink-literal "~0.5.0" + micromark-extension-gfm-strikethrough "~0.6.5" + micromark-extension-gfm-table "~0.4.0" + micromark-extension-gfm-tagfilter "~0.3.0" + micromark-extension-gfm-task-list-item "~0.3.0" + + micromark-extension-mdx-expression@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-1.0.3.tgz#cd3843573921bf55afcfff4ae0cd2e857a16dcfa" + integrity sha512-TjYtjEMszWze51NJCZmhv7MEBcgYRgb3tJeMAJ+HQCAaZHHRBaDCccqQzGizR/H4ODefP44wRTgOn2vE5I6nZA== + dependencies: + micromark-factory-mdx-expression "^1.0.0" + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-events-to-acorn "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + + micromark-extension-mdx-jsx@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-1.0.3.tgz#9f196be5f65eb09d2a49b237a7b3398bba2999be" + integrity sha512-VfA369RdqUISF0qGgv2FfV7gGjHDfn9+Qfiv5hEwpyr1xscRj/CiVRkU7rywGFCO7JwJ5L0e7CJz60lY52+qOA== + dependencies: + "@types/acorn" "^4.0.0" + estree-util-is-identifier-name "^2.0.0" + micromark-factory-mdx-expression "^1.0.0" + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + vfile-message "^3.0.0" + + micromark-extension-mdx-md@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-mdx-md/-/micromark-extension-mdx-md-1.0.0.tgz#382f5df9ee3706dd120b51782a211f31f4760d22" + integrity sha512-xaRAMoSkKdqZXDAoSgp20Azm0aRQKGOl0RrS81yGu8Hr/JhMsBmfs4wR7m9kgVUIO36cMUQjNyiyDKPrsv8gOw== + dependencies: + micromark-util-types "^1.0.0" + + micromark-extension-mdxjs-esm@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-1.0.2.tgz#df0c48743a0b1988119489c68314160b7942ffa6" + integrity sha512-bIaxblNIM+CCaJvp3L/V+168l79iuNmxEiTU6i3vB0YuDW+rumV64BFMxvhfRDxaJxQE1zD5vTPdyLBbW4efGA== + dependencies: + micromark-core-commonmark "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-events-to-acorn "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + unist-util-position-from-estree "^1.1.0" + uvu "^0.5.0" + vfile-message "^3.0.0" + + micromark-extension-mdxjs@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-extension-mdxjs/-/micromark-extension-mdxjs-1.0.0.tgz#772644e12fc8299a33e50f59c5aa15727f6689dd" + integrity sha512-TZZRZgeHvtgm+IhtgC2+uDMR7h8eTKF0QUX9YsgoL9+bADBpBY6SiLvWqnBlLbCEevITmTqmEuY3FoxMKVs1rQ== + dependencies: + acorn "^8.0.0" + acorn-jsx "^5.0.0" + micromark-extension-mdx-expression "^1.0.0" + micromark-extension-mdx-jsx "^1.0.0" + micromark-extension-mdx-md "^1.0.0" + micromark-extension-mdxjs-esm "^1.0.0" + micromark-util-combine-extensions "^1.0.0" + micromark-util-types "^1.0.0" + + micromark-factory-destination@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz#fef1cb59ad4997c496f887b6977aa3034a5a277e" + integrity sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + + micromark-factory-label@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz#6be2551fa8d13542fcbbac478258fb7a20047137" + integrity sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + + micromark-factory-mdx-expression@^1.0.0: + version "1.0.6" + resolved "https://registry.yarnpkg.com/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-1.0.6.tgz#917e17d16e6e9c2551f3a862e6a9ebdd22056476" + integrity sha512-WRQIc78FV7KrCfjsEf/sETopbYjElh3xAmNpLkd1ODPqxEngP42eVRGbiPEQWpRV27LzqW+XVTvQAMIIRLPnNA== + dependencies: + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-events-to-acorn "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + unist-util-position-from-estree "^1.0.0" + uvu "^0.5.0" + vfile-message "^3.0.0" + + micromark-factory-space@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz#cebff49968f2b9616c0fcb239e96685cb9497633" + integrity sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-types "^1.0.0" + + micromark-factory-title@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz#7e09287c3748ff1693930f176e1c4a328382494f" + integrity sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A== + dependencies: + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + + micromark-factory-whitespace@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz#e991e043ad376c1ba52f4e49858ce0794678621c" + integrity sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A== + dependencies: + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + + micromark-util-character@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-1.1.0.tgz#d97c54d5742a0d9611a68ca0cd4124331f264d86" + integrity sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg== + dependencies: + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + + micromark-util-chunked@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz#5b40d83f3d53b84c4c6bce30ed4257e9a4c79d06" + integrity sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g== + dependencies: + micromark-util-symbol "^1.0.0" + + micromark-util-classify-character@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz#cbd7b447cb79ee6997dd274a46fc4eb806460a20" + integrity sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + + micromark-util-combine-extensions@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz#91418e1e74fb893e3628b8d496085639124ff3d5" + integrity sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA== + dependencies: + micromark-util-chunked "^1.0.0" + micromark-util-types "^1.0.0" + + micromark-util-decode-numeric-character-reference@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz#dcc85f13b5bd93ff8d2868c3dba28039d490b946" + integrity sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w== + dependencies: + micromark-util-symbol "^1.0.0" + + micromark-util-decode-string@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz#942252ab7a76dec2dbf089cc32505ee2bc3acf02" + integrity sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q== + dependencies: + decode-named-character-reference "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-decode-numeric-character-reference "^1.0.0" + micromark-util-symbol "^1.0.0" + + micromark-util-encode@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz#2c1c22d3800870ad770ece5686ebca5920353383" + integrity sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA== + + micromark-util-events-to-acorn@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-1.0.4.tgz#07d26cd675dbca8c38b8d9aff2d4cdc91c9997aa" + integrity sha512-dpo8ecREK5s/KMph7jJ46RLM6g7N21CMc9LAJQbDLdbQnTpijigkSJPTIfLXZ+h5wdXlcsQ+b6ufAE9v76AdgA== + dependencies: + "@types/acorn" "^4.0.0" + "@types/estree" "^0.0.50" + estree-util-visit "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + vfile-message "^3.0.0" + + micromark-util-html-tag-name@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.0.0.tgz#75737e92fef50af0c6212bd309bc5cb8dbd489ed" + integrity sha512-NenEKIshW2ZI/ERv9HtFNsrn3llSPZtY337LID/24WeLqMzeZhBEE6BQ0vS2ZBjshm5n40chKtJ3qjAbVV8S0g== + + micromark-util-normalize-identifier@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz#4a3539cb8db954bbec5203952bfe8cedadae7828" + integrity sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg== + dependencies: + micromark-util-symbol "^1.0.0" + + micromark-util-resolve-all@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz#a7c363f49a0162e931960c44f3127ab58f031d88" + integrity sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw== + dependencies: + micromark-util-types "^1.0.0" + + micromark-util-sanitize-uri@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.0.0.tgz#27dc875397cd15102274c6c6da5585d34d4f12b2" + integrity sha512-cCxvBKlmac4rxCGx6ejlIviRaMKZc0fWm5HdCHEeDWRSkn44l6NdYVRyU+0nT1XC72EQJMZV8IPHF+jTr56lAg== + dependencies: + micromark-util-character "^1.0.0" + micromark-util-encode "^1.0.0" + micromark-util-symbol "^1.0.0" + + micromark-util-subtokenize@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz#ff6f1af6ac836f8bfdbf9b02f40431760ad89105" + integrity sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA== + dependencies: + micromark-util-chunked "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.0" + uvu "^0.5.0" + + micromark-util-symbol@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-1.0.1.tgz#b90344db62042ce454f351cf0bebcc0a6da4920e" + integrity sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ== + + micromark-util-types@^1.0.0, micromark-util-types@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-1.0.2.tgz#f4220fdb319205812f99c40f8c87a9be83eded20" + integrity sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w== + + micromark@^2.11.3, micromark@~2.11.0, micromark@~2.11.3: + version "2.11.4" + resolved "https://registry.yarnpkg.com/micromark/-/micromark-2.11.4.tgz#d13436138eea826383e822449c9a5c50ee44665a" + integrity sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA== + dependencies: + debug "^4.0.0" + parse-entities "^2.0.0" + + micromark@^3.0.0: + version "3.0.10" + resolved "https://registry.yarnpkg.com/micromark/-/micromark-3.0.10.tgz#1eac156f0399d42736458a14b0ca2d86190b457c" + integrity sha512-ryTDy6UUunOXy2HPjelppgJ2sNfcPz1pLlMdA6Rz9jPzhLikWXv/irpWV/I2jd68Uhmny7hHxAlAhk4+vWggpg== + dependencies: + "@types/debug" "^4.0.0" + debug "^4.0.0" + decode-named-character-reference "^1.0.0" + micromark-core-commonmark "^1.0.1" + micromark-factory-space "^1.0.0" + micromark-util-character "^1.0.0" + micromark-util-chunked "^1.0.0" + micromark-util-combine-extensions "^1.0.0" + micromark-util-decode-numeric-character-reference "^1.0.0" + micromark-util-encode "^1.0.0" + micromark-util-normalize-identifier "^1.0.0" + micromark-util-resolve-all "^1.0.0" + micromark-util-sanitize-uri "^1.0.0" + micromark-util-subtokenize "^1.0.0" + micromark-util-symbol "^1.0.0" + micromark-util-types "^1.0.1" + uvu "^0.5.0" + + micromatch@^3.1.4: + version "3.1.10" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + braces "^2.3.1" + define-property "^2.0.2" + extend-shallow "^3.0.2" + extglob "^2.0.4" + fragment-cache "^0.2.1" + kind-of "^6.0.2" + nanomatch "^1.2.9" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.2" + + micromatch@^4.0.2, micromatch@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== + dependencies: + braces "^3.0.1" + picomatch "^2.2.3" + + microseconds@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/microseconds/-/microseconds-0.2.0.tgz#233b25f50c62a65d861f978a4a4f8ec18797dc39" + integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA== + + miller-rabin@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + + mime-db@1.52.0, mime-db@^1.28.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + + mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + + mime@1.6.0, mime@^1.3.4: + version "1.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + + mime@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" + integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== + + mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + + mimic-response@^1.0.0, mimic-response@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + + min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= + dependencies: + dom-walk "^0.1.0" + + mini-create-react-context@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz#072171561bfdc922da08a60c2197a497cc2d1d5e" + integrity sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ== + dependencies: + "@babel/runtime" "^7.12.1" + tiny-warning "^1.0.3" + + mini-svg-data-uri@^1.2.3: + version "1.4.4" + resolved "https://registry.yarnpkg.com/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz#8ab0aabcdf8c29ad5693ca595af19dd2ead09939" + integrity sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg== + + minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + + minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= + + minimatch@3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + dependencies: + brace-expansion "^1.1.7" + + minimatch@^3.0.4, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + + minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + + minipass@^2.6.0, minipass@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" + integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + + minizlib@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" + integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== + dependencies: + minipass "^2.9.0" + + mixin-deep@^1.2.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== + dependencies: + for-in "^1.0.2" + is-extendable "^1.0.1" + + mkdirp-promise@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz#e9b8f68e552c68a9c1713b84883f7a1dd039b8a1" + integrity sha1-6bj2jlUsaKnBcTuEiD96HdA5uKE= + dependencies: + mkdirp "*" + + mkdirp@*, mkdirp@1.x, mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + + mkdirp@^0.5.1, mkdirp@^0.5.5: + version "0.5.5" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== + dependencies: + minimist "^1.2.5" + + mock-fs@^4.1.0: + version "4.14.0" + resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" + integrity sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw== + + mockdate@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/mockdate/-/mockdate-3.0.5.tgz#789be686deb3149e7df2b663d2bc4392bc3284fb" + integrity sha512-iniQP4rj1FhBdBYS/+eQv7j1tadJ9lJtdzgOpvsOHng/GbcDh2Fhdeq+ZRldrPYdXvCyfFUmFeEwEGXZB5I/AQ== + + module-alias@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/module-alias/-/module-alias-2.2.2.tgz#151cdcecc24e25739ff0aa6e51e1c5716974c0e0" + integrity sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q== + + mongodb-connection-string-url@^2.3.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.2.tgz#f075c8d529e8d3916386018b8a396aed4f16e5ed" + integrity sha512-tWDyIG8cQlI5k3skB6ywaEA5F9f5OntrKKsT/Lteub2zgwSUlhqEN2inGgBTm8bpYJf8QYBdA/5naz65XDpczA== + dependencies: + "@types/whatwg-url" "^8.2.1" + whatwg-url "^11.0.0" + + mongodb@4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-4.3.0.tgz#beac457cf57ea1b5c76ec67b8bbd6a63254bbc7c" + integrity sha512-ovq9ZD9wEvab+LsaQOiwtne1Sy2egaHW8K/H5M18Tv+V5PgTRi+qdmxDGlbm94TSL3h56m6amstptu115Nzgow== + dependencies: + bson "^4.6.1" + denque "^2.0.1" + mongodb-connection-string-url "^2.3.2" + socks "^2.6.1" + optionalDependencies: + saslprep "^1.0.3" + + mri@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" + integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== + + mrmime@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.0.tgz#14d387f0585a5233d291baba339b063752a2398b" + integrity sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ== + + ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + + ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + + ms@2.1.3, ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + + multibase@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.7.0.tgz#1adfc1c50abe05eefeb5091ac0c2728d6b84581b" + integrity sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg== + dependencies: + base-x "^3.0.8" + buffer "^5.5.0" + + multibase@~0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.6.1.tgz#b76df6298536cc17b9f6a6db53ec88f85f8cc12b" + integrity sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw== + dependencies: + base-x "^3.0.8" + buffer "^5.5.0" + + multicodec@^0.5.5: + version "0.5.7" + resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-0.5.7.tgz#1fb3f9dd866a10a55d226e194abba2dcc1ee9ffd" + integrity sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA== + dependencies: + varint "^5.0.0" + + multicodec@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-1.0.4.tgz#46ac064657c40380c28367c90304d8ed175a714f" + integrity sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg== + dependencies: + buffer "^5.6.0" + varint "^5.0.0" + + multihashes@^0.4.15, multihashes@~0.4.15: + version "0.4.21" + resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-0.4.21.tgz#dc02d525579f334a7909ade8a122dabb58ccfcb5" + integrity sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw== + dependencies: + buffer "^5.5.0" + multibase "^0.7.0" + varint "^5.0.0" + + mysql2@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/mysql2/-/mysql2-2.3.3.tgz#944f3deca4b16629052ff8614fbf89d5552545a0" + integrity sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA== + dependencies: + denque "^2.0.1" + generate-function "^2.3.1" + iconv-lite "^0.6.3" + long "^4.0.0" + lru-cache "^6.0.0" + named-placeholders "^1.1.2" + seq-queue "^0.0.5" + sqlstring "^2.3.2" + + mz@^2.4.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + + named-placeholders@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/named-placeholders/-/named-placeholders-1.1.2.tgz#ceb1fbff50b6b33492b5cf214ccf5e39cef3d0e8" + integrity sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA== + dependencies: + lru-cache "^4.1.3" + + nano-json-stream-parser@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz#0cc8f6d0e2b622b479c40d499c46d64b755c6f5f" + integrity sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18= + + nano-time@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef" + integrity sha1-sFVPaa2J4i0JB/ehKwmTpdlhN+8= + dependencies: + big-integer "^1.6.16" + + nanoclone@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/nanoclone/-/nanoclone-0.2.1.tgz#dd4090f8f1a110d26bb32c49ed2f5b9235209ed4" + integrity sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA== + + nanoid@^3.1.23, nanoid@^3.1.30, nanoid@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== + nanomatch@^1.2.9: + version "1.2.13" + resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== + dependencies: + arr-diff "^4.0.0" + array-unique "^0.3.2" + define-property "^2.0.2" + extend-shallow "^3.0.2" + fragment-cache "^0.2.1" + is-windows "^1.0.2" + kind-of "^6.0.2" + object.pick "^1.3.0" + regex-not "^1.0.0" + snapdragon "^0.8.1" + to-regex "^3.0.1" + + natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= + + negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + + neo-async@^2.6.0: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + + next-auth@^4.0.6: + version "4.3.0" + resolved "https://registry.yarnpkg.com/next-auth/-/next-auth-4.3.0.tgz#93274254f9e6263c3c3edf7169a92fb13a700619" + integrity sha512-QcXY0EkIoCHDJ/G5n5H1wG7c/E5WlnyTsA+N4un9ys+RF26Vv/kzIuzjSrVQ/no0PkIwQti6E+ZjpqXJCBykTA== + dependencies: + "@babel/runtime" "^7.16.3" + "@panva/hkdf" "^1.0.1" + cookie "^0.4.1" + jose "^4.3.7" + oauth "^0.9.15" + openid-client "^5.1.0" + preact "^10.6.3" + preact-render-to-string "^5.1.19" + uuid "^8.3.2" + + next-i18next@^8.9.0: + version "8.10.0" + resolved "https://registry.yarnpkg.com/next-i18next/-/next-i18next-8.10.0.tgz#94440d796d7c3d16a74218ac72df296daf13aaa3" + integrity sha512-nY3tw+uU6lzZq7YfqRr0lFBiz15txIeYBX5R6rVeAK8wWFsCRJpZ6lTm02DMC+MfD1G6LmtpR6bmOOaBD3TR9A== + dependencies: + "@babel/runtime" "^7.13.17" + "@types/hoist-non-react-statics" "^3.3.1" + core-js "^3" + hoist-non-react-statics "^3.2.0" + i18next "^20.1.0" + i18next-fs-backend "^1.0.7" + react-i18next "^11.8.13" + + next-plausible@^2.1.2: + version "2.2.0" + resolved "https://registry.yarnpkg.com/next-plausible/-/next-plausible-2.2.0.tgz#f825842f97bce0062bdaf897328c4908d7ce0a78" + integrity sha512-pIhs5MikL6ZMJvB7sxkM49xN06W1A6d6RYta5vrqwQmF2/oXoCG+IPoaPzyODZ/vo7f2/NMAOaUm5QM0dKqMdA== + + next-seo@^4.26.0: + version "4.29.0" + resolved "https://registry.yarnpkg.com/next-seo/-/next-seo-4.29.0.tgz#d281e95ba47914117cc99e9e468599f0547d9b9b" + integrity sha512-xmwzcz4uHaYJ8glbuhs6FSBQ7z3irmdPYdJJ5saWm72Uy3o+mPKGaPCXQetTCE6/xxVnpoDV4yFtFlEjUcljSg== + + next-themes@^0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.0.8.tgz#2a1748317085afbc2509e2c32bd04af4f0f6cb7d" + integrity sha512-dyrh+/bZW4hkecFEg2rfwOLLzU2UnE7KfiwcV0mIwkPrO+1n1WvwkC8nabgKA5Eoi8stkYfjmA72FxTaWEOHtg== + + next-tick@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" + integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== + + next-transpile-modules@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/next-transpile-modules/-/next-transpile-modules-8.0.0.tgz#56375cdc25ae5d23a834195f277fc2737b26cb97" + integrity sha512-Q2f2yB0zMJ8KJbIYAeZoIxG6cSfVk813zr6B5HzsLMBVcJ3FaF8lKr7WG66n0KlHCwjLSmf/6EkgI6QQVWHrDw== + dependencies: + enhanced-resolve "^5.7.0" + escalade "^3.1.1" + + next-transpile-modules@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/next-transpile-modules/-/next-transpile-modules-9.0.0.tgz#133b1742af082e61cc76b02a0f12ffd40ce2bf90" + integrity sha512-VCNFOazIAnXn1hvgYYSTYMnoWgKgwlYh4lm1pKbSfiB3kj5ZYLcKVhfh3jkPOg1cnd9DP+pte9yCUocdPEUBTQ== + dependencies: + enhanced-resolve "^5.7.0" + escalade "^3.1.1" + + next-validations@^0.1.11: + version "0.1.11" + resolved "https://registry.yarnpkg.com/next-validations/-/next-validations-0.1.11.tgz#fcc62dea5be8f9793d410de175f96e3fc1dac54d" + integrity sha512-rdyRgZ3f3jwhLigdi9MC5R74BvRpB3cewa8LVnMHDiDRnSThvX0CdZ5KHK4t/SgrIGaVXiXOQ59KtvBqjcm5pA== + next@^12.1.0: version "12.1.0" resolved "https://registry.yarnpkg.com/next/-/next-12.1.0.tgz#c33d753b644be92fc58e06e5a214f143da61dd5d" @@ -163,16 +11145,961 @@ Lockfile: "@next/swc-win32-ia32-msvc" "12.1.0" "@next/swc-win32-x64-msvc" "12.1.0" - object-assign@^4.1.1: + nextra-theme-docs@^1.2.2: + version "1.2.6" + resolved "https://registry.yarnpkg.com/nextra-theme-docs/-/nextra-theme-docs-1.2.6.tgz#e6d5d8788534ae62d589db96df65f1a6e8b60bcc" + integrity sha512-6tSq74EEw/lfZXfrN9TXr8UFov1mddW+yXnwQB57XRF9hBVq3WtVl6lJT7Xe9q0S0s9lkEeGviHtq+NRpONcQQ== + dependencies: + "@mdx-js/react" "^1.6.16" + "@reach/skip-nav" "^0.11.2" + classnames "^2.2.6" + focus-visible "^5.1.0" + github-slugger "^1.3.0" + grapheme-splitter "^1.0.4" + intersection-observer "^0.12.0" + match-sorter "^4.2.0" + next-themes "^0.0.8" + parse-git-url "^1.0.1" + prism-react-renderer "^1.1.1" + react-innertext "^1.1.5" + title "^3.4.2" + + nextra@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/nextra/-/nextra-1.1.0.tgz#94df0d975537f3e538d91a9b61101a4bc3e93fc8" + integrity sha512-WxD1c05gs4cyPHWvqOei9ofIQkLjtzQaDQo8+56f5ss7yJ6ZyI7Ohx7nyyjm6yTo1fO8gfj3v1l/AZmLnjh4FA== + dependencies: + "@mdx-js/loader" "^2.0.0-next.9" + download "^8.0.0" + graceful-fs "^4.2.6" + gray-matter "^4.0.3" + loader-utils "^2.0.0" + remark "^13.0.0" + remark-gfm "^1.0.0" + slash "^3.0.0" + strip-markdown "^4.0.0" + + nice-try@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== + + node-addon-api@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" + integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== + + node-fetch@2.6.7, node-fetch@^2.6.1: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" + + node-forge@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.2.1.tgz#82794919071ef2eb5c509293325cec8afd0fd53c" + integrity sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w== + + node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" + integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q== + + node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= + + node-mocks-http@^1.11.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/node-mocks-http/-/node-mocks-http-1.11.0.tgz#defc0febf6b935f08245397d47534a8de592996e" + integrity sha512-jS/WzSOcKbOeGrcgKbenZeNhxUNnP36Yw11+hL4TTxQXErGfqYZ+MaYNNvhaTiGIJlzNSqgQkk9j8dSu1YWSuw== + dependencies: + accepts "^1.3.7" + content-disposition "^0.5.3" + depd "^1.1.0" + fresh "^0.5.2" + merge-descriptors "^1.0.1" + methods "^1.1.2" + mime "^1.3.4" + parseurl "^1.3.3" + range-parser "^1.2.0" + type-is "^1.6.18" + + node-notifier@^8.0.0: + version "8.0.2" + resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.2.tgz#f3167a38ef0d2c8a866a83e318c1ba0efeb702c5" + integrity sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg== + dependencies: + growly "^1.3.0" + is-wsl "^2.2.0" + semver "^7.3.2" + shellwords "^0.1.1" + uuid "^8.3.0" + which "^2.0.2" + + node-releases@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01" + integrity sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg== + + nodemailer@^6.7.2: + version "6.7.2" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.7.2.tgz#44b2ad5f7ed71b7067f7a21c4fedabaec62b85e0" + integrity sha512-Dz7zVwlef4k5R71fdmxwR8Q39fiboGbu3xgswkzGwczUfjp873rVxt1O46+Fh0j1ORnAC6L9+heI8uUpO6DT7Q== + + normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + + normalize-path@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= + dependencies: + remove-trailing-separator "^1.0.1" + + normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + + normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= + + normalize-url@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" + integrity sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw== + dependencies: + prepend-http "^2.0.0" + query-string "^5.0.1" + sort-keys "^2.0.0" + + normalize-url@^4.1.0: + version "4.5.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" + integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== + + normalize-wheel@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/normalize-wheel/-/normalize-wheel-1.0.1.tgz#aec886affdb045070d856447df62ecf86146ec45" + integrity sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU= + + npm-run-all@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba" + integrity sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ== + dependencies: + ansi-styles "^3.2.1" + chalk "^2.4.1" + cross-spawn "^6.0.5" + memorystream "^0.3.1" + minimatch "^3.0.4" + pidtree "^0.3.0" + read-pkg "^3.0.0" + shell-quote "^1.6.1" + string.prototype.padend "^3.0.0" + + npm-run-path@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= + dependencies: + path-key "^2.0.0" + + npm-run-path@^4.0.0, npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + + number-to-bn@1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" + integrity sha1-uzYjWS9+X54AMLGXe9QaDFP+HqA= + dependencies: + bn.js "4.11.6" + strip-hex-prefix "1.0.0" + + nwsapi@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" + integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== + + oauth-sign@~0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + + oauth@^0.9.15: + version "0.9.15" + resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" + integrity sha1-vR/vr2hslrdUda7VGWQS/2DPucE= + + object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + object-copy@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= + dependencies: + copy-descriptor "^0.1.0" + define-property "^0.2.5" + kind-of "^3.0.3" + + object-hash@^2.0.1, object-hash@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5" + integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw== + + object-inspect@^1.11.0, object-inspect@^1.12.0, object-inspect@^1.9.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" + integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== + + object-keys@^1.0.12, object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + + object-keys@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.2.0.tgz#cddec02998b091be42bf1035ae32e49f1cb6ea67" + integrity sha1-zd7AKZiwkb5CvxA1rjLknxy26mc= + dependencies: + foreach "~2.0.1" + indexof "~0.0.1" + is "~0.2.6" + + object-keys@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" + integrity sha1-KKaq50KN0sOpLz2V8hM13SBOAzY= + + object-visit@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= + dependencies: + isobject "^3.0.0" + + object.assign@^4.1.0, object.assign@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" + integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + has-symbols "^1.0.1" + object-keys "^1.1.1" + + object.entries@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" + integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + + object.fromentries@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.5.tgz#7b37b205109c21e741e605727fe8b0ad5fa08251" + integrity sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + + object.hasown@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.0.tgz#7232ed266f34d197d15cac5880232f7a4790afe5" + integrity sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg== + dependencies: + define-properties "^1.1.3" + es-abstract "^1.19.1" + + object.pick@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= + dependencies: + isobject "^3.0.1" + + object.values@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" + integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + + oblivious-set@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.0.0.tgz#c8316f2c2fb6ff7b11b6158db3234c49f733c566" + integrity sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw== + + oboe@2.1.5: + version "2.1.5" + resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.5.tgz#5554284c543a2266d7a38f17e073821fbde393cd" + integrity sha1-VVQoTFQ6ImbXo48X4HOCH73jk80= + dependencies: + http-https "^1.0.0" + + octal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/octal/-/octal-1.0.0.tgz#63e7162a68efbeb9e213588d58e989d1e5c4530b" + integrity sha1-Y+cWKmjvvrniE1iNWOmJ0eXEUws= + + oidc-token-hash@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/oidc-token-hash/-/oidc-token-hash-5.0.1.tgz#ae6beec3ec20f0fd885e5400d175191d6e2f10c6" + integrity sha512-EvoOtz6FIEBzE+9q253HsLCVRiK/0doEJ2HCvvqMQb3dHZrP3WlJKYtJ55CRTw4jmYomzH4wkPuCj/I3ZvpKxQ== + + omggif@^1.0.10, omggif@^1.0.9: + version "1.0.10" + resolved "https://registry.yarnpkg.com/omggif/-/omggif-1.0.10.tgz#ddaaf90d4a42f532e9e7cb3a95ecdd47f17c7b19" + integrity sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw== + + on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + dependencies: + ee-first "1.1.1" + + once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + dependencies: + wrappy "1" + + onetime@^5.1.0, onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + + open@8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" + integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + + opener@^1.5.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" + integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== + + openid-client@^5.1.0: + version "5.1.4" + resolved "https://registry.yarnpkg.com/openid-client/-/openid-client-5.1.4.tgz#1d7c44da8fcf5861c585a2f7ffe4ffe152f2abd5" + integrity sha512-36/PZY3rDgiIFj2uCL9a1fILPmIwu3HksoWO4mukgXe74ZOsEisJMMqTMfmPNw6j/7kO0mBc2xqy4eYRrB8xPA== + dependencies: + jose "^4.1.4" + lru-cache "^6.0.0" + object-hash "^2.0.1" + oidc-token-hash "^5.0.1" + + optionator@^0.8.1: + version "0.8.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.6" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + word-wrap "~1.2.3" + + optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + + otplib@^12.0.1: + version "12.0.1" + resolved "https://registry.yarnpkg.com/otplib/-/otplib-12.0.1.tgz#c1d3060ab7aadf041ed2960302f27095777d1f73" + integrity sha512-xDGvUOQjop7RDgxTQ+o4pOol0/3xSZzawTiPKRrHnQWAy0WjhNs/5HdIDJCrqC4MBynmjXgULc6YfioaxZeFgg== + dependencies: + "@otplib/core" "^12.0.1" + "@otplib/preset-default" "^12.0.1" + "@otplib/preset-v11" "^12.0.1" + + p-cancelable@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" + integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw== + + p-cancelable@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" + integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ== + + p-cancelable@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" + integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== + + p-each-series@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a" + integrity sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA== + + p-event@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/p-event/-/p-event-2.3.1.tgz#596279ef169ab2c3e0cae88c1cfbb08079993ef6" + integrity sha512-NQCqOFhbpVTMX4qMe8PF8lbGtzZ+LCiN7pcNrb/413Na7+TRoe1xkKUzuWa/YEJdGQ0FvKtj35EEbDoVPO2kbA== + dependencies: + p-timeout "^2.0.1" + + p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= + + p-is-promise@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" + integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4= + + p-limit@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" + integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== + dependencies: + p-try "^1.0.0" + + p-limit@^2.0.0, p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + + p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= + dependencies: + p-limit "^1.1.0" + + p-locate@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== + dependencies: + p-limit "^2.0.0" + + p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + + p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + + p-timeout@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" + integrity sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y= + dependencies: + p-finally "^1.0.0" + + p-timeout@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" + integrity sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA== + dependencies: + p-finally "^1.0.0" + + p-try@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" + integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= + + p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + + packet-reader@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" + integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== + + pako@^1.0.5: + version "1.0.11" + resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" + integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== + + parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + + parenthesis@^3.1.8: + version "3.1.8" + resolved "https://registry.yarnpkg.com/parenthesis/-/parenthesis-3.1.8.tgz#3457fccb8f05db27572b841dad9d2630b912f125" + integrity sha512-KF/U8tk54BgQewkJPvB4s/US3VQY68BRDpH638+7O/n58TpnwiwnOtGIOsT2/i+M78s61BBpeC83STB88d8sqw== + + parse-asn1@^5.0.0, parse-asn1@^5.1.5: + version "5.1.6" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" + integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== + dependencies: + asn1.js "^5.2.0" + browserify-aes "^1.0.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + safe-buffer "^5.1.1" + + parse-bmfont-ascii@^1.0.3: + version "1.0.6" + resolved "https://registry.yarnpkg.com/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz#11ac3c3ff58f7c2020ab22769079108d4dfa0285" + integrity sha1-Eaw8P/WPfCAgqyJ2kHkQjU36AoU= + + parse-bmfont-binary@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz#d038b476d3e9dd9db1e11a0b0e53a22792b69006" + integrity sha1-0Di0dtPp3Z2x4RoLDlOiJ5K2kAY= + + parse-bmfont-xml@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/parse-bmfont-xml/-/parse-bmfont-xml-1.1.4.tgz#015319797e3e12f9e739c4d513872cd2fa35f389" + integrity sha512-bjnliEOmGv3y1aMEfREMBJ9tfL3WR0i0CKPj61DnSLaoxWR3nLrsQrEbCId/8rF4NyRF0cCqisSVXyQYWM+mCQ== + dependencies: + xml-parse-from-string "^1.0.0" + xml2js "^0.4.5" + + parse-entities@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" + integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ== + dependencies: + character-entities "^1.0.0" + character-entities-legacy "^1.0.0" + character-reference-invalid "^1.0.0" + is-alphanumerical "^1.0.0" + is-decimal "^1.0.0" + is-hexadecimal "^1.0.0" + + parse-entities@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-4.0.0.tgz#f67c856d4e3fe19b1a445c3fabe78dcdc1053eeb" + integrity sha512-5nk9Fn03x3rEhGaX1FU6IDwG/k+GxLXlFAkgrbM1asuAFl3BhdQWvASaIsmwWypRNcZKHPYnIuOSfIWEyEQnPQ== + dependencies: + "@types/unist" "^2.0.0" + character-entities "^2.0.0" + character-entities-legacy "^3.0.0" + character-reference-invalid "^2.0.0" + decode-named-character-reference "^1.0.0" + is-alphanumerical "^2.0.0" + is-decimal "^2.0.0" + is-hexadecimal "^2.0.0" + + parse-git-url@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parse-git-url/-/parse-git-url-1.0.1.tgz#92bdaf615a7e24d32bea3bf955ee90a9050aeb57" + integrity sha512-Zukjztu09UXpXV/Q+4vgwyVPzUBkUvDjlqHlpG+swv/zYzed/5Igw/33rIEJxFDRc5LxvEqYDVDzhBfnOLWDYw== + + parse-headers@^2.0.0: + version "2.0.5" + resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.5.tgz#069793f9356a54008571eb7f9761153e6c770da9" + integrity sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA== + + parse-json@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" + integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= + dependencies: + error-ex "^1.3.1" + json-parse-better-errors "^1.0.1" + + parse-json@^5.0.0, parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + + parse5-htmlparser2-tree-adapter@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" + integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA== + dependencies: + parse5 "^6.0.1" + + parse5@6.0.1, parse5@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + + parse5@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" + integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== + + parseurl@^1.3.3, parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + + pascalcase@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= + + path-browserify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" + integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== + + path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + 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.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + + path-key@^2.0.0, path-key@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= + + path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + + path-parse@^1.0.6, path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + + path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + + path-to-regexp@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" + integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== + dependencies: + isarray "0.0.1" + + path-type@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" + integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== + dependencies: + pify "^3.0.0" + + path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + + pbkdf2@^3.0.17, pbkdf2@^3.0.3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + + pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= + + performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + + periscopic@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/periscopic/-/periscopic-3.0.4.tgz#b3fbed0d1bc844976b977173ca2cd4a0ef4fa8d1" + integrity sha512-SFx68DxCv0Iyo6APZuw/AKewkkThGwssmU0QWtTlvov3VAtPX+QJ4CadwSaz8nrT5jPIuxdvJWB4PnD2KNDxQg== + dependencies: + estree-walker "^3.0.0" + is-reference "^3.0.0" + + pg-connection-string@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.5.0.tgz#538cadd0f7e603fc09a12590f3b8a452c2c0cf34" + integrity sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ== + + pg-int8@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" + integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== + + pg-pool@^3.4.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.5.1.tgz#f499ce76f9bf5097488b3b83b19861f28e4ed905" + integrity sha512-6iCR0wVrro6OOHFsyavV+i6KYL4lVNyYAB9RD18w66xSzN+d8b66HiwuP30Gp1SH5O9T82fckkzsRjlrhD0ioQ== + + pg-protocol@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.5.0.tgz#b5dd452257314565e2d54ab3c132adc46565a6a0" + integrity sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ== + + pg-types@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" + integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== + dependencies: + pg-int8 "1.0.1" + postgres-array "~2.0.0" + postgres-bytea "~1.0.0" + postgres-date "~1.0.4" + postgres-interval "^1.1.0" + + pg@8.7.1: + version "8.7.1" + resolved "https://registry.yarnpkg.com/pg/-/pg-8.7.1.tgz#9ea9d1ec225980c36f94e181d009ab9f4ce4c471" + integrity sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA== + dependencies: + buffer-writer "2.0.0" + packet-reader "1.0.0" + pg-connection-string "^2.5.0" + pg-pool "^3.4.1" + pg-protocol "^1.5.0" + pg-types "^2.1.0" + pgpass "1.x" + + pgpass@1.x: + version "1.0.5" + resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.5.tgz#9b873e4a564bb10fa7a7dbd55312728d422a223d" + integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug== + dependencies: + split2 "^4.1.0" + + phenomenon@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/phenomenon/-/phenomenon-1.6.0.tgz#7b5b7647d0b48152cc0846994da3d92e8f6da677" + integrity sha512-7h9/fjPD3qNlgggzm88cY58l9sudZ6Ey+UmZsizfhtawO6E3srZQXywaNm2lBwT72TbpHYRPy7ytIHeBUD/G0A== + + phin@^2.9.1: + version "2.9.3" + resolved "https://registry.yarnpkg.com/phin/-/phin-2.9.3.tgz#f9b6ac10a035636fb65dfc576aaaa17b8743125c" + integrity sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA== + picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + + pidtree@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a" + integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA== + + pify@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= + + pify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" + integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= + + pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + + pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= + dependencies: + pinkie "^2.0.0" + + pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= + + pirates@4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.4.tgz#07df81e61028e402735cdd49db701e4885b4e6e6" + integrity sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw== + + pirates@^4.0.1, pirates@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" + integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== + + pixelmatch@5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-5.2.1.tgz#9e4e4f4aa59648208a31310306a5bed5522b0d65" + integrity sha512-WjcAdYSnKrrdDdqTcVEY7aB7UhhwjYQKYhHiBXdJef0MOaQeYpUdQ+iVyBLa5YBKS8MPVPPMX7rpOByISLpeEQ== + dependencies: + pngjs "^4.0.1" + + pixelmatch@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-4.0.2.tgz#8f47dcec5011b477b67db03c243bc1f3085e8854" + integrity sha1-j0fc7FARtHe2fbA8JDvB8wheiFQ= + dependencies: + pngjs "^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" + + playwright-core@1.19.2: + version "1.19.2" + resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.19.2.tgz#90b9209554f174c649abf495952fcb4335437218" + integrity sha512-OsL3sJZIo1UxKNWSP7zW7sk3FyUGG06YRHxHeBw51eIOxTCQRx5t+hXd0cvXashN2CHnd3hIZTs2aKa/im4hZQ== + dependencies: + commander "8.3.0" + debug "4.3.3" + extract-zip "2.0.1" + https-proxy-agent "5.0.0" + jpeg-js "0.4.3" + mime "3.0.0" + pngjs "6.0.0" + progress "2.0.3" + proper-lockfile "4.1.2" + proxy-from-env "1.1.0" + rimraf "3.0.2" + socks-proxy-agent "6.1.1" + stack-utils "2.0.5" + ws "8.4.2" + yauzl "2.10.0" + yazl "2.5.1" + + pngjs@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-6.0.0.tgz#ca9e5d2aa48db0228a52c419c3308e87720da821" + integrity sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg== + + pngjs@^3.0.0, pngjs@^3.3.3: + version "3.4.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f" + integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w== + + pngjs@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-4.0.1.tgz#f803869bb2fc1bfe1bf99aa4ec21c108117cfdbe" + integrity sha512-rf5+2/ioHeQxR6IxuYNYGFytUyG3lma/WW1nsmjeHlWwtb2aByla6dkVc8pmJ9nplzkTA0q2xx7mMWrOTqT4Gg== + + pngjs@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb" + integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw== + + posix-character-classes@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= + + postcss-js@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.0.tgz#31db79889531b80dc7bc9b0ad283e418dce0ac00" + integrity sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ== + dependencies: + camelcase-css "^2.0.1" + + postcss-load-config@^3.1.0: + version "3.1.3" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.3.tgz#21935b2c43b9a86e6581a576ca7ee1bde2bd1d23" + integrity sha512-5EYgaM9auHGtO//ljHH+v/aC/TQ5LHXtL7bQajNAUBKUVKiYE8rYpFms7+V26D9FncaGe2zwCoPQsFKb5zF/Hw== + dependencies: + lilconfig "^2.0.4" + yaml "^1.10.2" + + postcss-nested@5.0.6: + version "5.0.6" + resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-5.0.6.tgz#466343f7fc8d3d46af3e7dba3fcd47d052a945bc" + integrity sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA== + dependencies: + postcss-selector-parser "^6.0.6" + + postcss-selector-parser@^6.0.6, postcss-selector-parser@^6.0.9: + version "6.0.9" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz#ee71c3b9ff63d9cd130838876c13a2ec1a992b2f" + integrity sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + + postcss-value-parser@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + postcss@8.4.5: version "8.4.5" resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95" @@ -182,19 +12109,3769 @@ Lockfile: picocolors "^1.0.0" source-map-js "^1.0.1" - source-map-js@^1.0.1: + postcss@^8.3.6: + version "8.4.12" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.12.tgz#1e7de78733b28970fa4743f7da6f3763648b1905" + integrity sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg== + dependencies: + nanoid "^3.3.1" + picocolors "^1.0.0" + source-map-js "^1.0.2" + + postcss@^8.4.4, postcss@^8.4.6: + version "8.4.11" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.11.tgz#a06229f23820b4ddd46500a3e38dbca1598a8e8d" + integrity sha512-D+jFLnT0ilGfy4CVBGbC+XE68HkVpT8+CUkDrcSpgxmo4RKco2uaZ4kIoyVGEm+m8KN/+Vwgs8MtpNbQ3/ma9w== + dependencies: + nanoid "^3.3.1" + picocolors "^1.0.0" + source-map-js "^1.0.2" + + postgres-array@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" + integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== + + postgres-bytea@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" + integrity sha1-AntTPAqokOJtFy1Hz5zOzFIazTU= + + postgres-date@~1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" + integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== + + postgres-interval@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" + integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== + dependencies: + xtend "^4.0.0" + + preact-render-to-string@^5.1.19: + version "5.1.20" + resolved "https://registry.yarnpkg.com/preact-render-to-string/-/preact-render-to-string-5.1.20.tgz#9e61a478e8514e5c4140282c7c43d9747a6d32a9" + integrity sha512-ivh2oOGzth0o7XqbatWUQ81WQGoJwSqDKP5z917SoqTWYCAr7dlBzMv3SAMTAu3Gr5g47BJwrvyO44H2Y10ubg== + dependencies: + pretty-format "^3.8.0" + + preact@^10.6.3: + version "10.6.6" + resolved "https://registry.yarnpkg.com/preact/-/preact-10.6.6.tgz#f1899bc8dab7c0788b858481532cb3b5d764a520" + integrity sha512-dgxpTFV2vs4vizwKohYKkk7g7rmp1wOOcfd4Tz3IB3Wi+ivZzsn/SpeKJhRENSE+n8sUfsAl4S3HiCVT923ABw== + + prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + + prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + + prepend-http@^1.0.1: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= + + prepend-http@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" + integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= + + prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + + prettier-plugin-tailwindcss@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.1.8.tgz#ba0f606ed91959ede670303d905b99106e9e6293" + integrity sha512-hwarSBCswAXa+kqYtaAkFr3Vop9o04WOyZs0qo3NyvW8L7f1rif61wRyq0+ArmVThOuRBcJF5hjGXYk86cwemg== + + prettier@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" + integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== + + pretty-format@^26.6.2: + version "26.6.2" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" + integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== + dependencies: + "@jest/types" "^26.6.2" + ansi-regex "^5.0.0" + ansi-styles "^4.0.0" + react-is "^17.0.1" + + pretty-format@^27.0.0, pretty-format@^27.2.5, pretty-format@^27.5.1: + version "27.5.1" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" + integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== + dependencies: + ansi-regex "^5.0.1" + ansi-styles "^5.0.0" + react-is "^17.0.1" + + pretty-format@^3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-3.8.0.tgz#bfbed56d5e9a776645f4b1ff7aa1a3ac4fa3c385" + integrity sha1-v77VbV6ad2ZF9LH/eqGjrE+jw4U= + + printj@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/printj/-/printj-1.3.1.tgz#9af6b1d55647a1587ac44f4c1654a4b95b8e12cb" + integrity sha512-GA3TdL8szPK4AQ2YnOe/b+Y1jUFwmmGMMK/qbY7VcE3Z7FU8JstbKiKRzO6CIiAKPhTO8m01NoQ0V5f3jc4OGg== + + prism-react-renderer@^1.1.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/prism-react-renderer/-/prism-react-renderer-1.3.1.tgz#88fc9d0df6bed06ca2b9097421349f8c2f24e30d" + integrity sha512-xUeDMEz074d0zc5y6rxiMp/dlC7C+5IDDlaEUlcBOFE2wddz7hz5PNupb087mPwTt7T9BrFmewObfCBuf/LKwQ== + + prisma@3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.10.0.tgz#872d87afbeb1cbcaa77c3d6a63c125e0d704b04d" + integrity sha512-dAld12vtwdz9Rz01nOjmnXe+vHana5PSog8t0XGgLemKsUVsaupYpr74AHaS3s78SaTS5s2HOghnJF+jn91ZrA== + dependencies: + "@prisma/engines" "3.10.0-50.73e60b76d394f8d37d8ebd1f8918c79029f0db86" + + process-es6@^0.11.2: + version "0.11.6" + resolved "https://registry.yarnpkg.com/process-es6/-/process-es6-0.11.6.tgz#c6bb389f9a951f82bd4eb169600105bd2ff9c778" + integrity sha1-xrs4n5qVH4K9TrFpYAEFvS/5x3g= + + process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + + process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= + + progress@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + + prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + + prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: + version "15.8.1" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + + proper-lockfile@4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" + integrity sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA== + dependencies: + graceful-fs "^4.2.4" + retry "^0.12.0" + signal-exit "^3.0.2" + + property-expr@^2.0.4: + version "2.0.5" + resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.5.tgz#278bdb15308ae16af3e3b9640024524f4dc02cb4" + integrity sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA== + + property-information@^6.0.0: + version "6.1.1" + resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.1.1.tgz#5ca85510a3019726cb9afed4197b7b8ac5926a22" + integrity sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w== + + proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + + proxy-from-env@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + + prr@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" + integrity sha1-GoS4WQgyVQFBGFPQCB7j+obikmo= + + prr@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= + + pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= + + psl@^1.1.28, psl@^1.1.33: + version "1.8.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== + + public-encrypt@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + safe-buffer "^5.1.2" + + pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + + punycode@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" + integrity sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0= + + punycode@^2.1.0, punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + + pvtsutils@^1.2.1, pvtsutils@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/pvtsutils/-/pvtsutils-1.2.2.tgz#62ef6bc0513cbc255ee02574dedeaa41272d6101" + integrity sha512-OALo5ZEdqiI127i64+CXwkCOyFHUA+tCQgaUO/MvRDFXWPr53f2sx28ECNztUEzuyu5xvuuD1EB/szg9mwJoGA== + dependencies: + tslib "^2.3.1" + + pvutils@latest: + version "1.1.3" + resolved "https://registry.yarnpkg.com/pvutils/-/pvutils-1.1.3.tgz#f35fc1d27e7cd3dfbd39c0826d173e806a03f5a3" + integrity sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ== + + qrcode@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.0.tgz#95abb8a91fdafd86f8190f2836abbfc500c72d1b" + integrity sha512-9MgRpgVc+/+47dFvQeD6U2s0Z92EsKzcHogtum4QB+UNd025WOJSHvn/hjk9xmzj7Stj95CyUAs31mrjxliEsQ== + dependencies: + dijkstrajs "^1.0.1" + encode-utf8 "^1.0.3" + pngjs "^5.0.0" + yargs "^15.3.1" + + qs@6.9.6: + version "6.9.6" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.6.tgz#26ed3c8243a431b2924aca84cc90471f35d5a0ee" + integrity sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ== + + qs@6.9.7: + version "6.9.7" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe" + integrity sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw== + + qs@^6.6.0, qs@^6.7.0: + version "6.10.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e" + integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== + dependencies: + side-channel "^1.0.4" + + qs@~6.5.2: + version "6.5.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" + integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== + + query-string@^5.0.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" + integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== + dependencies: + decode-uri-component "^0.2.0" + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + + queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + + quick-lru@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" + integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== + + rambda@7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/rambda/-/rambda-7.0.1.tgz#691fac4e0ca291af303e95e2b6d357293e01923a" + integrity sha512-u4isl3leprMj337gTNc7YOfxa9p0RKlK1RXgHQvCnxjlqy95tWKLCFh+7vZ3kE4bhSX7z2TxaorFDYo20FtHJw== + + randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + + randomfill@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== + dependencies: + randombytes "^2.0.5" + safe-buffer "^5.1.0" + + range-parser@^1.2.0, range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + + raw-body@2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" + integrity sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k= + dependencies: + bytes "3.0.0" + http-errors "1.6.2" + iconv-lite "0.4.19" + unpipe "1.0.0" + + raw-body@2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.2.tgz#baf3e9c21eebced59dd6533ac872b71f7b61cb32" + integrity sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ== + dependencies: + bytes "3.1.1" + http-errors "1.8.1" + iconv-lite "0.4.24" + unpipe "1.0.0" + + raw-body@2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.3.tgz#8f80305d11c2a0a545c2d9d89d7a0286fcead43c" + integrity sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g== + dependencies: + bytes "3.1.2" + http-errors "1.8.1" + iconv-lite "0.4.24" + unpipe "1.0.0" + + react-calendar@^3.3.1: + version "3.7.0" + resolved "https://registry.yarnpkg.com/react-calendar/-/react-calendar-3.7.0.tgz#951d56e91afb33b1c1e019cb790349fbffcc6894" + integrity sha512-zkK95zWLWLC6w3O7p3SHx/FJXEyyD2UMd4jr3CrKD+G73N+G5vEwrXxYQCNivIPoFNBjqoyYYGlkHA+TBDPLCw== + dependencies: + "@wojtekmaj/date-utils" "^1.0.2" + get-user-locale "^1.2.0" + merge-class-names "^1.1.1" + prop-types "^15.6.0" + + react-colorful@^5.5.1: + version "5.5.1" + resolved "https://registry.yarnpkg.com/react-colorful/-/react-colorful-5.5.1.tgz#29d9c4e496f2ca784dd2bb5053a3a4340cfaf784" + integrity sha512-M1TJH2X3RXEt12sWkpa6hLc/bbYS0H6F4rIqjQZ+RxNBstpY67d9TrFXtqdZwhpmBXcCwEi7stKqFue3ZRkiOg== + + react-confetti@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/react-confetti/-/react-confetti-6.0.1.tgz#d4f57b5a021dd908a6243b8f63b6009b00818d10" + integrity sha512-ZpOTBrqSNhWE4rRXCZ6E6U+wGd7iYHF5MGrqwikoiBpgBq9Akdu0DcLW+FdFnLjyZYC+VfAiV2KeFgYRMyMrkA== + dependencies: + tween-functions "^1.2.0" + + react-date-picker@^8.3.6, react-date-picker@^8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/react-date-picker/-/react-date-picker-8.4.0.tgz#2d166bbaa59b08ec8686f671fde553458d19f8c8" + integrity sha512-zocntugDUyiHmV2Nq1qnsk4kDQuhBLUsDTz7akfIEJ0jVX925w0K5Ai5oZzWFNQOzXL/ITxafmDMuSbzlpBt/A== + dependencies: + "@types/react-calendar" "^3.0.0" + "@wojtekmaj/date-utils" "^1.0.3" + get-user-locale "^1.2.0" + make-event-props "^1.1.0" + merge-class-names "^1.1.1" + merge-refs "^1.0.0" + prop-types "^15.6.0" + react-calendar "^3.3.1" + react-fit "^1.4.0" + update-input-width "^1.2.2" + + react-digit-input@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/react-digit-input/-/react-digit-input-2.1.0.tgz#8b0be6d3ea247fd361855483f21d0aafba341196" + integrity sha512-pGv0CtSmu3Mf4cD79LoYtJI7Wq4dpPiLiY1wvKsNaR+X2sJyk1ETiIxjq6G8i+XJqNXExM6vuytzDqblkkSaFw== + + react-dom@17.0.2, react-dom@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" + integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + scheduler "^0.20.2" + + react-easy-crop@^3.5.2: + version "3.5.3" + resolved "https://registry.yarnpkg.com/react-easy-crop/-/react-easy-crop-3.5.3.tgz#7481b6e484a8b6ac308373f0b173aad4f1d10239" + integrity sha512-ApTbh+lzKAvKqYW81ihd5J6ZTNN3vPDwi6ncFuUrHPI4bko2DlYOESkRm+0NYoW0H8YLaD7bxox+Z3EvIzAbUA== + dependencies: + normalize-wheel "^1.0.1" + tslib "2.0.1" + + react-fit@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/react-fit/-/react-fit-1.4.0.tgz#6b6e3c75215561cc3cfb9854a6811b4347628666" + integrity sha512-cf9sFKbr1rlTB9fNIKE5Uy4NCMUOqrX2mdJ69V4RtmV4KubPdtnbIP1tEar16GXaToCRr7I7c9d2wkTNk9TV5g== + dependencies: + detect-element-overflow "^1.2.0" + prop-types "^15.6.0" + tiny-warning "^1.0.0" + + react-hook-form@^7.16.2, react-hook-form@^7.20.4: + version "7.28.0" + resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.28.0.tgz#40f385da1f31a3c26bb7491d7d77c111b6ad6909" + integrity sha512-mmLpT86BkMGPr0r6ca8zxV0WH4Y1FW5MKs7Rq1+uHLVeeg5pSWbF5Z/qLCnM5vPVblHNM6lRBRRotnfEAf0ALA== + + react-hot-toast@^2.1.0, react-hot-toast@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/react-hot-toast/-/react-hot-toast-2.2.0.tgz#ab6f4caed4214b9534f94bb8cfaaf21b051e62b9" + integrity sha512-248rXw13uhf/6TNDVzagX+y7R8J183rp7MwUMNkcrBRyHj/jWOggfXTGlM8zAOuh701WyVW+eUaWG2LeSufX9g== + dependencies: + goober "^2.1.1" + + react-i18next@^11.8.13: + version "11.15.7" + resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.15.7.tgz#f14c5fbf17c568fe356a848a7ef13420c323b87c" + integrity sha512-zSWZ+21LhaG4T155GcvLdepG1j/qJqD9hUGztVtD1MGBc4/l9ft/LMbUX7oKXdVVLyKWjUhUFoDNAwB2402BIQ== + dependencies: + "@babel/runtime" "^7.14.5" + html-escaper "^2.0.2" + html-parse-stringify "^3.0.1" + + react-innertext@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/react-innertext/-/react-innertext-1.1.5.tgz#8147ac54db3f7067d95f49e2d2c05a720d27d8d0" + integrity sha512-PWAqdqhxhHIv80dT9znP2KvS+hfkbRovFp4zFYHFFlOoQLRiawIic81gKb3U1wEyJZgMwgs3JoLtwryASRWP3Q== + + react-intl@^5.22.0: + version "5.24.7" + resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-5.24.7.tgz#a57084543ff8e58ed2d2bc2f1d3b8add3a2f0e3b" + integrity sha512-URPLwISsEmnzft33honGEb87LcK0QtwkZXCNsXcDYTnrYC8ZyeJRTcPYvuXC3mrN6+DxnW52RfHC416zNxfyIg== + dependencies: + "@formatjs/ecma402-abstract" "1.11.3" + "@formatjs/icu-messageformat-parser" "2.0.18" + "@formatjs/intl" "2.1.0" + "@formatjs/intl-displaynames" "5.4.2" + "@formatjs/intl-listformat" "6.5.2" + "@types/hoist-non-react-statics" "^3.3.1" + "@types/react" "16 || 17" + hoist-non-react-statics "^3.3.2" + intl-messageformat "9.11.4" + tslib "^2.1.0" + + react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0: + version "16.13.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + + react-is@^17.0.1: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" + integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== + + react-live-chat-loader@^2.7.3: + version "2.7.3" + resolved "https://registry.yarnpkg.com/react-live-chat-loader/-/react-live-chat-loader-2.7.3.tgz#a66a7d64eacdf0a680570b4e9a99639a88bffaae" + integrity sha512-VviVqnF3PYDBJ77JiPZv4cpulx806L22WfsIQxvlxlEWmzKNp/0lEs57uP6EJcE+d1jQwGcR9DIsj5qouE6OkA== + + react-multi-email@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/react-multi-email/-/react-multi-email-0.5.3.tgz#734a0d4d1af23feef5cb5e635bde23963b0a9e8b" + integrity sha512-1AneeJlAwjvzkPV740q2SXes/kW3HKOzR3gs+U7whrHN5nz+yH5Unosf/rvz8kRj/eFwBf6fTzMqlJiupu7S5Q== + + react-phone-number-input@^3.1.41: + version "3.1.46" + resolved "https://registry.yarnpkg.com/react-phone-number-input/-/react-phone-number-input-3.1.46.tgz#f25ba70ff83ffb413c824062c5b46f891ee451bc" + integrity sha512-afYl7BMy/0vMqWtzsZBmOgiPdqQAGyPO/Z3auorFs4K/zgFSBq3YoaASleodBkeRO/PygJ4ML8Wnb4Ce+3dlVQ== + dependencies: + classnames "^2.2.5" + country-flag-icons "^1.0.2" + input-format "^0.3.7" + libphonenumber-js "^1.9.47" + prop-types "^15.7.2" + + react-query@^3.33.7: + version "3.34.16" + resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.34.16.tgz#279ea180bcaeaec49c7864b29d1711ee9f152594" + integrity sha512-7FvBvjgEM4YQ8nPfmAr+lJfbW95uyW/TVjFoi2GwCkF33/S8ajx45tuPHPFGWs4qYwPy1mzwxD4IQfpUDrefNQ== + dependencies: + "@babel/runtime" "^7.5.5" + broadcast-channel "^3.4.1" + match-sorter "^6.0.2" + + react-remove-scroll-bar@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.2.0.tgz#d4d545a7df024f75d67e151499a6ab5ac97c8cdd" + integrity sha512-UU9ZBP1wdMR8qoUs7owiVcpaPwsQxUDC2lypP6mmixaGlARZa7ZIBx1jcuObLdhMOvCsnZcvetOho0wzPa9PYg== + dependencies: + react-style-singleton "^2.1.0" + tslib "^1.0.0" + + react-remove-scroll@^2.4.0: + version "2.4.4" + resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.4.4.tgz#2dfff377cf17efc00de39dad51c143fc7a1b9e3e" + integrity sha512-EyC5ohYhaeKbThMSQxuN2i+QC5HqV3AJvNZKEdiATITexu0gHm00+5ko0ltNS1ajYJVeDgVG2baRSCei0AUWlQ== + dependencies: + react-remove-scroll-bar "^2.1.0" + react-style-singleton "^2.1.0" + tslib "^1.0.0" + use-callback-ref "^1.2.3" + use-sidecar "^1.0.1" + + react-router-dom@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.3.0.tgz#da1bfb535a0e89a712a93b97dd76f47ad1f32363" + integrity sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ== + dependencies: + "@babel/runtime" "^7.12.13" + history "^4.9.0" + loose-envify "^1.3.1" + prop-types "^15.6.2" + react-router "5.2.1" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + + react-router@5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.1.tgz#4d2e4e9d5ae9425091845b8dbc6d9d276239774d" + integrity sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ== + dependencies: + "@babel/runtime" "^7.12.13" + history "^4.9.0" + hoist-non-react-statics "^3.1.0" + loose-envify "^1.3.1" + mini-create-react-context "^0.4.0" + path-to-regexp "^1.7.0" + prop-types "^15.6.2" + react-is "^16.6.0" + tiny-invariant "^1.0.2" + tiny-warning "^1.0.0" + + react-select@^5.2.1, react-select@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/react-select/-/react-select-5.2.2.tgz#3d5edf0a60f1276fd5f29f9f90a305f0a25a5189" + integrity sha512-miGS2rT1XbFNjduMZT+V73xbJEeMzVkJOz727F6MeAr2hKE0uUSA8Ff7vD44H32x2PD3SRB6OXTY/L+fTV3z9w== + dependencies: + "@babel/runtime" "^7.12.0" + "@emotion/cache" "^11.4.0" + "@emotion/react" "^11.1.1" + "@types/react-transition-group" "^4.4.0" + memoize-one "^5.0.0" + prop-types "^15.6.0" + react-transition-group "^4.3.0" + + react-ssr-prepass@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/react-ssr-prepass/-/react-ssr-prepass-1.5.0.tgz#bc4ca7fcb52365e6aea11cc254a3d1bdcbd030c5" + integrity sha512-yFNHrlVEReVYKsLI5lF05tZoHveA5pGzjFbFJY/3pOqqjGOmMmqx83N4hIjN2n6E1AOa+eQEUxs3CgRnPmT0RQ== + + react-style-singleton@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.1.1.tgz#ce7f90b67618be2b6b94902a30aaea152ce52e66" + integrity sha512-jNRp07Jza6CBqdRKNgGhT3u9umWvils1xsuMOjZlghBDH2MU0PL2WZor4PGYjXpnRCa9DQSlHMs/xnABWOwYbA== + dependencies: + get-nonce "^1.0.0" + invariant "^2.2.4" + tslib "^1.0.0" + + react-timezone-select@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/react-timezone-select/-/react-timezone-select-1.3.1.tgz#844fc8825826865d68451426d77902532f472017" + integrity sha512-ydNax+6+nJcOOE5lZA4EfkU7wcHz/b/2KK7dEfSUmnUjlHnZKSO/rf1x3SOX8EgNNrWM/Pn8BbPIPqbM0Vu1iQ== + dependencies: + react-select "^5.2.2" + spacetime "^6.16.3" + timezone-soft "^1.3.1" + + react-transition-group@^4.3.0: + version "4.4.2" + resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470" + integrity sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg== + dependencies: + "@babel/runtime" "^7.5.5" + dom-helpers "^5.0.1" + loose-envify "^1.4.0" + prop-types "^15.6.2" + + react-twemoji@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/react-twemoji/-/react-twemoji-0.3.0.tgz#8c8d5aedec8dda5cc0538043639073bcdd44c3a8" + integrity sha512-y2ZQD3KvpZklETxz9c1NycRdUVF5nKsJ0bPNW3SaRJT+ReK36sMcneYwRPfv9EK2p3s9ph/NczDglnB8wbMJ0g== + dependencies: + lodash.isequal "^4.5.0" + prop-types "^15.7.2" + twemoji "^13.0.1" + + react-use-intercom@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/react-use-intercom/-/react-use-intercom-1.4.0.tgz#796527728c131ebf132186385bf78f69dbcd84cc" + integrity sha512-HqPp7nRnftREE01i88w2kYWOV45zvJt0Of6jtHflIBa3eKl1bAs/izZUINGCJ0DOdgAdlbLweAvJlP4VTzsJjQ== + + react-virtualized-auto-sizer@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.6.tgz#66c5b1c9278064c5ef1699ed40a29c11518f97ca" + integrity sha512-7tQ0BmZqfVF6YYEWcIGuoR3OdYe8I/ZFbNclFlGOC3pMqunkYF/oL30NCjSGl9sMEb17AnzixDz98Kqc3N76HQ== + + react-window@^1.8.6: + version "1.8.6" + resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.6.tgz#d011950ac643a994118632665aad0c6382e2a112" + integrity sha512-8VwEEYyjz6DCnGBsd+MgkD0KJ2/OXFULyDtorIiTz+QzwoP94tBoA7CnbtyXMm+cCeAUER5KJcPtWl9cpKbOBg== + dependencies: + "@babel/runtime" "^7.0.0" + memoize-one ">=3.1.1 <6" + + react@17.0.2, react@^17.0.2: + version "17.0.2" + resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" + integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + + read-pkg-up@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" + integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== + dependencies: + find-up "^4.1.0" + read-pkg "^5.2.0" + type-fest "^0.8.1" + + read-pkg@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" + integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= + dependencies: + load-json-file "^4.0.0" + normalize-package-data "^2.3.2" + path-type "^3.0.0" + + read-pkg@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" + integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== + dependencies: + "@types/normalize-package-data" "^2.4.0" + normalize-package-data "^2.5.0" + parse-json "^5.0.0" + type-fest "^0.6.0" + + readable-stream@^1.0.26-4: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + + readable-stream@^2.0.0, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5: + version "2.3.7" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + + readable-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" + + readable-stream@~1.0.26, readable-stream@~1.0.26-4: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw= + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + + readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + + redis-errors@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" + integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= + + redis-parser@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" + integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= + dependencies: + redis-errors "^1.0.0" + + redis@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/redis/-/redis-4.0.1.tgz#c020e2ac7f83f0c1d42ced50b8a7af28164bd6ee" + integrity sha512-qfcq1oz2ci7pNdCfTLLEuKhS8jZ17dFiT1exogOr+jd3EVP/h9qpy7K+VajB4BXA0k8q68KFqR6HrliKV6jt1Q== + dependencies: + "@node-redis/client" "^1.0.1" + "@node-redis/json" "^1.0.1" + "@node-redis/search" "^1.0.1" + "@node-redis/time-series" "^1.0.0" + + reflect-metadata@0.1.13, reflect-metadata@^0.1.13: + version "0.1.13" + resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" + integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== + + regenerate-unicode-properties@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz#7f442732aa7934a3740c779bb9b3340dccc1fb56" + integrity sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw== + dependencies: + regenerate "^1.4.2" + + regenerate@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" + integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== + + regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4: + version "0.13.9" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" + integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== + + regenerator-transform@^0.14.2: + version "0.14.5" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" + integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== + dependencies: + "@babel/runtime" "^7.8.4" + + regex-not@^1.0.0, regex-not@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== + dependencies: + extend-shallow "^3.0.2" + safe-regex "^1.1.0" + + regexp.prototype.flags@^1.3.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz#b3f4c0059af9e47eca9f3f660e51d81307e72307" + integrity sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + + regexpp@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + + regexpu-core@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.0.1.tgz#c531122a7840de743dcf9c83e923b5560323ced3" + integrity sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw== + dependencies: + regenerate "^1.4.2" + regenerate-unicode-properties "^10.0.1" + regjsgen "^0.6.0" + regjsparser "^0.8.2" + unicode-match-property-ecmascript "^2.0.0" + unicode-match-property-value-ecmascript "^2.0.0" + + regjsgen@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.6.0.tgz#83414c5354afd7d6627b16af5f10f41c4e71808d" + integrity sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA== + + regjsparser@^0.8.2: + version "0.8.4" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.8.4.tgz#8a14285ffcc5de78c5b95d62bbf413b6bc132d5f" + integrity sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA== + dependencies: + jsesc "~0.5.0" + + remark-gfm@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-1.0.0.tgz#9213643001be3f277da6256464d56fd28c3b3c0d" + integrity sha512-KfexHJCiqvrdBZVbQ6RopMZGwaXz6wFJEfByIuEwGf0arvITHjiKKZ1dpXujjH9KZdm1//XJQwgfnJ3lmXaDPA== + dependencies: + mdast-util-gfm "^0.1.0" + micromark-extension-gfm "^0.3.0" + + remark-html@^14.0.1: + version "14.0.1" + resolved "https://registry.yarnpkg.com/remark-html/-/remark-html-14.0.1.tgz#2118516604c1a6c2ea9d5914a526942554e04e30" + integrity sha512-a/x5bTlFrkwYkz43zuJIk0m0IuS5Rx8zLztGwdzmAdUj0Hsi4C4nkJ8gTQRNXY/ET/gMrqQORMMI0arRItq/aQ== + dependencies: + "@types/mdast" "^3.0.0" + hast-util-sanitize "^4.0.0" + hast-util-to-html "^8.0.0" + mdast-util-to-hast "^11.0.0" + unified "^10.0.0" + + remark-mdx@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-2.0.0.tgz#bd921780c19ce3e51941e54b1e6388440ed499b3" + integrity sha512-TDnjSv77Oynf+K1deGWZPKSwh3/9hykVAxVm9enAw6BmicCGklREET8s19KYnjGsNPms0pNDJLmp+bnHDVItAQ== + dependencies: + mdast-util-mdx "^2.0.0" + micromark-extension-mdxjs "^1.0.0" + + remark-parse@^10.0.0: + version "10.0.1" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-10.0.1.tgz#6f60ae53edbf0cf38ea223fe643db64d112e0775" + integrity sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw== + dependencies: + "@types/mdast" "^3.0.0" + mdast-util-from-markdown "^1.0.0" + unified "^10.0.0" + + remark-parse@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-9.0.0.tgz#4d20a299665880e4f4af5d90b7c7b8a935853640" + integrity sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw== + dependencies: + mdast-util-from-markdown "^0.8.0" + + remark-rehype@^10.0.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-10.1.0.tgz#32dc99d2034c27ecaf2e0150d22a6dcccd9a6279" + integrity sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw== + dependencies: + "@types/hast" "^2.0.0" + "@types/mdast" "^3.0.0" + mdast-util-to-hast "^12.1.0" + unified "^10.0.0" + + remark-stringify@^10.0.0: + version "10.0.2" + resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-10.0.2.tgz#50414a6983f5008eb9e72eed05f980582d1f69d7" + integrity sha512-6wV3pvbPvHkbNnWB0wdDvVFHOe1hBRAx1Q/5g/EpH4RppAII6J8Gnwe7VbHuXaoKIF6LAg6ExTel/+kNqSQ7lw== + dependencies: + "@types/mdast" "^3.0.0" + mdast-util-to-markdown "^1.0.0" + unified "^10.0.0" + + remark-stringify@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-9.0.1.tgz#576d06e910548b0a7191a71f27b33f1218862894" + integrity sha512-mWmNg3ZtESvZS8fv5PTvaPckdL4iNlCHTt8/e/8oN08nArHRHjNZMKzA/YW3+p7/lYqIw4nx1XsjCBo/AxNChg== + dependencies: + mdast-util-to-markdown "^0.6.0" + + remark@^13.0.0: + version "13.0.0" + resolved "https://registry.yarnpkg.com/remark/-/remark-13.0.0.tgz#d15d9bf71a402f40287ebe36067b66d54868e425" + integrity sha512-HDz1+IKGtOyWN+QgBiAT0kn+2s6ovOxHyPAFGKVE81VSzJ+mq7RwHFledEvB5F1p4iJvOah/LOKdFuzvRnNLCA== + dependencies: + remark-parse "^9.0.0" + remark-stringify "^9.0.0" + unified "^9.1.0" + + remark@^14.0.1: + version "14.0.2" + resolved "https://registry.yarnpkg.com/remark/-/remark-14.0.2.tgz#4a1833f7441a5c29e44b37bb1843fb820797b40f" + integrity sha512-A3ARm2V4BgiRXaUo5K0dRvJ1lbogrbXnhkJRmD0yw092/Yl0kOCZt1k9ZeElEwkZsWGsMumz6qL5MfNJH9nOBA== + dependencies: + "@types/mdast" "^3.0.0" + remark-parse "^10.0.0" + remark-stringify "^10.0.0" + unified "^10.0.0" + + remove-accents@0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.4.2.tgz#0a43d3aaae1e80db919e07ae254b285d9e1c7bb5" + integrity sha1-CkPTqq4egNuRngeuJUsoXZ4ce7U= + + remove-trailing-separator@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= + + repeat-element@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" + integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== + + repeat-string@^1.0.0, repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= + + request@^2.79.0: + version "2.88.2" + resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + har-validator "~5.1.3" + http-signature "~1.2.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + oauth-sign "~0.9.0" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^3.3.2" + + require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + + require-main-filename@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== + + reselect@^4.0.0: + version "4.1.5" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.5.tgz#852c361247198da6756d07d9296c2b51eddb79f6" + integrity sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ== + + 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-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-pathname@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" + integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== + + resolve-url@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= + + 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.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.18.1, resolve@^1.20.0, resolve@^1.22.0: + version "1.22.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" + integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== + dependencies: + is-core-module "^2.8.1" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + + resolve@^2.0.0-next.3: + version "2.0.0-next.3" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.3.tgz#d41016293d4a8586a39ca5d9b5f15cbea1f55e46" + integrity sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q== + dependencies: + is-core-module "^2.2.0" + path-parse "^1.0.6" + + responselike@1.0.2, responselike@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" + integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= + dependencies: + lowercase-keys "^1.0.0" + + restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + + ret@~0.1.10: + version "0.1.15" + resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== + + retry@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= + + reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + + rfdc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + + rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + + ripemd160@2.0.2, ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + + rlp@^2.2.4: + version "2.2.7" + resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.7.tgz#33f31c4afac81124ac4b283e2bd4d9720b30beaf" + integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== + dependencies: + bn.js "^5.2.0" + + rollup-plugin-node-builtins@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/rollup-plugin-node-builtins/-/rollup-plugin-node-builtins-2.1.2.tgz#24a1fed4a43257b6b64371d8abc6ce1ab14597e9" + integrity sha1-JKH+1KQyV7a2Q3HYq8bOGrFFl+k= + dependencies: + browserify-fs "^1.0.0" + buffer-es6 "^4.9.2" + crypto-browserify "^3.11.0" + process-es6 "^0.11.2" + + rollup-plugin-polyfill-node@0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/rollup-plugin-polyfill-node/-/rollup-plugin-polyfill-node-0.8.0.tgz#859c070822f5e38d221e5b4238cb34aa894c2b19" + integrity sha512-C4UeKedOmOBkB3FgR+z/v9kzRwV1Q/H8xWs1u1+CNe4XOV6hINfOrcO+TredKxYvopCmr+WKUSNsFUnD1RLHgQ== + dependencies: + "@rollup/plugin-inject" "^4.0.0" + + rsvp@^4.8.4: + version "4.8.5" + resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" + integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== + + run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + + rxjs@^7.5.5: + version "7.5.5" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f" + integrity sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw== + dependencies: + tslib "^2.1.0" + + sade@^1.7.3: + version "1.8.1" + resolved "https://registry.yarnpkg.com/sade/-/sade-1.8.1.tgz#0a78e81d658d394887be57d2a409bf703a3b2701" + integrity sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A== + dependencies: + mri "^1.1.0" + + safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, 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== + + safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + + safe-regex@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= + dependencies: + ret "~0.1.10" + + "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + + sane@^4.0.3: + version "4.1.0" + resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" + integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== + dependencies: + "@cnakazawa/watch" "^1.0.3" + anymatch "^2.0.0" + capture-exit "^2.0.0" + exec-sh "^0.3.2" + execa "^1.0.0" + fb-watchman "^2.0.0" + micromatch "^3.1.4" + minimist "^1.1.1" + walker "~1.0.5" + + saslprep@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" + integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag== + dependencies: + sparse-bitfield "^3.0.3" + + sax@>=0.6.0, sax@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + + saxes@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== + dependencies: + xmlchars "^2.2.0" + + scheduler@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" + integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + + scrypt-js@^3.0.0, scrypt-js@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" + integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== + + secp256k1@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.3.tgz#c4559ecd1b8d3c1827ed2d1b94190d69ce267303" + integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA== + dependencies: + elliptic "^6.5.4" + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + + section-matter@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/section-matter/-/section-matter-1.0.0.tgz#e9041953506780ec01d59f292a19c7b850b84167" + integrity sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA== + dependencies: + extend-shallow "^2.0.1" + kind-of "^6.0.0" + + seek-bzip@^1.0.5: + version "1.0.6" + resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.6.tgz#35c4171f55a680916b52a07859ecf3b5857f21c4" + integrity sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ== + dependencies: + commander "^2.8.1" + + "semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + + semver@7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" + integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== + + semver@7.x, semver@^7.3.2, semver@^7.3.5: + version "7.3.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== + dependencies: + lru-cache "^6.0.0" + + semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== + + semver@~2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-2.3.2.tgz#b9848f25d6cf36333073ec9ef8856d42f1233e52" + integrity sha1-uYSPJdbPNjMwc+ye+IVtQvEjPlI= + + send@0.17.2: + version "0.17.2" + resolved "https://registry.yarnpkg.com/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820" + integrity sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww== + dependencies: + debug "2.6.9" + depd "~1.1.2" + destroy "~1.0.4" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "1.8.1" + mime "1.6.0" + ms "2.1.3" + on-finished "~2.3.0" + range-parser "~1.2.1" + statuses "~1.5.0" + + seq-queue@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e" + integrity sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4= + + serve-static@1.14.2: + version "1.14.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.2.tgz#722d6294b1d62626d41b43a013ece4598d292bfa" + integrity sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.17.2" + + servify@^0.1.12: + version "0.1.12" + resolved "https://registry.yarnpkg.com/servify/-/servify-0.1.12.tgz#142ab7bee1f1d033b66d0707086085b17c06db95" + integrity sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw== + dependencies: + body-parser "^1.16.0" + cors "^2.8.1" + express "^4.14.0" + request "^2.79.0" + xhr "^2.3.3" + + set-blocking@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + + set-value@^2.0.0, set-value@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== + dependencies: + extend-shallow "^2.0.1" + is-extendable "^0.1.1" + is-plain-object "^2.0.3" + split-string "^3.0.1" + + setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= + + setprototypeof@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" + integrity sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ= + + setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + + sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + + shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= + dependencies: + shebang-regex "^1.0.0" + + shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + + shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= + + shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + + shell-quote@^1.6.1: + version "1.7.3" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" + integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== + + shellwords@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== + + short-uuid@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/short-uuid/-/short-uuid-4.2.0.tgz#3706d9e7287ac589dc5ffe324d3e34817a07540b" + integrity sha512-r3cxuPPZSuF0QkKsK9bBR7u+7cwuCRzWzgjPh07F5N2iIUNgblnMHepBY16xgj5t1lG9iOP9k/TEafY1qhRzaw== + dependencies: + any-base "^1.1.0" + uuid "^8.3.2" + + side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + + signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + + simple-concat@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== + + simple-get@^2.7.0: + version "2.8.2" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.2.tgz#5708fb0919d440657326cd5fe7d2599d07705019" + integrity sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw== + dependencies: + decompress-response "^3.3.0" + once "^1.3.1" + simple-concat "^1.0.0" + + sirv@^1.0.7: + version "1.0.19" + resolved "https://registry.yarnpkg.com/sirv/-/sirv-1.0.19.tgz#1d73979b38c7fe91fcba49c85280daa9c2363b49" + integrity sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ== + dependencies: + "@polka/url" "^1.0.0-next.20" + mrmime "^1.0.0" + totalist "^1.0.0" + + sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + + slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + + slice-ansi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" + integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + + slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + + slice-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" + integrity sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== + dependencies: + ansi-styles "^6.0.0" + is-fullwidth-code-point "^4.0.0" + + smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + + snapdragon-node@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== + dependencies: + define-property "^1.0.0" + isobject "^3.0.0" + snapdragon-util "^3.0.1" + + snapdragon-util@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== + dependencies: + kind-of "^3.2.0" + + snapdragon@^0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== + dependencies: + base "^0.11.1" + debug "^2.2.0" + define-property "^0.2.5" + extend-shallow "^2.0.1" + map-cache "^0.2.2" + source-map "^0.5.6" + source-map-resolve "^0.5.0" + use "^3.1.0" + + socket.io-parser@*: + version "4.1.2" + resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.1.2.tgz#0a97d4fb8e67022158a568450a6e41887e42035e" + integrity sha512-j3kk71QLJuyQ/hh5F/L2t1goqzdTL0gvDzuhTuNSwihfuFUrcSji0qFZmJJPtG6Rmug153eOPsUizeirf1IIog== + dependencies: + "@socket.io/component-emitter" "~3.0.0" + debug "~4.3.1" + + socks-proxy-agent@6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz#e664e8f1aaf4e1fb3df945f09e3d94f911137f87" + integrity sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew== + dependencies: + agent-base "^6.0.2" + debug "^4.3.1" + socks "^2.6.1" + + socks@^2.6.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.2.tgz#ec042d7960073d40d94268ff3bb727dc685f111a" + integrity sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA== + dependencies: + ip "^1.1.5" + smart-buffer "^4.2.0" + + sort-keys-length@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sort-keys-length/-/sort-keys-length-1.0.1.tgz#9cb6f4f4e9e48155a6aa0671edd336ff1479a188" + integrity sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg= + dependencies: + sort-keys "^1.0.0" + + sort-keys@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" + integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0= + dependencies: + is-plain-obj "^1.0.0" + + sort-keys@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" + integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= + dependencies: + is-plain-obj "^1.0.0" + + source-map-js@^1.0.1, source-map-js@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + source-map-resolve@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + + source-map-support@0.4.18: + version "0.4.18" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" + integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== + dependencies: + source-map "^0.5.6" + + source-map-support@^0.5.21, source-map-support@^0.5.6: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + + source-map-url@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" + integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== + + source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7: + version "0.5.7" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= + + source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + + source-map@^0.7.0, source-map@^0.7.3: + version "0.7.3" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== + + sourcemap-codec@^1.4.8: + version "1.4.8" + resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" + integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== + + space-separated-tokens@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.1.tgz#43193cec4fb858a2ce934b7f98b7f2c18107098b" + integrity sha512-ekwEbFp5aqSPKaqeY1PGrlGQxPNaq+Cnx4+bE2D8sciBQrHpbwoBbawqTN2+6jPs9IdWxxiUcN0K2pkczD3zmw== + + spacetime@^6.16.3: + version "6.16.3" + resolved "https://registry.yarnpkg.com/spacetime/-/spacetime-6.16.3.tgz#86d3b05db33421a9ee478b1f2ca025582fc61fcf" + integrity sha512-JQEfj3VHT1gU1IMV5NvhgAP8P+2mDFd84ZCiHN//dp6hRKmuW0IizHissy62lO0nilfFjVhnoSaMC7te+Y5f4A== + + sparse-bitfield@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" + integrity sha1-/0rm5oZWBWuks+eSqzM004JzyhE= + dependencies: + memory-pager "^1.0.2" + + spdx-correct@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" + integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + + spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== + + spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + + spdx-license-ids@^3.0.0: + version "3.0.11" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95" + integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g== + + split-string@^3.0.1, split-string@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== + dependencies: + extend-shallow "^3.0.0" + + split2@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-4.1.0.tgz#101907a24370f85bb782f08adaabe4e281ecf809" + integrity sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ== + + sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= + + sqlstring@^2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.3.tgz#2ddc21f03bce2c387ed60680e739922c65751d0c" + integrity sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg== + + sshpk@^1.7.0: + version "1.17.0" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" + integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + + stack-utils@2.0.5, stack-utils@^2.0.2, 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" + + static-extend@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= + dependencies: + define-property "^0.2.5" + object-copy "^0.1.0" + + "statuses@>= 1.3.1 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" + integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + + strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= + + string-argv@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" + integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== + + 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-range@~1.2, string-range@~1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/string-range/-/string-range-1.2.2.tgz#a893ed347e72299bc83befbbf2a692a8d239d5dd" + integrity sha1-qJPtNH5yKZvIO++78qaSqNI51d0= + + string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + + string-width@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + + string.prototype.matchall@^4.0.6: + version "4.0.6" + resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz#5abb5dabc94c7b0ea2380f65ba610b3a544b15fa" + integrity sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + get-intrinsic "^1.1.1" + has-symbols "^1.0.2" + internal-slot "^1.0.3" + regexp.prototype.flags "^1.3.1" + side-channel "^1.0.4" + + string.prototype.padend@^3.0.0: + version "3.1.3" + resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.3.tgz#997a6de12c92c7cb34dc8a201a6c53d9bd88a5f1" + integrity sha512-jNIIeokznm8SD/TZISQsZKYu7RJyheFNt84DUPrh482GC8RVp2MKqm2O5oBRdGxbDQoXrhhWtPIWQOiy20svUg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.19.1" + + string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + + string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + + 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" + integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= + + string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + + stringify-entities@^4.0.0, stringify-entities@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-4.0.2.tgz#13d113dc7449dc8ae4cb22c28883ee3fff8753e3" + integrity sha512-MTxTVcEkorNtBbNpoFJPEh0kKdM6+QbMjLbaxmvaPMmayOXdr/AIVIIJX7FReUVweRBFJfZepK4A4AKgwuFpMQ== + dependencies: + character-entities-html4 "^2.0.0" + character-entities-legacy "^3.0.0" + + strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + + strip-ansi@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" + integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw== + dependencies: + ansi-regex "^6.0.1" + + strip-bom-string@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" + integrity sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI= + + strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= + + 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-dirs@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" + integrity sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g== + dependencies: + is-natural-number "^4.0.1" + + strip-eof@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= + + 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-hex-prefix@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" + integrity sha1-DF8VX+8RUTczd96du1iNoFUA428= + dependencies: + is-hex-prefixed "1.0.0" + + strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + + strip-markdown@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/strip-markdown/-/strip-markdown-4.2.0.tgz#2a26eadf6cd358ac18faa7f53f60ccae10cbf120" + integrity sha512-sZYHI1KoKOOBfIq78R3E62NHg7kk6aKtZSqiH7wWxFB6Ak6PTZe4N88aJnzjV00Lbfw91oyLpy3baYfTTqNYBA== + + strip-outer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631" + integrity sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg== + dependencies: + escape-string-regexp "^1.0.2" + + stripe@*, stripe@^8.191.0: + version "8.209.0" + resolved "https://registry.yarnpkg.com/stripe/-/stripe-8.209.0.tgz#a8f34132fb4140bdf9152943b15c641ad99cd3b1" + integrity sha512-ozfs8t0fxA/uvCK1DNvitSdEublOHK5CTRsrd2AWWk9LogjXcfkxmtz3KGSSQd+jyA2+rbee9TMzhJ6aabQ5WQ== + dependencies: + "@types/node" ">=8.1.0" + qs "^6.6.0" + + style-to-object@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.3.0.tgz#b1b790d205991cc783801967214979ee19a76e46" + integrity sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA== + dependencies: + inline-style-parser "0.1.1" + styled-jsx@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.0.tgz#816b4b92e07b1786c6b7111821750e0ba4d26e77" integrity sha512-qUqsWoBquEdERe10EW8vLp3jT25s/ssG1/qX5gZ4wu15OZpmSMFI2v+fWlRhLfykA5rFtlJ1ME8A8pm/peV4WA== + stylis@4.0.13: + version "4.0.13" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.13.tgz#f5db332e376d13cc84ecfe5dace9a2a51d954c91" + integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag== + + superjson@1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/superjson/-/superjson-1.8.1.tgz#c0fe510b8ff71c3bde5733a125623994ca9ec608" + integrity sha512-RaBKdbsYj29Ky+XcdE11pJAyKXPrqiCV269koH2WAlpeHh/9qnK0ET84GiVWvnutiufyDolK/vS2jtdFYr341w== + dependencies: + debug "^4.3.1" + lodash.clonedeep "^4.5.0" + + supports-color@^4.0.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b" + integrity sha1-vnoN5ITexcXN34s9WRJQRJEvY1s= + dependencies: + has-flag "^2.0.0" + + supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + + supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + + supports-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-color@^9.2.1: + version "9.2.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-9.2.1.tgz#599dc9d45acf74c6176e0d880bab1d7d718fe891" + integrity sha512-Obv7ycoCTG51N7y175StI9BlAXrmgZrFhZOb0/PyjHBher/NmsdBgbbQ1Inhq+gIhz6+7Gb+jWF2Vqi7Mf1xnQ== + + 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== + + swarm-js@^0.1.40: + version "0.1.40" + resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.40.tgz#b1bc7b6dcc76061f6c772203e004c11997e06b99" + integrity sha512-yqiOCEoA4/IShXkY3WKwP5PvZhmoOOD8clsKA7EEcRILMkTEYHCQ21HDCAcVpmIxZq4LyZvWeRJ6quIyHk1caA== + dependencies: + bluebird "^3.5.0" + buffer "^5.0.5" + eth-lib "^0.1.26" + fs-extra "^4.0.2" + got "^7.1.0" + mime-types "^2.1.16" + mkdirp-promise "^5.0.1" + mock-fs "^4.1.0" + setimmediate "^1.0.5" + tar "^4.0.2" + xhr-request "^1.0.1" + + symbol-tree@^3.2.4: + version "3.2.4" + resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== + + tailwindcss@^3.0.23: + version "3.0.23" + resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.0.23.tgz#c620521d53a289650872a66adfcb4129d2200d10" + integrity sha512-+OZOV9ubyQ6oI2BXEhzw4HrqvgcARY38xv3zKcjnWtMIZstEsXdI9xftd1iB7+RbOnj2HOEzkA0OyB5BaSxPQA== + dependencies: + arg "^5.0.1" + chalk "^4.1.2" + chokidar "^3.5.3" + color-name "^1.1.4" + cosmiconfig "^7.0.1" + detective "^5.2.0" + didyoumean "^1.2.2" + dlv "^1.1.3" + fast-glob "^3.2.11" + glob-parent "^6.0.2" + is-glob "^4.0.3" + normalize-path "^3.0.0" + object-hash "^2.2.0" + postcss "^8.4.6" + postcss-js "^4.0.0" + postcss-load-config "^3.1.0" + postcss-nested "5.0.6" + postcss-selector-parser "^6.0.9" + postcss-value-parser "^4.2.0" + quick-lru "^5.1.1" + resolve "^1.22.0" + + tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + + tar-stream@^1.5.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" + integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== + dependencies: + bl "^1.0.0" + buffer-alloc "^1.2.0" + end-of-stream "^1.0.0" + fs-constants "^1.0.0" + readable-stream "^2.3.0" + to-buffer "^1.1.1" + xtend "^4.0.0" + + tar@^4.0.2: + version "4.4.19" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3" + integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA== + dependencies: + chownr "^1.1.4" + fs-minipass "^1.2.7" + minipass "^2.9.0" + minizlib "^1.3.3" + mkdirp "^0.5.5" + safe-buffer "^5.2.1" + yallist "^3.1.1" + + 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" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= + + thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= + dependencies: + thenify ">= 3.1.0 < 4" + + "thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + + thirty-two@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/thirty-two/-/thirty-two-1.0.2.tgz#4ca2fffc02a51290d2744b9e3f557693ca6b627a" + integrity sha1-TKL//AKlEpDSdEueP1V2k8prYno= + + throat@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" + integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== + + throat@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" + integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w== + + through@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= + + thumbprint@0.0.1, thumbprint@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/thumbprint/-/thumbprint-0.0.1.tgz#55e86f9a9b14efb45b15c039645d47b6226bb777" + integrity sha1-VehvmpsU77RbFcA5ZF1HtiJrt3c= + + timed-out@^4.0.0, timed-out@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" + integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= + + timezone-soft@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/timezone-soft/-/timezone-soft-1.3.1.tgz#0e994067cbccc76a9c16b71fd8f2f94394be5b0d" + integrity sha512-mphMogFJzQy6UIpl/UgKLSNbhmLtdgbz866TnqJ/CnWnc+7dsNyAe8nPwVdOW3Mf8nT0lA32MW/gYhAl4/RkVg== + + timm@^1.6.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/timm/-/timm-1.7.1.tgz#96bab60c7d45b5a10a8a4d0f0117c6b7e5aff76f" + integrity sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw== + + tiny-invariant@^1.0.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9" + integrity sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg== + + tiny-warning@^1.0.0, tiny-warning@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" + integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== + + tinycolor2@^1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803" + integrity sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA== + + title@^3.4.2: + version "3.4.4" + resolved "https://registry.yarnpkg.com/title/-/title-3.4.4.tgz#5c0ab11fd69643bc05dc006bba52aaf5c1630f5e" + integrity sha512-ViLJMyg5TFwWQ7Aqrs3e0IPINA99++cOLzQFIuBw6rKPhn8Cz7J7sdsag0BQPCf4ip7bHY1/docykbQe2R4N6Q== + dependencies: + arg "1.0.0" + chalk "2.3.0" + clipboardy "1.2.2" + titleize "1.0.0" + + titleize@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/titleize/-/titleize-1.0.0.tgz#7d350722061830ba6617631e0cfd3ea08398d95a" + integrity sha1-fTUHIgYYMLpmF2MeDP0+oIOY2Vo= + + 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-buffer@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" + integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== + + to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + + to-object-path@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= + dependencies: + kind-of "^3.0.2" + + to-readable-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" + integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== + + to-regex-range@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= + dependencies: + is-number "^3.0.0" + repeat-string "^1.6.1" + + to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + + to-regex@^3.0.1, to-regex@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== + dependencies: + define-property "^2.0.2" + extend-shallow "^3.0.2" + regex-not "^1.0.2" + safe-regex "^1.1.0" + + toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + + toposort@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330" + integrity sha1-riF2gXXRVZ1IvvNUILL0li8JwzA= + + totalist@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df" + integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g== + + tough-cookie@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" + integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.1.2" + + tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + + tr46@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" + integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== + dependencies: + punycode "^2.1.1" + + tr46@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9" + integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA== + dependencies: + punycode "^2.1.1" + + tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + + trim-repeated@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21" + integrity sha1-42RqLqTokTEr9+rObPsFOAvAHCE= + dependencies: + escape-string-regexp "^1.0.2" + + trough@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" + integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== + + trough@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/trough/-/trough-2.1.0.tgz#0f7b511a4fde65a46f18477ab38849b22c554876" + integrity sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g== + + ts-jest@^26.0.0: + version "26.5.6" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.6.tgz#c32e0746425274e1dfe333f43cd3c800e014ec35" + integrity sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA== + dependencies: + bs-logger "0.x" + buffer-from "1.x" + fast-json-stable-stringify "2.x" + jest-util "^26.1.0" + json5 "2.x" + lodash "4.x" + make-error "1.x" + mkdirp "1.x" + semver "7.x" + yargs-parser "20.x" + + ts-morph@^13.0.2: + version "13.0.3" + resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-13.0.3.tgz#c0c51d1273ae2edb46d76f65161eb9d763444c1d" + integrity sha512-pSOfUMx8Ld/WUreoSzvMFQG5i9uEiWIsBYjpU9+TTASOeUa89j5HykomeqVULm1oqWtBdleI3KEFRLrlA3zGIw== + dependencies: + "@ts-morph/common" "~0.12.3" + code-block-writer "^11.0.0" + + ts-node@^10.6.0: + version "10.7.0" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.7.0.tgz#35d503d0fab3e2baa672a0e94f4b40653c2463f5" + integrity sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A== + dependencies: + "@cspotcode/source-map-support" "0.7.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.0" + yn "3.1.1" + + tsconfig-paths@^3.12.0, tsconfig-paths@^3.9.0: + version "3.14.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.0.tgz#4fcc48f9ccea8826c41b9ca093479de7f5018976" + integrity sha512-cg/1jAZoL57R39+wiw4u/SCC6Ic9Q5NqjBOb+9xISedOYurfog9ZNmKJSxAnb2m/5Bq4lE9lhUcau33Ml8DM0g== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.1" + minimist "^1.2.0" + strip-bom "^3.0.0" + + tsdav@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/tsdav/-/tsdav-2.0.0.tgz#e0a91d0ad79e793885b3fdc34157bd8aeedfb0f1" + integrity sha512-ENdQyhu4T03QZxh5dhoDP7vXB8bqwpBATCA57pu61Gam5/wg+7JApQuUdGjXHGzcqSpWpD960avPCdj2M+hlLQ== + dependencies: + base-64 "1.0.0" + cross-fetch "3.1.5" + debug "4.3.3" + eslint-module-utils "2.7.3" + rollup-plugin-node-builtins "2.1.2" + rollup-plugin-polyfill-node "0.8.0" + xml-js "1.6.11" + + tslib@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.1.tgz#410eb0d113e5b6356490eec749603725b021b43e" + integrity sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ== + + tslib@2.3.1, tslib@^2.0.0, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== + + tslib@^1.0.0, tslib@^1.8.1, tslib@^1.9.3: + version "1.14.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + + tslog@^3.2.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/tslog/-/tslog-3.3.2.tgz#ceef419054a85d992cfdd923dc04aa0ea3539e24" + integrity sha512-K+XduMfa9+yiHE/vxbUD/dL7RAbw9yIfi9tMjQj3uQ8evkPRKkmw0mQgEkzmueyg23hJHGaOQmDnCEZoKEws+w== + dependencies: + source-map-support "^0.5.21" + + tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + + tsyringe@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/tsyringe/-/tsyringe-4.6.0.tgz#14915d3d7f0db35e1cf7269bdbf7c440713c8d07" + integrity sha512-BMQAZamSfEmIQzH8WJeRu1yZGQbPSDuI9g+yEiKZFIcO46GPZuMOC2d0b52cVBdw1d++06JnDSIIZvEnogMdAw== + dependencies: + tslib "^1.9.3" + + tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + + turbo-darwin-64@1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/turbo-darwin-64/-/turbo-darwin-64-1.1.6.tgz#1f493d9fed174e609b65c2f64028d42d095c9bb7" + integrity sha512-xzl79T7mPKaIGhMBCAzpTvXkbFNZaMyeOMsNXxVT5dTY+d3FwLFfbqHIoG1dH745TbH6i67bxtt70lKdQa+qdQ== + + turbo-darwin-arm64@1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/turbo-darwin-arm64/-/turbo-darwin-arm64-1.1.6.tgz#aa6218492de696e49c1af16bb1d13118aa85a203" + integrity sha512-r0D+Kfwcaqec5h9Xa4T/VD6mWZ2LQr+zOEBBL6UA15htgel06B2eXiGdjRiw4i7ieV80tEBEDdz9tSWJBhAL/Q== + + turbo-freebsd-64@1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/turbo-freebsd-64/-/turbo-freebsd-64-1.1.6.tgz#9a7b6affb3177f100a2315cdd81c3b2f87180287" + integrity sha512-v5MJeRcyeCDF3La40TOub0+/OuGGFuLzlVHb4jYxthESbtLve1H23bDiL+4gCQgPYOsKMOvKQpuoMaKW2gxk7A== + + turbo-freebsd-arm64@1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/turbo-freebsd-arm64/-/turbo-freebsd-arm64-1.1.6.tgz#e70e94277c7149ba95cbacd826068f46b0346727" + integrity sha512-5gm3r+M5f/Idt/pggyCQ+MZSlaUdxUeb/4LtPohhWOoj4PYo1o5kwInaRlckr7uV36E4/npDvz9cDV96Pohejg== + + turbo-linux-32@1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/turbo-linux-32/-/turbo-linux-32-1.1.6.tgz#02f072f68bb8a71e205f24cee2068ee455fb1cb1" + integrity sha512-dLc1Vd/LQP5n3NGLMf+cdaK99sMWvHdDvTUSrSwoYDy5fWFpUm0E12lAxRH3tikX2m7Kfcy2uY5xSJIuq5xzYQ== + + turbo-linux-64@1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/turbo-linux-64/-/turbo-linux-64-1.1.6.tgz#5b90ab2aa1e2e0a94f18905871d88656335f0285" + integrity sha512-V4rb41yQUA+vPDgXc06oHmKbgrBUbwm09oRtjvmlIQU8zX8qujMPZIun8tGP4NuzErJXGzD3WDgj7VSsO23IIw== + + turbo-linux-arm64@1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/turbo-linux-arm64/-/turbo-linux-arm64-1.1.6.tgz#f7e738e35b5daa7e5f82f61aa1018a39ad03501f" + integrity sha512-QsE7gow3WxWXKwNWJX4DIJys6xc6Up4/icjdTZCZbglPLwuG2UiUzjJ2+beXxVU4EmpQF6NwKubHCtrs8m8/kQ== + + turbo-linux-arm@1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/turbo-linux-arm/-/turbo-linux-arm-1.1.6.tgz#39b29c3f91a5e426fb17f1fe543ed8587b861c7b" + integrity sha512-zAaIa0+EhRYYkM51ruB1LCUqyeigK66A+KfXZ3Y9+aiKg7EYbDvuv+ReD4srLPKoIuAxR5dYlk5RVhSKejt2Cw== + + turbo-linux-mips64le@1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/turbo-linux-mips64le/-/turbo-linux-mips64le-1.1.6.tgz#b10aab67382984d728e3c2e7239bd4d9a67da9e2" + integrity sha512-098DB9daXoI6LRCkuOv1Pqim+H4wXZrFza9Xd7zJIel1WmxEgNsHqWpSH5Jn2J92LbkWl+tfN1+myw4+a4ESfw== + + turbo-linux-ppc64le@1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/turbo-linux-ppc64le/-/turbo-linux-ppc64le-1.1.6.tgz#0fa6bdcf3420ee65b4faa2755fe852390c022a5b" + integrity sha512-U5A1mnsGM994h/1VT4FbsV/bb+I0fgvkY5/TTX7MfA9Iwt0SxsNlh+Jgofe1svPz0CKEe6Hl2WQSGHTlBPJb5Q== + + turbo-windows-32@1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/turbo-windows-32/-/turbo-windows-32-1.1.6.tgz#724185a8584fa2c14edc4892056f23576aeb0317" + integrity sha512-0C+/EI11j8ABtI6O2n+NYL2osDI6moo7YL8pqiWbNrdEGI2KbeCTVQpruUH+GONsMov06pR4BouL9UT2jSpG0g== + + turbo-windows-64@1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/turbo-windows-64/-/turbo-windows-64-1.1.6.tgz#3965a5c0c55273de2882e580ca042c6564c43272" + integrity sha512-O2kC+7+zuMjFIi6mpU1qz+Bv27TcHkkCczcDNVU29G52pm5lwj7BZ+/gu+EPJSnF5VrgdA6Oru6KVXPRS1q+Cg== + + turbo@latest: + version "1.1.6" + resolved "https://registry.yarnpkg.com/turbo/-/turbo-1.1.6.tgz#dcae11bbd7a465473bdf416b82caac2b7f94d641" + integrity sha512-pZTc6Sb5MtK/X/qhiDSssc8AZWoUoYf14ZqYjvDWg/aEtqgwYorVJqfRcj4XOXOqtVZ3gO/91eXwdyh/q2aQHA== + optionalDependencies: + turbo-darwin-64 "1.1.6" + turbo-darwin-arm64 "1.1.6" + turbo-freebsd-64 "1.1.6" + turbo-freebsd-arm64 "1.1.6" + turbo-linux-32 "1.1.6" + turbo-linux-64 "1.1.6" + turbo-linux-arm "1.1.6" + turbo-linux-arm64 "1.1.6" + turbo-linux-mips64le "1.1.6" + turbo-linux-ppc64le "1.1.6" + turbo-windows-32 "1.1.6" + turbo-windows-64 "1.1.6" + + tween-functions@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tween-functions/-/tween-functions-1.2.0.tgz#1ae3a50e7c60bb3def774eac707acbca73bbc3ff" + integrity sha1-GuOlDnxguz3vd06scHrLynO7w/8= + + tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + + twemoji-parser@13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/twemoji-parser/-/twemoji-parser-13.1.0.tgz#65e7e449c59258791b22ac0b37077349127e3ea4" + integrity sha512-AQOzLJpYlpWMy8n+0ATyKKZzWlZBJN+G0C+5lhX7Ftc2PeEVdUU/7ns2Pn2vVje26AIZ/OHwFoUbdv6YYD/wGg== + + twemoji@^13.0.1: + version "13.1.1" + resolved "https://registry.yarnpkg.com/twemoji/-/twemoji-13.1.1.tgz#6e31409908bb5383cdb1d09c9c8e7856aa6e2e3b" + integrity sha512-IIIoq+n1lk1M1+evBKZD3DO0ud02fDQ4ssbgAv8rp3YBWUeNmskjlisFUPPDacQ50XS3bhrd4Kq9Q2gqhxb0dg== + dependencies: + fs-extra "^8.0.1" + jsonfile "^5.0.0" + twemoji-parser "13.1.0" + universalify "^0.1.2" + + type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + + type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + 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.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + + type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + + type-fest@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" + integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== + + type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + + type-is@^1.6.18, type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + + type@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" + integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== + + type@^2.5.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/type/-/type-2.6.0.tgz#3ca6099af5981d36ca86b78442973694278a219f" + integrity sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ== + + typedarray-to-buffer@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== + dependencies: + is-typedarray "^1.0.0" + + typedarray-to-buffer@~1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-1.0.4.tgz#9bb8ba0e841fb3f4cf1fe7c245e9f3fa8a5fe99c" + integrity sha1-m7i6DoQfs/TPH+fCRenz+opf6Zw= + + typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= + + typeorm@0.2.41: + version "0.2.41" + resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.41.tgz#88758101ac158dc0a0a903d70eaacea2974281cc" + integrity sha512-/d8CLJJxKPgsnrZWiMyPI0rz2MFZnBQrnQ5XP3Vu3mswv2WPexb58QM6BEtmRmlTMYN5KFWUz8SKluze+wS9xw== + dependencies: + "@sqltools/formatter" "^1.2.2" + app-root-path "^3.0.0" + buffer "^6.0.3" + chalk "^4.1.0" + cli-highlight "^2.1.11" + debug "^4.3.1" + dotenv "^8.2.0" + glob "^7.1.6" + js-yaml "^4.0.0" + mkdirp "^1.0.4" + reflect-metadata "^0.1.13" + sha.js "^2.4.11" + tslib "^2.1.0" + xml2js "^0.4.23" + yargs "^17.0.1" + zen-observable-ts "^1.0.0" + + typescript@^4.5.3: + version "4.6.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.2.tgz#fe12d2727b708f4eef40f51598b3398baa9611d4" + integrity sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg== + + typescript@^4.6.3: + version "4.6.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.3.tgz#eefeafa6afdd31d725584c67a0eaba80f6fc6c6c" + integrity sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw== + + uglify-js@^3.1.4: + version "3.15.3" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.15.3.tgz#9aa82ca22419ba4c0137642ba0df800cb06e0471" + integrity sha512-6iCVm2omGJbsu3JWac+p6kUiOpg3wFO2f8lIXjfEb8RrmLjzog1wTPMmwKB7swfzzqxj9YM+sGUM++u1qN4qJg== + + ultron@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" + integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== + + unbox-primitive@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" + integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== + dependencies: + function-bind "^1.1.1" + has-bigints "^1.0.1" + has-symbols "^1.0.2" + which-boxed-primitive "^1.0.2" + + unbzip2-stream@^1.0.9: + version "1.4.3" + resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" + integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== + dependencies: + buffer "^5.2.1" + through "^2.3.8" + + unicode-canonical-property-names-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" + integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== + + unicode-match-property-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" + integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== + dependencies: + unicode-canonical-property-names-ecmascript "^2.0.0" + unicode-property-aliases-ecmascript "^2.0.0" + + unicode-match-property-value-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" + integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== + + unicode-property-aliases-ecmascript@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" + integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== + + unified@^10.0.0: + version "10.1.2" + resolved "https://registry.yarnpkg.com/unified/-/unified-10.1.2.tgz#b1d64e55dafe1f0b98bb6c719881103ecf6c86df" + integrity sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q== + dependencies: + "@types/unist" "^2.0.0" + bail "^2.0.0" + extend "^3.0.0" + is-buffer "^2.0.0" + is-plain-obj "^4.0.0" + trough "^2.0.0" + vfile "^5.0.0" + + unified@^9.1.0: + version "9.2.2" + resolved "https://registry.yarnpkg.com/unified/-/unified-9.2.2.tgz#67649a1abfc3ab85d2969502902775eb03146975" + integrity sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ== + dependencies: + bail "^1.0.0" + extend "^3.0.0" + is-buffer "^2.0.0" + is-plain-obj "^2.0.0" + trough "^1.0.0" + vfile "^4.0.0" + + union-value@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== + dependencies: + arr-union "^3.1.0" + get-value "^2.0.6" + is-extendable "^0.1.1" + set-value "^2.0.1" + + unist-builder@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/unist-builder/-/unist-builder-3.0.0.tgz#728baca4767c0e784e1e64bb44b5a5a753021a04" + integrity sha512-GFxmfEAa0vi9i5sd0R2kcrI9ks0r82NasRq5QHh2ysGngrc6GiqD5CDf1FjPenY4vApmFASBIIlk/jj5J5YbmQ== + dependencies: + "@types/unist" "^2.0.0" + + unist-util-generated@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-2.0.0.tgz#86fafb77eb6ce9bfa6b663c3f5ad4f8e56a60113" + integrity sha512-TiWE6DVtVe7Ye2QxOVW9kqybs6cZexNwTwSMVgkfjEReqy/xwGpAXb99OxktoWwmL+Z+Epb0Dn8/GNDYP1wnUw== + + unist-util-is@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.1.0.tgz#976e5f462a7a5de73d94b706bac1b90671b57797" + integrity sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg== + + unist-util-is@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-5.1.1.tgz#e8aece0b102fa9bc097b0fef8f870c496d4a6236" + integrity sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ== + + unist-util-position-from-estree@^1.0.0, unist-util-position-from-estree@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/unist-util-position-from-estree/-/unist-util-position-from-estree-1.1.1.tgz#96f4d543dfb0428edc01ebb928570b602d280c4c" + integrity sha512-xtoY50b5+7IH8tFbkw64gisG9tMSpxDjhX9TmaJJae/XuxQ9R/Kc8Nv1eOsf43Gt4KV/LkriMy9mptDr7XLcaw== + dependencies: + "@types/unist" "^2.0.0" + + unist-util-position@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-4.0.1.tgz#f8484b2da19a897a0180556d160c28633070dbb9" + integrity sha512-mgy/zI9fQ2HlbOtTdr2w9lhVaiFUHWQnZrFF2EUoVOqtAUdzqMtNiD99qA5a1IcjWVR8O6aVYE9u7Z2z1v0SQA== + + unist-util-remove-position@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-4.0.1.tgz#d5b46a7304ac114c8d91990ece085ca7c2c135c8" + integrity sha512-0yDkppiIhDlPrfHELgB+NLQD5mfjup3a8UYclHruTJWmY74je8g+CIFr79x5f6AkmzSwlvKLbs63hC0meOMowQ== + dependencies: + "@types/unist" "^2.0.0" + unist-util-visit "^4.0.0" + + unist-util-stringify-position@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da" + integrity sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g== + dependencies: + "@types/unist" "^2.0.2" + + unist-util-stringify-position@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz#5c6aa07c90b1deffd9153be170dce628a869a447" + integrity sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg== + dependencies: + "@types/unist" "^2.0.0" + + unist-util-visit-parents@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz#65a6ce698f78a6b0f56aa0e88f13801886cdaef6" + integrity sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^4.0.0" + + unist-util-visit-parents@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-4.1.1.tgz#e83559a4ad7e6048a46b1bdb22614f2f3f4724f2" + integrity sha512-1xAFJXAKpnnJl8G7K5KgU7FY55y3GcLIXqkzUj5QF/QVP7biUm0K0O2oqVkYsdjzJKifYeWn9+o6piAK2hGSHw== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^5.0.0" + + unist-util-visit-parents@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-5.1.0.tgz#44bbc5d25f2411e7dfc5cecff12de43296aa8521" + integrity sha512-y+QVLcY5eR/YVpqDsLf/xh9R3Q2Y4HxkZTp7ViLDU6WtJCEcPmRzW1gpdWDCDIqIlhuPDXOgttqPlykrHYDekg== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^5.0.0" + + unist-util-visit@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-3.1.0.tgz#9420d285e1aee938c7d9acbafc8e160186dbaf7b" + integrity sha512-Szoh+R/Ll68QWAyQyZZpQzZQm2UPbxibDvaY8Xc9SUtYgPsDzx5AWSk++UUt2hJuow8mvwR+rG+LQLw+KsuAKA== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^5.0.0" + unist-util-visit-parents "^4.0.0" + + unist-util-visit@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-4.1.0.tgz#f41e407a9e94da31594e6b1c9811c51ab0b3d8f5" + integrity sha512-n7lyhFKJfVZ9MnKtqbsqkQEk5P1KShj0+//V7mAcoI6bpbUjh3C/OG8HVD+pBihfh6Ovl01m8dkcv9HNqYajmQ== + dependencies: + "@types/unist" "^2.0.0" + unist-util-is "^5.0.0" + unist-util-visit-parents "^5.0.0" + + universalify@^0.1.0, universalify@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== + + unload@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7" + integrity sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA== + dependencies: + "@babel/runtime" "^7.6.2" + detect-node "^2.0.4" + + unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + + unset-value@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= + dependencies: + has-value "^0.3.1" + isobject "^3.0.0" + + update-input-width@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/update-input-width/-/update-input-width-1.2.2.tgz#9a6a35858ae8e66fbfe0304437b23a4934fc7d37" + integrity sha512-6QwD9ZVSXb96PxOZ01DU0DJTPwQGY7qBYgdniZKJN02Xzom2m+9J6EPxMbefskqtj4x78qbe5psDSALq9iNEYg== + + uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + + urix@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= + + url-parse-lax@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" + integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= + dependencies: + prepend-http "^1.0.1" + + url-parse-lax@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" + integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= + dependencies: + prepend-http "^2.0.0" + + url-set-query@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-set-query/-/url-set-query-1.0.0.tgz#016e8cfd7c20ee05cafe7795e892bd0702faa339" + integrity sha1-AW6M/Xwg7gXK/neV6JK9BwL6ozk= + + url-template@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21" + integrity sha1-/FZaPMy/93MMd19WQflVV5FDnyE= + + url-to-options@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" + integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k= + + use-callback-ref@^1.2.3: + version "1.2.5" + resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.2.5.tgz#6115ed242cfbaed5915499c0a9842ca2912f38a5" + integrity sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg== + + use-sidecar@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.0.5.tgz#ffff2a17c1df42e348624b699ba6e5c220527f2b" + integrity sha512-k9jnrjYNwN6xYLj1iaGhonDghfvmeTmYjAiGvOr7clwKfPjMXJf4/HOr7oT5tJwYafgp2tG2l3eZEOfoELiMcA== + dependencies: + detect-node-es "^1.1.0" + tslib "^1.9.3" + use-subscription@1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.5.1.tgz#73501107f02fad84c6dd57965beb0b75c68c42d1" integrity sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA== dependencies: object-assign "^4.1.1" + + use@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== + + utf-8-validate@^5.0.2: + version "5.0.9" + resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.9.tgz#ba16a822fbeedff1a58918f2a6a6b36387493ea3" + integrity sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q== + dependencies: + node-gyp-build "^4.3.0" + + utf8@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" + integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== + + utif@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/utif/-/utif-2.0.1.tgz#9e1582d9bbd20011a6588548ed3266298e711759" + integrity sha512-Z/S1fNKCicQTf375lIP9G8Sa1H/phcysstNrrSdZKj1f9g58J4NMgb5IgiEZN9/nLMPDwF0W7hdOe9Qq2IYoLg== + dependencies: + pako "^1.0.5" + + util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + + util@^0.12.0: + version "0.12.4" + resolved "https://registry.yarnpkg.com/util/-/util-0.12.4.tgz#66121a31420df8f01ca0c464be15dfa1d1850253" + integrity sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw== + dependencies: + inherits "^2.0.3" + is-arguments "^1.0.4" + is-generator-function "^1.0.7" + is-typed-array "^1.1.3" + safe-buffer "^5.1.2" + which-typed-array "^1.1.2" + + utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" + integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + + uuid@3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" + integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== + + uuid@^3.3.2: + version "3.4.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== + + uuid@^8.0.0, uuid@^8.3.0, uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + + uvu@^0.5.0: + version "0.5.3" + resolved "https://registry.yarnpkg.com/uvu/-/uvu-0.5.3.tgz#3d83c5bc1230f153451877bfc7f4aea2392219ae" + integrity sha512-brFwqA3FXzilmtnIyJ+CxdkInkY/i4ErvP7uV0DnUVxQcQ55reuHphorpF+tZoVHK2MniZ/VJzI7zJQoc9T9Yw== + dependencies: + dequal "^2.0.0" + diff "^5.0.0" + kleur "^4.0.3" + sade "^1.7.3" + + v8-compile-cache-lib@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz#0582bcb1c74f3a2ee46487ceecf372e46bce53e8" + integrity sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA== + + v8-compile-cache@^2.0.3: + version "2.3.0" + 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@^7.0.0: + version "7.1.2" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz#30898d1a7fa0c84d225a2c1434fb958f290883c1" + integrity sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + source-map "^0.7.3" + + v8-to-istanbul@^8.1.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed" + integrity sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^1.6.0" + source-map "^0.7.3" + + validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + + value-equal@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" + integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== + + varint@^5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.2.tgz#5b47f8a947eb668b848e034dcfa87d0ff8a7f7a4" + integrity sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow== + + vary@^1, vary@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + + verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + + vfile-message@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a" + integrity sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ== + dependencies: + "@types/unist" "^2.0.0" + unist-util-stringify-position "^2.0.0" + + vfile-message@^3.0.0: + version "3.1.2" + resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-3.1.2.tgz#a2908f64d9e557315ec9d7ea3a910f658ac05f7d" + integrity sha512-QjSNP6Yxzyycd4SVOtmKKyTsSvClqBPJcd00Z0zuPj3hOIjg0rUPG6DbFGPvUKRgYyaIWLPKpuEclcuvb3H8qA== + dependencies: + "@types/unist" "^2.0.0" + unist-util-stringify-position "^3.0.0" + + vfile@^4.0.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-4.2.1.tgz#03f1dce28fc625c625bc6514350fbdb00fa9e624" + integrity sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA== + dependencies: + "@types/unist" "^2.0.0" + is-buffer "^2.0.0" + unist-util-stringify-position "^2.0.0" + vfile-message "^2.0.0" + + vfile@^5.0.0: + version "5.3.2" + resolved "https://registry.yarnpkg.com/vfile/-/vfile-5.3.2.tgz#b499fbc50197ea50ad3749e9b60beb16ca5b7c54" + integrity sha512-w0PLIugRY3Crkgw89TeMvHCzqCs/zpreR31hl4D92y6SOE07+bfJe+dK5Q2akwS+i/c801kzjoOr9gMcTe6IAA== + dependencies: + "@types/unist" "^2.0.0" + is-buffer "^2.0.0" + unist-util-stringify-position "^3.0.0" + vfile-message "^3.0.0" + + void-elements@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" + integrity sha1-YU9/v42AHwu18GYfWy9XhXUOTwk= + + w3c-hr-time@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== + dependencies: + browser-process-hrtime "^1.0.0" + + w3c-xmlserializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== + dependencies: + xml-name-validator "^3.0.0" + + walker@^1.0.7, walker@~1.0.5: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + + warning@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" + integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== + dependencies: + loose-envify "^1.0.0" + + web3-bzz@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.7.1.tgz#ea1e7d27050eca089bc5d71b7f7688d20b68a25d" + integrity sha512-sVeUSINx4a4pfdnT+3ahdRdpDPvZDf4ZT/eBF5XtqGWq1mhGTl8XaQAk15zafKVm6Onq28vN8abgB/l+TrG8kA== + dependencies: + "@types/node" "^12.12.6" + got "9.6.0" + swarm-js "^0.1.40" + + web3-core-helpers@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.7.1.tgz#6dc34eff6ad31149db6c7cc2babbf574a09970cd" + integrity sha512-xn7Sx+s4CyukOJdlW8bBBDnUCWndr+OCJAlUe/dN2wXiyaGRiCWRhuQZrFjbxLeBt1fYFH7uWyYHhYU6muOHgw== + dependencies: + web3-eth-iban "1.7.1" + web3-utils "1.7.1" + + web3-core-method@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.7.1.tgz#912c87d0f107d3f823932cf8a716852e3250e557" + integrity sha512-383wu5FMcEphBFl5jCjk502JnEg3ugHj7MQrsX7DY76pg5N5/dEzxeEMIJFCN6kr5Iq32NINOG3VuJIyjxpsEg== + dependencies: + "@ethersproject/transactions" "^5.0.0-beta.135" + web3-core-helpers "1.7.1" + web3-core-promievent "1.7.1" + web3-core-subscriptions "1.7.1" + web3-utils "1.7.1" + + web3-core-promievent@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.7.1.tgz#7f78ec100a696954d0c882dac619fec28b2efc96" + integrity sha512-Vd+CVnpPejrnevIdxhCkzMEywqgVbhHk/AmXXceYpmwA6sX41c5a65TqXv1i3FWRJAz/dW7oKz9NAzRIBAO/kA== + dependencies: + eventemitter3 "4.0.4" + + web3-core-requestmanager@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.7.1.tgz#5cd7507276ca449538fe11cb4f363de8507502e5" + integrity sha512-/EHVTiMShpZKiq0Jka0Vgguxi3vxq1DAHKxg42miqHdUsz4/cDWay2wGALDR2x3ofDB9kqp7pb66HsvQImQeag== + dependencies: + util "^0.12.0" + web3-core-helpers "1.7.1" + web3-providers-http "1.7.1" + web3-providers-ipc "1.7.1" + web3-providers-ws "1.7.1" + + web3-core-subscriptions@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.7.1.tgz#f7c834ee3544f4a5641a989304f61fde6a523e0b" + integrity sha512-NZBsvSe4J+Wt16xCf4KEtBbxA9TOwSVr8KWfUQ0tC2KMdDYdzNswl0Q9P58xaVuNlJ3/BH+uDFZJJ5E61BSA1Q== + dependencies: + eventemitter3 "4.0.4" + web3-core-helpers "1.7.1" + + web3-core@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.7.1.tgz#ef9b7f03909387b9ab783f34cdc5ebcb50248368" + integrity sha512-HOyDPj+4cNyeNPwgSeUkhtS0F+Pxc2obcm4oRYPW5ku6jnTO34pjaij0us+zoY3QEusR8FfAKVK1kFPZnS7Dzw== + dependencies: + "@types/bn.js" "^4.11.5" + "@types/node" "^12.12.6" + bignumber.js "^9.0.0" + web3-core-helpers "1.7.1" + web3-core-method "1.7.1" + web3-core-requestmanager "1.7.1" + web3-utils "1.7.1" + + web3-eth-abi@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.7.1.tgz#6632003220a4defee4de8215dc703e43147382ea" + integrity sha512-8BVBOoFX1oheXk+t+uERBibDaVZ5dxdcefpbFTWcBs7cdm0tP8CD1ZTCLi5Xo+1bolVHNH2dMSf/nEAssq5pUA== + dependencies: + "@ethersproject/abi" "5.0.7" + web3-utils "1.7.1" + + web3-eth-accounts@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.7.1.tgz#f938060d08f4b641bebe743809b0018fd4e4ba51" + integrity sha512-3xGQ2bkTQc7LFoqGWxp5cQDrKndlX05s7m0rAFVoyZZODMqrdSGjMPMqmWqHzJRUswNEMc+oelqSnGBubqhguQ== + dependencies: + "@ethereumjs/common" "^2.5.0" + "@ethereumjs/tx" "^3.3.2" + crypto-browserify "3.12.0" + eth-lib "0.2.8" + ethereumjs-util "^7.0.10" + scrypt-js "^3.0.1" + uuid "3.3.2" + web3-core "1.7.1" + web3-core-helpers "1.7.1" + web3-core-method "1.7.1" + web3-utils "1.7.1" + + web3-eth-contract@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.7.1.tgz#3f5147e5f1441ae388c985ba95023d02503378ae" + integrity sha512-HpnbkPYkVK3lOyos2SaUjCleKfbF0SP3yjw7l551rAAi5sIz/vwlEzdPWd0IHL7ouxXbO0tDn7jzWBRcD3sTbA== + dependencies: + "@types/bn.js" "^4.11.5" + web3-core "1.7.1" + web3-core-helpers "1.7.1" + web3-core-method "1.7.1" + web3-core-promievent "1.7.1" + web3-core-subscriptions "1.7.1" + web3-eth-abi "1.7.1" + web3-utils "1.7.1" + + web3-eth-ens@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.7.1.tgz#18ddb22e14e50108f9515c9d17f14560d69ff397" + integrity sha512-DVCF76i9wM93DrPQwLrYiCw/UzxFuofBsuxTVugrnbm0SzucajLLNftp3ITK0c4/lV3x9oo5ER/wD6RRMHQnvw== + dependencies: + content-hash "^2.5.2" + eth-ens-namehash "2.0.8" + web3-core "1.7.1" + web3-core-helpers "1.7.1" + web3-core-promievent "1.7.1" + web3-eth-abi "1.7.1" + web3-eth-contract "1.7.1" + web3-utils "1.7.1" + + web3-eth-iban@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.7.1.tgz#2148dff256392491df36b175e393b03c6874cd31" + integrity sha512-XG4I3QXuKB/udRwZdNEhdYdGKjkhfb/uH477oFVMLBqNimU/Cw8yXUI5qwFKvBHM+hMQWfzPDuSDEDKC2uuiMg== + dependencies: + bn.js "^4.11.9" + web3-utils "1.7.1" + + web3-eth-personal@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.7.1.tgz#38635f94223f951422105e5fcb7f7ba767a3ee9f" + integrity sha512-02H6nFBNfNmFjMGZL6xcDi0r7tUhxrUP91FTFdoLyR94eIJDadPp4rpXfG7MVES873i1PReh4ep5pSCHbc3+Pg== + dependencies: + "@types/node" "^12.12.6" + web3-core "1.7.1" + web3-core-helpers "1.7.1" + web3-core-method "1.7.1" + web3-net "1.7.1" + web3-utils "1.7.1" + + web3-eth@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.7.1.tgz#721599865f675b43877f5a18babfb7ae087449f7" + integrity sha512-Uz3gO4CjTJ+hMyJZAd2eiv2Ur1uurpN7sTMATWKXYR/SgG+SZgncnk/9d8t23hyu4lyi2GiVL1AqVqptpRElxg== + dependencies: + web3-core "1.7.1" + web3-core-helpers "1.7.1" + web3-core-method "1.7.1" + web3-core-subscriptions "1.7.1" + web3-eth-abi "1.7.1" + web3-eth-accounts "1.7.1" + web3-eth-contract "1.7.1" + web3-eth-ens "1.7.1" + web3-eth-iban "1.7.1" + web3-eth-personal "1.7.1" + web3-net "1.7.1" + web3-utils "1.7.1" + + web3-net@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.7.1.tgz#c75ff7ccabb949cf15e9098505516eb1ed8e37de" + integrity sha512-8yPNp2gvjInWnU7DCoj4pIPNhxzUjrxKlODsyyXF8j0q3Z2VZuQp+c63gL++r2Prg4fS8t141/HcJw4aMu5sVA== + dependencies: + web3-core "1.7.1" + web3-core-method "1.7.1" + web3-utils "1.7.1" + + web3-providers-http@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.7.1.tgz#3e00e013f013766aade28da29247daa1a937e759" + integrity sha512-dmiO6G4dgAa3yv+2VD5TduKNckgfR97VI9YKXVleWdcpBoKXe2jofhdvtafd42fpIoaKiYsErxQNcOC5gI/7Vg== + dependencies: + web3-core-helpers "1.7.1" + xhr2-cookies "1.1.0" + + web3-providers-ipc@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.7.1.tgz#cde879a2ba57b1deac2e1030de90d185b793dd50" + integrity sha512-uNgLIFynwnd5M9ZC0lBvRQU5iLtU75hgaPpc7ZYYR+kjSk2jr2BkEAQhFVJ8dlqisrVmmqoAPXOEU0flYZZgNQ== + dependencies: + oboe "2.1.5" + web3-core-helpers "1.7.1" + + web3-providers-ws@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.7.1.tgz#b6b3919ce155eff29b21bc3f205a098299a8c1b2" + integrity sha512-Uj0n5hdrh0ESkMnTQBsEUS2u6Unqdc7Pe4Zl+iZFb7Yn9cIGsPJBl7/YOP4137EtD5ueXAv+MKwzcelpVhFiFg== + dependencies: + eventemitter3 "4.0.4" + web3-core-helpers "1.7.1" + websocket "^1.0.32" + + web3-shh@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.7.1.tgz#c6a0fc67321dd585085e3e3be8f2c1c8d61636ef" + integrity sha512-NO+jpEjo8kYX6c7GiaAm57Sx93PLYkWYUCWlZmUOW7URdUcux8VVluvTWklGPvdM9H1WfDrol91DjuSW+ykyqg== + dependencies: + web3-core "1.7.1" + web3-core-method "1.7.1" + web3-core-subscriptions "1.7.1" + web3-net "1.7.1" + + web3-utils@1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.7.1.tgz#77d8bacaf426c66027d8aa4864d77f0ed211aacd" + integrity sha512-fef0EsqMGJUgiHPdX+KN9okVWshbIumyJPmR+btnD1HgvoXijKEkuKBv0OmUqjbeqmLKP2/N9EiXKJel5+E1Dw== + dependencies: + bn.js "^4.11.9" + ethereum-bloom-filters "^1.0.6" + ethereumjs-util "^7.1.0" + ethjs-unit "0.1.6" + number-to-bn "1.7.0" + randombytes "^2.1.0" + utf8 "3.0.0" + + web3@^1.6.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/web3/-/web3-1.7.1.tgz#4d01371a2c0c07dba089f8009dabd2b11821c5e8" + integrity sha512-RKVdyZ5FuVEykj62C1o2tc0teJciSOh61jpVB9yb344dBHO3ZV4XPPP24s/PPqIMXmVFN00g2GD9M/v1SoHO/A== + dependencies: + web3-bzz "1.7.1" + web3-core "1.7.1" + web3-eth "1.7.1" + web3-eth-personal "1.7.1" + web3-net "1.7.1" + web3-shh "1.7.1" + web3-utils "1.7.1" + + webcrypto-core@^1.4.0: + version "1.7.1" + resolved "https://registry.yarnpkg.com/webcrypto-core/-/webcrypto-core-1.7.1.tgz#eb30112c28d0f75442cfb52cae59676c7fe155ef" + integrity sha512-Gw2zLzYSJ7Imp5lLDu3CcWB5oTTACMDEE2PjoLfttGgIhd7BfackBdVgEzd9ZM/i65gpNq0+IelL0JZ48QwzNg== + dependencies: + "@peculiar/asn1-schema" "^2.0.44" + "@peculiar/json-schema" "^1.1.12" + "@types/web" "^0.0.55" + asn1js "^2.2.0" + pvtsutils "^1.2.2" + tslib "^2.3.1" + + webextension-polyfill-ts@^0.22.0: + version "0.22.0" + resolved "https://registry.yarnpkg.com/webextension-polyfill-ts/-/webextension-polyfill-ts-0.22.0.tgz#86cfd7bab4d9d779d98c8340983f4b691b2343f3" + integrity sha512-3P33ClMwZ/qiAT7UH1ROrkRC1KM78umlnPpRhdC/292UyoTTW9NcjJEqDsv83HbibcTB6qCtpVeuB2q2/oniHQ== + dependencies: + webextension-polyfill "^0.7.0" + + webextension-polyfill-ts@^0.25.0: + version "0.25.0" + resolved "https://registry.yarnpkg.com/webextension-polyfill-ts/-/webextension-polyfill-ts-0.25.0.tgz#fff041626365dbd0e29c40b197e989a55ec221ca" + integrity sha512-ikQhwwHYkpBu00pFaUzIKY26I6L87DeRI+Q6jBT1daZUNuu8dSrg5U9l/ZbqdaQ1M/TTSPKeAa3kolP5liuedw== + dependencies: + webextension-polyfill "^0.7.0" + + webextension-polyfill@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/webextension-polyfill/-/webextension-polyfill-0.7.0.tgz#0df1120ff0266056319ce1a622b09ad8d4a56505" + integrity sha512-su48BkMLxqzTTvPSE1eWxKToPS2Tv5DLGxKexLEVpwFd6Po6N8hhSLIvG6acPAg7qERoEaDL+Y5HQJeJeml5Aw== + + webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= + + webidl-conversions@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== + + webidl-conversions@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" + integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== + + webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + + webpack-bundle-analyzer@4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.3.0.tgz#2f3c0ca9041d5ee47fa418693cf56b4a518b578b" + integrity sha512-J3TPm54bPARx6QG8z4cKBszahnUglcv70+N+8gUqv2I5KOFHJbzBiLx+pAp606so0X004fxM7hqRu10MLjJifA== + dependencies: + acorn "^8.0.4" + acorn-walk "^8.0.0" + chalk "^4.1.0" + commander "^6.2.0" + gzip-size "^6.0.0" + lodash "^4.17.20" + opener "^1.5.2" + sirv "^1.0.7" + ws "^7.3.1" + + websocket@^1.0.32: + version "1.0.34" + resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.34.tgz#2bdc2602c08bf2c82253b730655c0ef7dcab3111" + integrity sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ== + dependencies: + bufferutil "^4.0.1" + debug "^2.2.0" + es5-ext "^0.10.50" + typedarray-to-buffer "^3.1.5" + utf-8-validate "^5.0.2" + yaeti "^0.0.6" + + whatwg-encoding@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== + dependencies: + iconv-lite "0.4.24" + + whatwg-mimetype@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== + + whatwg-url@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-11.0.0.tgz#0a849eebb5faf2119b901bb76fd795c2848d4018" + integrity sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ== + dependencies: + tr46 "^3.0.0" + webidl-conversions "^7.0.0" + + whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + + whatwg-url@^8.0.0, whatwg-url@^8.5.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" + integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== + dependencies: + lodash "^4.7.0" + tr46 "^2.1.0" + webidl-conversions "^6.1.0" + + which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + + which-module@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= + + which-typed-array@^1.1.2: + version "1.1.7" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.7.tgz#2761799b9a22d4b8660b3c1b40abaa7739691793" + integrity sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + es-abstract "^1.18.5" + foreach "^2.0.5" + has-tostringtag "^1.0.0" + is-typed-array "^1.1.7" + + which@^1.2.9: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + + which@^2.0.1, which@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + + word-wrap@^1.2.3, word-wrap@~1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + + wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + + wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + + wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + + wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + + write-file-atomic@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== + dependencies: + imurmurhash "^0.1.4" + is-typedarray "^1.0.0" + signal-exit "^3.0.2" + typedarray-to-buffer "^3.1.5" + + ws@8.4.2: + version "8.4.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.4.2.tgz#18e749868d8439f2268368829042894b6907aa0b" + integrity sha512-Kbk4Nxyq7/ZWqr/tarI9yIt/+iNNFOjBXEWgTb4ydaNHBNGgvf2QHbS9fdfsndfjFlFwEd4Al+mw83YkaD10ZA== + + ws@^3.0.0: + version "3.3.3" + resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" + integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA== + dependencies: + async-limiter "~1.0.0" + safe-buffer "~5.1.0" + ultron "~1.1.0" + + ws@^7.3.1, ws@^7.4.6: + version "7.5.7" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67" + integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A== + + xhr-request-promise@^0.1.2: + version "0.1.3" + resolved "https://registry.yarnpkg.com/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz#2d5f4b16d8c6c893be97f1a62b0ed4cf3ca5f96c" + integrity sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg== + dependencies: + xhr-request "^1.1.0" + + xhr-request@^1.0.1, xhr-request@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/xhr-request/-/xhr-request-1.1.0.tgz#f4a7c1868b9f198723444d82dcae317643f2e2ed" + integrity sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA== + dependencies: + buffer-to-arraybuffer "^0.0.5" + object-assign "^4.1.1" + query-string "^5.0.1" + simple-get "^2.7.0" + timed-out "^4.0.1" + url-set-query "^1.0.0" + xhr "^2.0.4" + + xhr2-cookies@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz#7d77449d0999197f155cb73b23df72505ed89d48" + integrity sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg= + dependencies: + cookiejar "^2.1.1" + + xhr@^2.0.1, xhr@^2.0.4, xhr@^2.3.3: + version "2.6.0" + resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.6.0.tgz#b69d4395e792b4173d6b7df077f0fc5e4e2b249d" + integrity sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA== + dependencies: + global "~4.4.0" + is-function "^1.0.1" + parse-headers "^2.0.0" + xtend "^4.0.0" + + xml-crypto@2.1.3, xml-crypto@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/xml-crypto/-/xml-crypto-2.1.3.tgz#6a7272b610ea3e4ea7f13e9e4876f1b20cbc32c8" + integrity sha512-MpXZwnn9JK0mNPZ5mnFIbNnQa+8lMGK4NtnX2FlJMfMWR60sJdFO9X72yO6ji068pxixzk53O7x0/iSKh6IhyQ== + dependencies: + "@xmldom/xmldom" "^0.7.0" + xpath "0.0.32" + + xml-js@1.6.11: + version "1.6.11" + resolved "https://registry.yarnpkg.com/xml-js/-/xml-js-1.6.11.tgz#927d2f6947f7f1c19a316dd8eea3614e8b18f8e9" + integrity sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g== + dependencies: + sax "^1.2.4" + + xml-name-validator@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== + + xml-parse-from-string@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz#a9029e929d3dbcded169f3c6e28238d95a5d5a28" + integrity sha1-qQKekp09vN7RafPG4oI42VpdWig= + + xml2js@0.4.23, xml2js@^0.4.23, xml2js@^0.4.5: + version "0.4.23" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" + integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== + dependencies: + sax ">=0.6.0" + xmlbuilder "~11.0.0" + + xmlbuilder@15.1.1: + version "15.1.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5" + integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg== + + xmlbuilder@~11.0.0: + version "11.0.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" + integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== + + xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + + xpath@0.0.32: + version "0.0.32" + resolved "https://registry.yarnpkg.com/xpath/-/xpath-0.0.32.tgz#1b73d3351af736e17ec078d6da4b8175405c48af" + integrity sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw== + + xtend@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.2.0.tgz#eef6b1f198c1c8deafad8b1765a04dad4a01c5a9" + integrity sha1-7vax8ZjByN6vrYsXZaBNrUoBxak= + + xtend@^4.0.0, xtend@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + + xtend@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.0.6.tgz#5ea657a6dba447069c2e59c58a1138cb0c5e6cee" + integrity sha1-XqZXptukRwacLlnFihE4ywxebO4= + dependencies: + is-object "~0.1.2" + object-keys "~0.2.0" + + xtend@~2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" + integrity sha1-bv7MKk2tjmlixJAbM3znuoe10os= + dependencies: + object-keys "~0.4.0" + + xtend@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-3.0.0.tgz#5cce7407baf642cba7becda568111c493f59665a" + integrity sha1-XM50B7r2Qsunvs2laBEcST9ZZlo= + + y18n@^4.0.0: + version "4.0.3" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" + integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== + + y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + + yaeti@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" + integrity sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc= + + yallist@4.0.0, yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + + yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= + + yallist@^3.0.0, yallist@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + + yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + + yargs-parser@20.x, yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + + yargs-parser@^18.1.2: + version "18.1.3" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== + dependencies: + camelcase "^5.0.0" + decamelize "^1.2.0" + + yargs-parser@^21.0.0: + version "21.0.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.1.tgz#0267f286c877a4f0f728fceb6f8a3e4cb95c6e35" + integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg== + + yargs@^15.3.1, yargs@^15.4.1: + version "15.4.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" + integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== + dependencies: + cliui "^6.0.0" + decamelize "^1.2.0" + find-up "^4.1.0" + get-caller-file "^2.0.1" + require-directory "^2.1.1" + require-main-filename "^2.0.0" + set-blocking "^2.0.0" + string-width "^4.2.0" + which-module "^2.0.0" + y18n "^4.0.0" + yargs-parser "^18.1.2" + + yargs@^16.0.0, yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + + yargs@^17.0.1: + version "17.3.1" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.3.1.tgz#da56b28f32e2fd45aefb402ed9c26f42be4c07b9" + integrity sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA== + 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" + + yauzl@2.10.0, yauzl@^2.10.0, yauzl@^2.4.2: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" + + yazl@2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.5.1.tgz#a3d65d3dd659a5b0937850e8609f22fffa2b5c35" + integrity sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw== + dependencies: + buffer-crc32 "~0.2.3" + + yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + + yup@^0.32.9: + version "0.32.11" + resolved "https://registry.yarnpkg.com/yup/-/yup-0.32.11.tgz#d67fb83eefa4698607982e63f7ca4c5ed3cf18c5" + integrity sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg== + dependencies: + "@babel/runtime" "^7.15.4" + "@types/lodash" "^4.14.175" + lodash "^4.17.21" + lodash-es "^4.17.21" + nanoclone "^0.2.1" + property-expr "^2.0.4" + toposort "^2.0.2" + + zen-observable-ts@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz#2d1aa9d79b87058e9b75698b92791c1838551f83" + integrity sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA== + dependencies: + "@types/zen-observable" "0.8.3" + zen-observable "0.8.15" + + zen-observable@0.8.15: + version "0.8.15" + resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" + integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== + + zod-prisma@^0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/zod-prisma/-/zod-prisma-0.5.4.tgz#f1c4d107cb9e4c666e2432017e6dcc390ef23700" + integrity sha512-5Ca4Qd1a1jy1T/NqCEpbr0c+EsbjJfJ/7euEHob3zDvtUK2rTuD1Rc/vfzH8q8PtaR2TZbysD88NHmrLwpv3Xg== + dependencies: + "@prisma/generator-helper" "~3.8.1" + parenthesis "^3.1.8" + ts-morph "^13.0.2" + + zod@^3.14.2: + version "3.14.2" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.14.2.tgz#0b4ed79085c471adce0e7f2c0a4fbb5ddc516ba2" + integrity sha512-iF+wrtzz7fQfkmn60PG6XFxaWBhYYKzp2i+nv24WbLUWb2JjymdkHlzBwP0erpc78WotwP5g9AAu7Sk8GWVVNw== + + zod@^3.8.2, zod@^3.9.5: + version "3.13.4" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.13.4.tgz#5d6fe03ef4824a637d7ef50b5441cf6ab3acede0" + integrity sha512-LZRucWt4j/ru5azOkJxCfpR87IyFDn8h2UODdqvXzZLb3K7bb9chUrUIGTy3BPsr8XnbQYfQ5Md5Hu2OYIo1mg== + + zwitch@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920" + integrity sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw== + + zwitch@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.2.tgz#91f8d0e901ffa3d66599756dde7f57b17c95dce1" + integrity sha512-JZxotl7SxAJH0j7dN4pxsTV6ZLXoLdGME+PsjkL/DaBrVryK9kTGq06GfKrwcSOqypP+fdXGoCHE36b99fWVoA== From c2234593dbafb7d846fa49cd909ddfad3373b563 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 25 Mar 2022 19:37:51 +0100 Subject: [PATCH 020/658] feat: adds module transpiling so api can require @calcom/prisma and not @prisma/client directly --- README.md | 3 +++ lib/validations/apiKey.ts | 16 +++++++++++++ next.config.js | 9 ++++++-- package.json | 3 ++- pages/api/api-keys/[id]/delete.ts | 36 ++++++++++++++++++++++++++++++ pages/api/api-keys/[id]/edit.ts | 37 +++++++++++++++++++++++++++++++ pages/api/api-keys/[id]/index.ts | 31 ++++++++++++++++++++++++++ pages/api/api-keys/index.ts | 19 ++++++++++++++++ pages/api/api-keys/new.ts | 30 +++++++++++++++++++++++++ tsconfig.json | 2 ++ 10 files changed, 183 insertions(+), 3 deletions(-) create mode 100644 lib/validations/apiKey.ts create mode 100644 pages/api/api-keys/[id]/delete.ts create mode 100644 pages/api/api-keys/[id]/edit.ts create mode 100644 pages/api/api-keys/[id]/index.ts create mode 100644 pages/api/api-keys/index.ts create mode 100644 pages/api/api-keys/new.ts diff --git a/README.md b/README.md index c2320f50c9..f8834ae82d 100644 --- a/README.md +++ b/README.md @@ -39,3 +39,6 @@ We aim to provide a fully tested API for our peace of mind, this is accomplished Since this will only support an API, we redirect the requests to root to the /api folder. We also added a redirect for future-proofing API versioning when we might need it, without having to resort to dirty hacks like a v1/v2 folders with lots of duplicated code, instead we redirect /api/v*/:rest to /api/:rest?version=* + + +The priority is the booking-related API routes so people can build their own booking flow, then event type management routes, then availability management routes etc \ No newline at end of file diff --git a/lib/validations/apiKey.ts b/lib/validations/apiKey.ts new file mode 100644 index 0000000000..5ed6e12b76 --- /dev/null +++ b/lib/validations/apiKey.ts @@ -0,0 +1,16 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +const schemaApiKey = z + .object({ + expiresAt: z.date().optional(), // default is 30 days + note: z.string().min(1).optional(), + }) + .strict(); // Adding strict so that we can disallow passing in extra fields +const withValidApiKey = withValidation({ + schema: schemaApiKey, + type: "Zod", + mode: "body", +}); + +export { schemaApiKey, withValidApiKey }; diff --git a/next.config.js b/next.config.js index 1e6d5beae6..3f24426e89 100644 --- a/next.config.js +++ b/next.config.js @@ -1,4 +1,9 @@ -module.exports = { +const withTM = require("next-transpile-modules")([ + "@calcom/prisma", +]); + + +module.exports = withTM({ async rewrites() { return [ // This redirects requests recieved at / the root to the /api/ folder. @@ -13,4 +18,4 @@ module.exports = { }, ]; }, -}; +}); diff --git a/package.json b/package.json index 12a5753dc7..f829c22786 100644 --- a/package.json +++ b/package.json @@ -31,9 +31,10 @@ "node-mocks-http": "^1.11.0" }, "dependencies": { - "typescript": "^4.6.3", "next": "^12.1.0", + "next-transpile-modules": "^9.0.0", "next-validations": "^0.1.11", + "typescript": "^4.6.3", "zod": "^3.14.2" } } diff --git a/pages/api/api-keys/[id]/delete.ts b/pages/api/api-keys/[id]/delete.ts new file mode 100644 index 0000000000..7912907b51 --- /dev/null +++ b/pages/api/api-keys/[id]/delete.ts @@ -0,0 +1,36 @@ +import { PrismaClient } from "@prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryId, withValidQueryId } from "@lib/validations/queryIdTransformParseInt"; + +const prisma = new PrismaClient(); + +type ResponseData = { + message?: string; + error?: unknown; +}; + +export async function eventType(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryId.safeParse(query); + if (safe.success) { + if (method === "DELETE") { + // DELETE WILL DELETE THE EVENT TYPE + prisma.eventType + .delete({ where: { id: safe.data.id } }) + .then(() => { + // We only remove the event type from the database if there's an existing resource. + res.status(200).json({ message: `event-type with id: ${safe.data.id} deleted successfully` }); + }) + .catch((error) => { + // This catches the error thrown by prisma.eventType.delete() if the resource is not found. + res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); + }); + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only DELETE Method allowed in /event-types/[id]/delete endpoint" }); + } + } +} + +export default withValidQueryId(eventType); diff --git a/pages/api/api-keys/[id]/edit.ts b/pages/api/api-keys/[id]/edit.ts new file mode 100644 index 0000000000..c4eac80975 --- /dev/null +++ b/pages/api/api-keys/[id]/edit.ts @@ -0,0 +1,37 @@ +import { PrismaClient, EventType } from "@prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaEventType, withValidEventType } from "@lib/validations/eventType"; +import { schemaQueryId, withValidQueryId } from "@lib/validations/queryIdTransformParseInt"; + +const prisma = new PrismaClient(); + +type ResponseData = { + data?: EventType; + message?: string; + error?: unknown; +}; + +export async function editEventType(req: NextApiRequest, res: NextApiResponse) { + const { query, body, method } = req; + const safeQuery = await schemaQueryId.safeParse(query); + const safeBody = await schemaEventType.safeParse(body); + + if (method === "PATCH") { + if (safeQuery.success && safeBody.success) { + await prisma.eventType.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }).then(event => { + res.status(200).json({ data: event }); + }).catch(error => { + res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + }); + } + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only PATCH Method allowed for updating event-types" }); + } +} + +export default withValidQueryId(withValidEventType(editEventType)); diff --git a/pages/api/api-keys/[id]/index.ts b/pages/api/api-keys/[id]/index.ts new file mode 100644 index 0000000000..087a30cd55 --- /dev/null +++ b/pages/api/api-keys/[id]/index.ts @@ -0,0 +1,31 @@ +import { PrismaClient, EventType } from "@prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryId, withValidQueryId } from "@lib/validations/queryIdTransformParseInt"; + +const prisma = new PrismaClient(); + +type ResponseData = { + data?: EventType; + message?: string; + error?: unknown; +}; + +export async function eventType(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryId.safeParse(query); + if (safe.success) { + if (method === "GET") { + const event = await prisma.eventType.findUnique({ where: { id: safe.data.id } }); + + if (event) res.status(200).json({ data: event }); + if (!event) res.status(404).json({ message: "Event type not found" }); + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only GET Method allowed" }); + } + } +} + + +export default withValidQueryId(eventType); diff --git a/pages/api/api-keys/index.ts b/pages/api/api-keys/index.ts new file mode 100644 index 0000000000..257fa060a1 --- /dev/null +++ b/pages/api/api-keys/index.ts @@ -0,0 +1,19 @@ +import { PrismaClient, ApiKey } from "@prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +const prisma = new PrismaClient(); +type ResponseData = { + data?: ApiKey[]; + error?: unknown; +}; + +export default async function apiKey(req: NextApiRequest, res: NextApiResponse) { + try { + const apiKeys = await prisma.apiKey.findMany({ where: { id: `${req.query.eventTypeId}` } }); + res.status(200).json({ data: { ...apiKeys } }); + } catch (error) { + console.log(error); + // FIXME: Add zod for validation/error handling + res.status(400).json({ error: error }); + } +} diff --git a/pages/api/api-keys/new.ts b/pages/api/api-keys/new.ts new file mode 100644 index 0000000000..5c4e210cca --- /dev/null +++ b/pages/api/api-keys/new.ts @@ -0,0 +1,30 @@ +import { PrismaClient, ApiKey } from "@prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaApiKey, withValidApiKey } from "@lib/validations/apiKey"; + +const prisma = new PrismaClient(); +type ResponseData = { + data?: ApiKey; + message?: string; + error?: string; +}; + +async function createApiKey(req: NextApiRequest, res: NextApiResponse) { + const { body, method } = req; + if (method === "POST") { + const safe = schemaApiKey.safeParse(body); + if (safe.success && safe.data) { + await prisma.apiKey + .create({ data: { ...safe.data, user: { connect: { id: 1 } } +}}) + .then((event) => res.status(201).json({ data: event })) + .catch((error) => res.status(400).json({ message: "Could not create event type", error: error })); + } + } else { + // Reject any other HTTP method than POST + res.status(405).json({ error: "Only POST Method allowed" }); + } +} + +export default withValidApiKey(createApiKey); diff --git a/tsconfig.json b/tsconfig.json index b9b2164ce0..951cbeb88c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,7 +21,9 @@ "jsx": "preserve", "paths": { "@api/*": ["pages/api/*"], + "@prisma/client/*": ["@calcom/prisma/client/*"], "@lib/*": ["lib/*"] + }, }, "include": [ From d9c34f67e628a8af413d7f9b0785082018cadfe7 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 25 Mar 2022 20:17:37 +0100 Subject: [PATCH 021/658] feat: adds api keys endpoints, new QueryIdAsString as apiKey has a UUID string-like ID unlike the numbers of event-type or others --- lib/validations/queryIdString.ts | 20 ++++++++++++++++ lib/validations/queryIdTransformParseInt.ts | 4 ++-- next.config.js | 3 +++ pages/api/api-keys/[id]/delete.ts | 22 ++++++++--------- pages/api/api-keys/[id]/edit.ts | 26 ++++++++++----------- pages/api/api-keys/[id]/index.ts | 20 ++++++++-------- pages/api/api-keys/index.ts | 6 ++--- pages/api/api-keys/new.ts | 10 ++++---- pages/api/event-types/[id]/delete.ts | 8 +++---- pages/api/event-types/[id]/edit.ts | 10 ++++---- pages/api/event-types/[id]/index.ts | 10 ++++---- pages/api/event-types/index.ts | 6 ++--- pages/api/event-types/new.ts | 6 ++--- 13 files changed, 86 insertions(+), 65 deletions(-) create mode 100644 lib/validations/queryIdString.ts diff --git a/lib/validations/queryIdString.ts b/lib/validations/queryIdString.ts new file mode 100644 index 0000000000..02c1e6aee5 --- /dev/null +++ b/lib/validations/queryIdString.ts @@ -0,0 +1,20 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +// Extracted out as utility function so can be reused +// at different endpoints that require this validation. +const schemaQueryId = z + .object({ + // since nextjs parses query params as strings, + // we need to cast them to numbers using z.transform() and parseInt() + id: z.string().uuid() + }) + .strict(); + +const withValidQueryIdString = withValidation({ + schema: schemaQueryId, + type: "Zod", + mode: "query", +}); + +export { schemaQueryId, withValidQueryIdString }; diff --git a/lib/validations/queryIdTransformParseInt.ts b/lib/validations/queryIdTransformParseInt.ts index 1bbb5cfa09..f99ea64e18 100644 --- a/lib/validations/queryIdTransformParseInt.ts +++ b/lib/validations/queryIdTransformParseInt.ts @@ -14,10 +14,10 @@ const schemaQueryId = z }) .strict(); -const withValidQueryId = withValidation({ +const withValidQueryIdTransformParseInt = withValidation({ schema: schemaQueryId, type: "Zod", mode: "query", }); -export { schemaQueryId, withValidQueryId }; +export { schemaQueryId, withValidQueryIdTransformParseInt }; diff --git a/next.config.js b/next.config.js index 3f24426e89..7cd0ff53d7 100644 --- a/next.config.js +++ b/next.config.js @@ -1,7 +1,10 @@ +// https://www.npmjs.com/package/next-transpile-modules +// This makes our @calcom/prisma package from the monorepo to be transpiled and usable by API const withTM = require("next-transpile-modules")([ "@calcom/prisma", ]); +// use something like withPlugins([withTM], {}) if more plugins added later. module.exports = withTM({ async rewrites() { diff --git a/pages/api/api-keys/[id]/delete.ts b/pages/api/api-keys/[id]/delete.ts index 7912907b51..488712d91d 100644 --- a/pages/api/api-keys/[id]/delete.ts +++ b/pages/api/api-keys/[id]/delete.ts @@ -1,36 +1,34 @@ -import { PrismaClient } from "@prisma/client"; -import type { NextApiRequest, NextApiResponse } from "next"; +import prisma from "@calcom/prisma"; +import { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryId, withValidQueryId } from "@lib/validations/queryIdTransformParseInt"; - -const prisma = new PrismaClient(); +import { schemaQueryId, withValidQueryIdString } from "@lib/validations/queryIdString"; type ResponseData = { message?: string; error?: unknown; }; -export async function eventType(req: NextApiRequest, res: NextApiResponse) { +export async function apiKey(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; const safe = await schemaQueryId.safeParse(query); if (safe.success) { if (method === "DELETE") { // DELETE WILL DELETE THE EVENT TYPE - prisma.eventType + prisma.apiKey .delete({ where: { id: safe.data.id } }) .then(() => { - // We only remove the event type from the database if there's an existing resource. - res.status(200).json({ message: `event-type with id: ${safe.data.id} deleted successfully` }); + // We only remove the api key from the database if there's an existing resource. + res.status(200).json({ message: `api-key with id: ${safe.data.id} deleted successfully` }); }) .catch((error) => { - // This catches the error thrown by prisma.eventType.delete() if the resource is not found. + // This catches the error thrown by prisma.apiKey.delete() if the resource is not found. res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); }); } else { // Reject any other HTTP method than POST - res.status(405).json({ message: "Only DELETE Method allowed in /event-types/[id]/delete endpoint" }); + res.status(405).json({ message: "Only DELETE Method allowed in /api-keys/[id]/delete endpoint" }); } } } -export default withValidQueryId(eventType); +export default withValidQueryIdString(apiKey); diff --git a/pages/api/api-keys/[id]/edit.ts b/pages/api/api-keys/[id]/edit.ts index c4eac80975..ce97a24b8e 100644 --- a/pages/api/api-keys/[id]/edit.ts +++ b/pages/api/api-keys/[id]/edit.ts @@ -1,37 +1,37 @@ -import { PrismaClient, EventType } from "@prisma/client"; +import prisma from "@calcom/prisma"; + +import { ApiKey } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaEventType, withValidEventType } from "@lib/validations/eventType"; -import { schemaQueryId, withValidQueryId } from "@lib/validations/queryIdTransformParseInt"; - -const prisma = new PrismaClient(); +import { schemaApiKey, withValidApiKey } from "@lib/validations/apiKey"; +import { schemaQueryId, withValidQueryIdString } from "@lib/validations/queryIdString"; type ResponseData = { - data?: EventType; + data?: ApiKey; message?: string; error?: unknown; }; -export async function editEventType(req: NextApiRequest, res: NextApiResponse) { +export async function editApiKey(req: NextApiRequest, res: NextApiResponse) { const { query, body, method } = req; const safeQuery = await schemaQueryId.safeParse(query); - const safeBody = await schemaEventType.safeParse(body); + const safeBody = await schemaApiKey.safeParse(body); if (method === "PATCH") { if (safeQuery.success && safeBody.success) { - await prisma.eventType.update({ + await prisma.apiKey.update({ where: { id: safeQuery.data.id }, data: safeBody.data, - }).then(event => { - res.status(200).json({ data: event }); + }).then(apiKey => { + res.status(200).json({ data: apiKey }); }).catch(error => { res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) }); } } else { // Reject any other HTTP method than POST - res.status(405).json({ message: "Only PATCH Method allowed for updating event-types" }); + res.status(405).json({ message: "Only PATCH Method allowed for updating apiKey-types" }); } } -export default withValidQueryId(withValidEventType(editEventType)); +export default withValidQueryIdString(withValidApiKey(editApiKey)); diff --git a/pages/api/api-keys/[id]/index.ts b/pages/api/api-keys/[id]/index.ts index 087a30cd55..177ba289d9 100644 --- a/pages/api/api-keys/[id]/index.ts +++ b/pages/api/api-keys/[id]/index.ts @@ -1,25 +1,25 @@ -import { PrismaClient, EventType } from "@prisma/client"; +import prisma from "@calcom/prisma"; + +import { ApiKey } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryId, withValidQueryId } from "@lib/validations/queryIdTransformParseInt"; - -const prisma = new PrismaClient(); +import { schemaQueryId, withValidQueryIdString } from "@lib/validations/queryIdString"; type ResponseData = { - data?: EventType; + data?: ApiKey; message?: string; error?: unknown; }; -export async function eventType(req: NextApiRequest, res: NextApiResponse) { +export async function apiKey(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; const safe = await schemaQueryId.safeParse(query); if (safe.success) { if (method === "GET") { - const event = await prisma.eventType.findUnique({ where: { id: safe.data.id } }); + const apiKey = await prisma.apiKey.findUnique({ where: { id: safe.data.id } }); - if (event) res.status(200).json({ data: event }); - if (!event) res.status(404).json({ message: "Event type not found" }); + if (apiKey) res.status(200).json({ data: apiKey }); + if (!apiKey) res.status(404).json({ message: "Event type not found" }); } else { // Reject any other HTTP method than POST res.status(405).json({ message: "Only GET Method allowed" }); @@ -28,4 +28,4 @@ export async function eventType(req: NextApiRequest, res: NextApiResponse res.status(201).json({ data: event })) - .catch((error) => res.status(400).json({ message: "Could not create event type", error: error })); + .then((apiKey) => res.status(201).json({ data: apiKey })) + .catch((error) => res.status(400).json({ message: "Could not create apiKey", error: error })); } } else { // Reject any other HTTP method than POST diff --git a/pages/api/event-types/[id]/delete.ts b/pages/api/event-types/[id]/delete.ts index 7912907b51..52f2cd74b7 100644 --- a/pages/api/event-types/[id]/delete.ts +++ b/pages/api/event-types/[id]/delete.ts @@ -1,9 +1,9 @@ -import { PrismaClient } from "@prisma/client"; +import prisma from "@calcom/prisma"; + import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryId, withValidQueryId } from "@lib/validations/queryIdTransformParseInt"; +import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/queryIdTransformParseInt"; -const prisma = new PrismaClient(); type ResponseData = { message?: string; @@ -33,4 +33,4 @@ export async function eventType(req: NextApiRequest, res: NextApiResponse Date: Fri, 25 Mar 2022 23:26:22 +0100 Subject: [PATCH 022/658] feat: improve api key endpoints, add users endpoint --- lib/validations/apiKey.ts | 2 +- lib/validations/queryIdString.ts | 2 +- lib/validations/user.ts | 62 ++++++++++++++++++++++++++++++++ pages/api/api-keys/index.ts | 2 +- pages/api/api-keys/new.ts | 13 +++++-- pages/api/event-types/index.ts | 2 +- pages/api/users/[id]/delete.ts | 36 +++++++++++++++++++ pages/api/users/[id]/edit.ts | 37 +++++++++++++++++++ pages/api/users/[id]/index.ts | 31 ++++++++++++++++ pages/api/users/index.ts | 19 ++++++++++ pages/api/users/new.ts | 29 +++++++++++++++ 11 files changed, 228 insertions(+), 7 deletions(-) create mode 100644 lib/validations/user.ts create mode 100644 pages/api/users/[id]/delete.ts create mode 100644 pages/api/users/[id]/edit.ts create mode 100644 pages/api/users/[id]/index.ts create mode 100644 pages/api/users/index.ts create mode 100644 pages/api/users/new.ts diff --git a/lib/validations/apiKey.ts b/lib/validations/apiKey.ts index 5ed6e12b76..ea0fbaec3a 100644 --- a/lib/validations/apiKey.ts +++ b/lib/validations/apiKey.ts @@ -3,7 +3,7 @@ import { z } from "zod"; const schemaApiKey = z .object({ - expiresAt: z.date().optional(), // default is 30 days + expiresAt: z.string().transform((date: string) => new Date(date)).optional(), // default is 30 days note: z.string().min(1).optional(), }) .strict(); // Adding strict so that we can disallow passing in extra fields diff --git a/lib/validations/queryIdString.ts b/lib/validations/queryIdString.ts index 02c1e6aee5..ef000f2014 100644 --- a/lib/validations/queryIdString.ts +++ b/lib/validations/queryIdString.ts @@ -7,7 +7,7 @@ const schemaQueryId = z .object({ // since nextjs parses query params as strings, // we need to cast them to numbers using z.transform() and parseInt() - id: z.string().uuid() + id: z.string() }) .strict(); diff --git a/lib/validations/user.ts b/lib/validations/user.ts new file mode 100644 index 0000000000..4b24b168af --- /dev/null +++ b/lib/validations/user.ts @@ -0,0 +1,62 @@ +import { withValidation } from "next-validations"; +import { schemaEventType } from "./eventType"; +// import { schemaCredential } from "./credential"; +// import { schemaMembership } from "./membership"; +// import { schemaBooking } from "./booking"; +// import { schemaSchedule } from "./schedule"; +// import { schemaSelectedCalendar } from "./selectedCalendar"; +// import { schemaAvailability } from "./availability"; +// import { schemaWebhook } from "./webhook"; + +import { z } from "zod"; +import { schemaApiKey } from "./apiKey"; + +const schemaUser = z + .object({ + username: z.string().min(3), + name: z.string().min(3), + email: z.string().email(), // max is a full day. + emailVerified: z.date().optional(), + password: z.string().optional(), + bio: z.string().min(3).optional(), + avatar: z.string().optional(), + timeZone: z.string().default("Europe/London"), + weekStart: z.string().default("Sunday"), + bufferTime: z.number().default(0), + hideBranding: z.boolean().default(false), + theme: z.string().optional(), + trialEndsAt: z.date().optional(), + eventTypes: z.array((schemaEventType)).optional(), + // credentials: z.array((schemaCredentials)).optional(), + // teams: z.array((schemaMembership)).optional(), + // bookings: z.array((schemaBooking)).optional(), + // schedules: z.array((schemaSchedule)).optional(), + defaultScheduleId: z.number().optional(), + // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), + completedOnboarding: z.boolean().default(false), + locale: z.string().optional(), + timeFormat: z.number().optional().default(12), + twoFactorEnabled: z.boolean().default(false), + twoFactorSecret: z.string().optional(), + identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), + identityProviderId: z.string().optional(), + // availavility: z.array((schemaAvailavility)).optional(), + invitedTo: z.number().optional(), + plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), + // webhooks: z.array((schemaWebhook)).optional(), + brandColor: z.string().default("#292929"), + darkBrandColor: z.string().default("#fafafa"), + // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here + away: z.boolean().default(false), + metadata: z.object({}).optional(), + verified: z.boolean().default(false), + apiKeys: z.array((schemaApiKey)).optional(), + }) + .strict(); // Adding strict so that we can disallow passing in extra fields +const withValidUser = withValidation({ + schema: schemaUser, + type: "Zod", + mode: "body", +}); + +export { schemaUser, withValidUser }; diff --git a/pages/api/api-keys/index.ts b/pages/api/api-keys/index.ts index d6337207e2..ed0314a9fc 100644 --- a/pages/api/api-keys/index.ts +++ b/pages/api/api-keys/index.ts @@ -9,7 +9,7 @@ type ResponseData = { export default async function apiKey(req: NextApiRequest, res: NextApiResponse) { try { - const apiKeys = await prisma.apiKey.findMany({ where: { id: `${req.query.eventTypeId}` } }); + const apiKeys = await prisma.apiKey.findMany({}); res.status(200).json({ data: { ...apiKeys } }); } catch (error) { console.log(error); diff --git a/pages/api/api-keys/new.ts b/pages/api/api-keys/new.ts index 2e649321c0..4133ea80c2 100644 --- a/pages/api/api-keys/new.ts +++ b/pages/api/api-keys/new.ts @@ -16,10 +16,17 @@ async function createApiKey(req: NextApiRequest, res: NextApiResponse res.status(201).json({ data: apiKey })) - .catch((error) => res.status(400).json({ message: "Could not create apiKey", error: error })); + .catch((error) => { + console.log(error); + res.status(400).json({ message: "Could not create apiKey", error: error }) + } + ) } } else { // Reject any other HTTP method than POST diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index faad9e43ba..491989884f 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -9,7 +9,7 @@ type ResponseData = { export default async function eventType(req: NextApiRequest, res: NextApiResponse) { try { - const eventTypes = await prisma.eventType.findMany({ where: { id: Number(req.query.eventTypeId) } }); + const eventTypes = await prisma.eventType.findMany(); res.status(200).json({ data: { ...eventTypes } }); } catch (error) { console.log(error); diff --git a/pages/api/users/[id]/delete.ts b/pages/api/users/[id]/delete.ts new file mode 100644 index 0000000000..3c35fd5844 --- /dev/null +++ b/pages/api/users/[id]/delete.ts @@ -0,0 +1,36 @@ +import prisma from "@calcom/prisma"; + +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/queryIdTransformParseInt"; + + +type ResponseData = { + message?: string; + error?: unknown; +}; + +export async function user(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryId.safeParse(query); + if (safe.success) { + if (method === "DELETE") { + // DELETE WILL DELETE THE EVENT TYPE + prisma.user + .delete({ where: { id: safe.data.id } }) + .then(() => { + // We only remove the user type from the database if there's an existing resource. + res.status(200).json({ message: `user-type with id: ${safe.data.id} deleted successfully` }); + }) + .catch((error) => { + // This catches the error thrown by prisma.user.delete() if the resource is not found. + res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); + }); + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only DELETE Method allowed in /user-types/[id]/delete endpoint" }); + } + } +} + +export default withValidQueryIdTransformParseInt(user); diff --git a/pages/api/users/[id]/edit.ts b/pages/api/users/[id]/edit.ts new file mode 100644 index 0000000000..1332b3c686 --- /dev/null +++ b/pages/api/users/[id]/edit.ts @@ -0,0 +1,37 @@ +import prisma from "@calcom/prisma"; + +import { User } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaUser, withValidUser } from "@lib/validations/user"; +import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/queryIdTransformParseInt"; + +type ResponseData = { + data?: User; + message?: string; + error?: unknown; +}; + +export async function editUser(req: NextApiRequest, res: NextApiResponse) { + const { query, body, method } = req; + const safeQuery = await schemaQueryId.safeParse(query); + const safeBody = await schemaUser.safeParse(body); + + if (method === "PATCH") { + if (safeQuery.success && safeBody.success) { + await prisma.user.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }).then(user => { + res.status(200).json({ data: user }); + }).catch(error => { + res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + }); + } + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only PATCH Method allowed for updating user-types" }); + } +} + +export default withValidQueryIdTransformParseInt(withValidUser(editUser)); diff --git a/pages/api/users/[id]/index.ts b/pages/api/users/[id]/index.ts new file mode 100644 index 0000000000..7b6c991f2b --- /dev/null +++ b/pages/api/users/[id]/index.ts @@ -0,0 +1,31 @@ +import prisma from "@calcom/prisma"; + +import { User } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/queryIdTransformParseInt"; + +type ResponseData = { + data?: User; + message?: string; + error?: unknown; +}; + +export async function user(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryId.safeParse(query); + if (safe.success) { + if (method === "GET") { + const user = await prisma.user.findUnique({ where: { id: safe.data.id } }); + + if (user) res.status(200).json({ data: user }); + if (!user) res.status(404).json({ message: "Event type not found" }); + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only GET Method allowed" }); + } + } +} + + +export default withValidQueryIdTransformParseInt(user); diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts new file mode 100644 index 0000000000..3d03dcf205 --- /dev/null +++ b/pages/api/users/index.ts @@ -0,0 +1,19 @@ +import prisma from "@calcom/prisma"; + +import { User } from "@calcom/prisma/client";import type { NextApiRequest, NextApiResponse } from "next"; + +type ResponseData = { + data?: User[]; + error?: unknown; +}; + +export default async function user(req: NextApiRequest, res: NextApiResponse) { + try { + const users = await prisma.user.findMany(); + res.status(200).json({ data: { ...users } }); + } catch (error) { + console.log(error); + // FIXME: Add zod for validation/error handling + res.status(400).json({ error: error }); + } +} diff --git a/pages/api/users/new.ts b/pages/api/users/new.ts new file mode 100644 index 0000000000..4dee441ff5 --- /dev/null +++ b/pages/api/users/new.ts @@ -0,0 +1,29 @@ +import prisma from "@calcom/prisma"; + +import { User } from "@calcom/prisma/client";import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaUser, withValidUser } from "@lib/validations/user"; + +type ResponseData = { + data?: User; + message?: string; + error?: string; +}; + +async function createUser(req: NextApiRequest, res: NextApiResponse) { + const { body, method } = req; + if (method === "POST") { + const safe = schemaUser.safeParse(body); + if (safe.success && safe.data) { + await prisma.user + .create({ data: safe.data }) + .then((user) => res.status(201).json({ data: user })) + .catch((error) => res.status(400).json({ message: "Could not create user type", error: error })); + } + } else { + // Reject any other HTTP method than POST + res.status(405).json({ error: "Only POST Method allowed" }); + } +} + +export default withValidUser(createUser); From 9e8be659c56569479cb41bf7a4e0c1e2a0baf502 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 26 Mar 2022 00:42:12 +0100 Subject: [PATCH 023/658] feat: initial tests for api-keys endpoint --- __tests__/api-keys/api-key.id.test.index.ts | 83 +++++++++++++++++++ .../[id]/event-type.id.test.edit.ts | 10 +-- .../[id]/event-type.id.test.index.ts | 10 +-- lib/validations/apiKey.ts | 2 +- pages/api/api-keys/[id]/index.ts | 2 +- tsconfig.json | 1 - 6 files changed, 95 insertions(+), 13 deletions(-) create mode 100644 __tests__/api-keys/api-key.id.test.index.ts diff --git a/__tests__/api-keys/api-key.id.test.index.ts b/__tests__/api-keys/api-key.id.test.index.ts new file mode 100644 index 0000000000..cac8a6ae97 --- /dev/null +++ b/__tests__/api-keys/api-key.id.test.index.ts @@ -0,0 +1,83 @@ +import handleApiKey from "@api/api-keys/[id]"; +import { createMocks } from "node-mocks-http"; + +import prisma from "@calcom/prisma"; + +const stringifyISODate = (date: Date|undefined): string => { + return `${date?.toISOString()}` +} +describe("GET /api/api-keys/[id] with valid id as string returns an apiKey", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "GET", + query: { + id: "cl16zg6860000wwylnsgva00b", + }, + }); + const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.id} }); + await handleApiKey(req, res); + + expect(res._getStatusCode()).toBe(200); + expect(JSON.parse(res._getData())).toEqual({ data: {...apiKey, createdAt: stringifyISODate(apiKey?.createdAt), expiresAt: stringifyISODate(apiKey?.expiresAt)} }); + }); +}); + +// This can never happen under our normal nextjs setup where query is always a string | string[]. +// But seemed a good example for testing an error validation +describe("GET /api/api-keys/[id] errors if query id is number, requires a string", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "GET", + query: { + id: 1, // passing query as a number, which should fail as nextjs will try to parse it as a string + }, + }); + await handleApiKey(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(JSON.parse(res._getData())).toStrictEqual([ + { + code: "invalid_type", + expected: "string", + received: "number", + path: ["id"], + message: "Expected string, received number", + }, + ]); + }); +}); + +describe("GET /api/api-keys/[id] an id not present in db like 0, throws 404 not found", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "GET", + query: { + id: "0", // There's no apiKey with id 0 + }, + }); + await handleApiKey(req, res); + + expect(res._getStatusCode()).toBe(404); + expect(JSON.parse(res._getData())).toStrictEqual({ message: "API key was not found" }); + }); +}); + +describe("POST /api/api-keys/[id] fails, only GET allowed", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + query: { + id: "1", + }, + }); + await handleApiKey(req, res); + + expect(res._getStatusCode()).toBe(405); + expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); + }); +}); + +afterAll((done) => { + prisma.$disconnect().then(); + done(); +}); diff --git a/__tests__/event-types/[id]/event-type.id.test.edit.ts b/__tests__/event-types/[id]/event-type.id.test.edit.ts index 8f55f76a53..2b71706599 100644 --- a/__tests__/event-types/[id]/event-type.id.test.edit.ts +++ b/__tests__/event-types/[id]/event-type.id.test.edit.ts @@ -1,4 +1,4 @@ -import handleEventEdit from "@api/event-types/[id]/edit"; +import handleEventTypeEdit from "@api/event-types/[id]/edit"; import { createMocks } from "node-mocks-http"; import prisma from "@calcom/prisma"; @@ -17,7 +17,7 @@ describe("PATCH /api/event-types/[id]/edit with valid id and body updates an eve }, }); const event = await prisma.eventType.findUnique({ where: { id: 2 } }); - await handleEventEdit(req, res); + await handleEventTypeEdit(req, res); expect(res._getStatusCode()).toBe(200); if (event) event.title = "Updated title"; @@ -39,7 +39,7 @@ describe("PATCH /api/event-types/[id]/edit with invalid id returns 404", () => { }, }); const event = await prisma.eventType.findUnique({ where: { id: 2 } }); - await handleEventEdit(req, res); + await handleEventTypeEdit(req, res); expect(res._getStatusCode()).toBe(404); if (event) event.title = "Updated title"; @@ -62,7 +62,7 @@ describe("PATCH /api/event-types/[id]/edit with valid id and no body returns 400 id: "2", }, }); - await handleEventEdit(req, res); + await handleEventTypeEdit(req, res); expect(res._getStatusCode()).toBe(400); expect(JSON.parse(res._getData())).toStrictEqual([{"code": "invalid_type", "expected": "string", "message": "Required", "path": ["title"], "received": "undefined"}, {"code": "invalid_type", "expected": "string", "message": "Required", "path": ["slug"], "received": "undefined"}, {"code": "invalid_type", "expected": "number", "message": "Required", "path": ["length"], "received": "undefined"}]); @@ -82,7 +82,7 @@ describe("POST /api/event-types/[id]/edit fails, only PATCH allowed", () => { length: 1, }, }); - await handleEventEdit(req, res); + await handleEventTypeEdit(req, res); expect(res._getStatusCode()).toBe(405); expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only PATCH Method allowed for updating event-types" }); diff --git a/__tests__/event-types/[id]/event-type.id.test.index.ts b/__tests__/event-types/[id]/event-type.id.test.index.ts index a80e04c41c..61f7e718fe 100644 --- a/__tests__/event-types/[id]/event-type.id.test.index.ts +++ b/__tests__/event-types/[id]/event-type.id.test.index.ts @@ -1,4 +1,4 @@ -import handleEvent from "@api/event-types/[id]"; +import handleEventType from "@api/event-types/[id]"; import { createMocks } from "node-mocks-http"; import prisma from "@calcom/prisma"; @@ -12,7 +12,7 @@ describe("GET /api/event-types/[id] with valid id as string returns an event-typ }, }); const event = await prisma.eventType.findUnique({ where: { id: 1 } }); - await handleEvent(req, res); + await handleEventType(req, res); expect(res._getStatusCode()).toBe(200); expect(JSON.parse(res._getData())).toStrictEqual({ data: event }); @@ -29,7 +29,7 @@ describe("GET /api/event-types/[id] errors if query id is number, requires a str id: 1, // passing query as a number, which should fail as nextjs will try to parse it as a string }, }); - await handleEvent(req, res); + await handleEventType(req, res); expect(res._getStatusCode()).toBe(400); expect(JSON.parse(res._getData())).toStrictEqual([ @@ -52,7 +52,7 @@ describe("GET /api/event-types/[id] an id not present in db like 0, throws 404 n id: "0", // There's no event type with id 0 }, }); - await handleEvent(req, res); + await handleEventType(req, res); expect(res._getStatusCode()).toBe(404); expect(JSON.parse(res._getData())).toStrictEqual({ message: "Event type not found" }); @@ -67,7 +67,7 @@ describe("POST /api/event-types/[id] fails, only GET allowed", () => { id: "1", }, }); - await handleEvent(req, res); + await handleEventType(req, res); expect(res._getStatusCode()).toBe(405); expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); diff --git a/lib/validations/apiKey.ts b/lib/validations/apiKey.ts index ea0fbaec3a..5e98f3810d 100644 --- a/lib/validations/apiKey.ts +++ b/lib/validations/apiKey.ts @@ -3,7 +3,7 @@ import { z } from "zod"; const schemaApiKey = z .object({ - expiresAt: z.string().transform((date: string) => new Date(date)).optional(), // default is 30 days + expiresAt: z.string().optional(), // default is 30 days note: z.string().min(1).optional(), }) .strict(); // Adding strict so that we can disallow passing in extra fields diff --git a/pages/api/api-keys/[id]/index.ts b/pages/api/api-keys/[id]/index.ts index 177ba289d9..1c6a69c871 100644 --- a/pages/api/api-keys/[id]/index.ts +++ b/pages/api/api-keys/[id]/index.ts @@ -19,7 +19,7 @@ export async function apiKey(req: NextApiRequest, res: NextApiResponse Date: Sat, 26 Mar 2022 01:40:43 +0100 Subject: [PATCH 024/658] feat: adds tests for api keys endpoints --- __tests__/api-keys/api-key.id.test.edit.ts | 92 +++++++++++++++++++ __tests__/api-keys/api-key.id.test.index.ts | 4 +- .../[id]/event-type.id.test.edit.ts | 4 +- lib/utils/stringifyISODate.ts | 3 + lib/validations/apiKey.ts | 2 +- lib/validations/queryIdString.ts | 6 +- pages/api/api-keys/[id]/edit.ts | 11 ++- pages/api/api-keys/[id]/index.ts | 6 +- pages/api/api-keys/index.ts | 2 +- pages/api/api-keys/new.ts | 5 +- 10 files changed, 115 insertions(+), 20 deletions(-) create mode 100644 __tests__/api-keys/api-key.id.test.edit.ts create mode 100644 lib/utils/stringifyISODate.ts diff --git a/__tests__/api-keys/api-key.id.test.edit.ts b/__tests__/api-keys/api-key.id.test.edit.ts new file mode 100644 index 0000000000..0e0f5f88b8 --- /dev/null +++ b/__tests__/api-keys/api-key.id.test.edit.ts @@ -0,0 +1,92 @@ +import handleapiKeyEdit from "@api/api-keys/[id]/edit"; +import { createMocks } from "node-mocks-http"; + +import prisma from "@calcom/prisma"; +import {stringifyISODate} from "@lib/utils/stringifyISODate"; + +describe("PATCH /api/api-keys/[id]/edit with valid id and body updates an apiKey-type", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "PATCH", + query: { + id: "cl16zg6860000wwylnsgva00b", + }, + body: { + note: "Updated note", + }, + }); + const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.id } }); + await handleapiKeyEdit(req, res); + + expect(res._getStatusCode()).toBe(200); + expect(JSON.parse(res._getData())).toEqual({ data: {...apiKey, createdAt: stringifyISODate(apiKey?.createdAt), expiresAt: stringifyISODate(apiKey?.expiresAt)} }); + }); +}); + +// describe("PATCH /api/api-keys/[id]/edit with invalid id returns 404", () => { +// it("returns a message with the specified apiKeys", async () => { +// const { req, res } = createMocks({ +// method: "PATCH", +// query: { +// id: "cl16zg6860000wwylnsgva00a", +// }, +// body: { +// note: "Updated note", +// }, +// }); +// const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.id } }); +// await handleapiKeyEdit(req, res); + +// expect(res._getStatusCode()).toBe(404); +// if (apiKey) apiKey.note = "Updated note"; +// expect(JSON.parse(res._getData())).toStrictEqual({ "error": { +// "clientVersion": "3.10.0", +// "code": "P2025", +// "meta": { +// "cause": "Record to update not found.", +// }, +// }, +// "message": "apiKey with ID cl16zg6860000wwylnsgva00a not found and wasn't updated", }); +// }); +// }); + +describe("PATCH /api/api-keys/[id]/edit with valid id and no body returns 200 with an apiKey with no note and default expireAt", () => { + it("returns a message with the specified apiKeys", async () => { + const apiKey = await prisma.apiKey.create({data:{} }); + const { req, res } = createMocks({ + method: "PATCH", + query: { + id: apiKey?.id, + }, + }); + await handleapiKeyEdit(req, res); + + expect(apiKey?.note).toBeNull(); + expect(res._getStatusCode()).toBe(200); + expect(JSON.parse(res._getData())).toEqual({ data: {...apiKey, createdAt: stringifyISODate(apiKey?.createdAt), expiresAt: stringifyISODate(apiKey?.expiresAt)} }); + + }); +}); + +describe("POST /api/api-keys/[id]/edit fails, only PATCH allowed", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + query: { + id: "cl16zg6860000wwylnsgva00b", + }, + body: { + note: "Updated note", + }, + }); + await handleapiKeyEdit(req, res); + + expect(res._getStatusCode()).toBe(405); + expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only PATCH Method allowed for updating API keys" }); + }); +}); + +afterAll((done) => { + prisma.$disconnect().then(); + done(); +}); diff --git a/__tests__/api-keys/api-key.id.test.index.ts b/__tests__/api-keys/api-key.id.test.index.ts index cac8a6ae97..010d034e1f 100644 --- a/__tests__/api-keys/api-key.id.test.index.ts +++ b/__tests__/api-keys/api-key.id.test.index.ts @@ -2,10 +2,8 @@ import handleApiKey from "@api/api-keys/[id]"; import { createMocks } from "node-mocks-http"; import prisma from "@calcom/prisma"; +import {stringifyISODate} from "@lib/utils/stringifyISODate"; -const stringifyISODate = (date: Date|undefined): string => { - return `${date?.toISOString()}` -} describe("GET /api/api-keys/[id] with valid id as string returns an apiKey", () => { it("returns a message with the specified apiKeys", async () => { const { req, res } = createMocks({ diff --git a/__tests__/event-types/[id]/event-type.id.test.edit.ts b/__tests__/event-types/[id]/event-type.id.test.edit.ts index 2b71706599..ee9206298c 100644 --- a/__tests__/event-types/[id]/event-type.id.test.edit.ts +++ b/__tests__/event-types/[id]/event-type.id.test.edit.ts @@ -16,7 +16,7 @@ describe("PATCH /api/event-types/[id]/edit with valid id and body updates an eve length: 1, }, }); - const event = await prisma.eventType.findUnique({ where: { id: 2 } }); + const event = await prisma.eventType.findUnique({ where: { id: parseInt(req.query.id) } }); await handleEventTypeEdit(req, res); expect(res._getStatusCode()).toBe(200); @@ -38,7 +38,7 @@ describe("PATCH /api/event-types/[id]/edit with invalid id returns 404", () => { length: 1, }, }); - const event = await prisma.eventType.findUnique({ where: { id: 2 } }); + const event = await prisma.eventType.findUnique({ where: { id: parseInt(req.query.id) } }); await handleEventTypeEdit(req, res); expect(res._getStatusCode()).toBe(404); diff --git a/lib/utils/stringifyISODate.ts b/lib/utils/stringifyISODate.ts new file mode 100644 index 0000000000..d01b174964 --- /dev/null +++ b/lib/utils/stringifyISODate.ts @@ -0,0 +1,3 @@ +export const stringifyISODate = (date: Date|undefined): string => { + return `${date?.toISOString()}` +} \ No newline at end of file diff --git a/lib/validations/apiKey.ts b/lib/validations/apiKey.ts index 5e98f3810d..8b0069d974 100644 --- a/lib/validations/apiKey.ts +++ b/lib/validations/apiKey.ts @@ -3,7 +3,7 @@ import { z } from "zod"; const schemaApiKey = z .object({ - expiresAt: z.string().optional(), // default is 30 days + expiresAt: z.date().optional(), // default is 30 days note: z.string().min(1).optional(), }) .strict(); // Adding strict so that we can disallow passing in extra fields diff --git a/lib/validations/queryIdString.ts b/lib/validations/queryIdString.ts index ef000f2014..c221606841 100644 --- a/lib/validations/queryIdString.ts +++ b/lib/validations/queryIdString.ts @@ -3,7 +3,7 @@ import { z } from "zod"; // Extracted out as utility function so can be reused // at different endpoints that require this validation. -const schemaQueryId = z +const schemaQueryIdAsString = z .object({ // since nextjs parses query params as strings, // we need to cast them to numbers using z.transform() and parseInt() @@ -12,9 +12,9 @@ const schemaQueryId = z .strict(); const withValidQueryIdString = withValidation({ - schema: schemaQueryId, + schema: schemaQueryIdAsString, type: "Zod", mode: "query", }); -export { schemaQueryId, withValidQueryIdString }; +export { schemaQueryIdAsString, withValidQueryIdString }; diff --git a/pages/api/api-keys/[id]/edit.ts b/pages/api/api-keys/[id]/edit.ts index ce97a24b8e..269691a733 100644 --- a/pages/api/api-keys/[id]/edit.ts +++ b/pages/api/api-keys/[id]/edit.ts @@ -1,10 +1,10 @@ import prisma from "@calcom/prisma"; -import { ApiKey } from "@calcom/prisma/client"; +import { ApiKey } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; import { schemaApiKey, withValidApiKey } from "@lib/validations/apiKey"; -import { schemaQueryId, withValidQueryIdString } from "@lib/validations/queryIdString"; +import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/queryIdString"; type ResponseData = { data?: ApiKey; @@ -14,7 +14,7 @@ type ResponseData = { export async function editApiKey(req: NextApiRequest, res: NextApiResponse) { const { query, body, method } = req; - const safeQuery = await schemaQueryId.safeParse(query); + const safeQuery = await schemaQueryIdAsString.safeParse(query); const safeBody = await schemaApiKey.safeParse(body); if (method === "PATCH") { @@ -25,12 +25,13 @@ export async function editApiKey(req: NextApiRequest, res: NextApiResponse { res.status(200).json({ data: apiKey }); }).catch(error => { - res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + console.log(error) + res.status(404).json({ message: `apiKey with ID ${safeQuery.data.id} not found and wasn't updated`, error }) }); } } else { // Reject any other HTTP method than POST - res.status(405).json({ message: "Only PATCH Method allowed for updating apiKey-types" }); + res.status(405).json({ message: "Only PATCH Method allowed for updating API keys" }); } } diff --git a/pages/api/api-keys/[id]/index.ts b/pages/api/api-keys/[id]/index.ts index 1c6a69c871..f5f1a31ff2 100644 --- a/pages/api/api-keys/[id]/index.ts +++ b/pages/api/api-keys/[id]/index.ts @@ -1,9 +1,9 @@ import prisma from "@calcom/prisma"; -import { ApiKey } from "@calcom/prisma/client"; +import { ApiKey } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryId, withValidQueryIdString } from "@lib/validations/queryIdString"; +import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/queryIdString"; type ResponseData = { data?: ApiKey; @@ -13,7 +13,7 @@ type ResponseData = { export async function apiKey(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; - const safe = await schemaQueryId.safeParse(query); + const safe = await schemaQueryIdAsString.safeParse(query); if (safe.success) { if (method === "GET") { const apiKey = await prisma.apiKey.findUnique({ where: { id: safe.data.id } }); diff --git a/pages/api/api-keys/index.ts b/pages/api/api-keys/index.ts index ed0314a9fc..5af005d4e8 100644 --- a/pages/api/api-keys/index.ts +++ b/pages/api/api-keys/index.ts @@ -12,7 +12,7 @@ export default async function apiKey(req: NextApiRequest, res: NextApiResponse res.status(201).json({ data: apiKey })) .catch((error) => { - console.log(error); + // console.log(error); res.status(400).json({ message: "Could not create apiKey", error: error }) } ) From f2be36f89cbb27e9cd07759a9b851c4e2538c654 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 26 Mar 2022 01:41:22 +0100 Subject: [PATCH 025/658] fix: remove console statements --- pages/api/api-keys/[id]/edit.ts | 1 - pages/api/api-keys/new.ts | 1 - pages/api/event-types/index.ts | 1 - pages/api/users/index.ts | 1 - 4 files changed, 4 deletions(-) diff --git a/pages/api/api-keys/[id]/edit.ts b/pages/api/api-keys/[id]/edit.ts index 269691a733..445cb429b4 100644 --- a/pages/api/api-keys/[id]/edit.ts +++ b/pages/api/api-keys/[id]/edit.ts @@ -25,7 +25,6 @@ export async function editApiKey(req: NextApiRequest, res: NextApiResponse { res.status(200).json({ data: apiKey }); }).catch(error => { - console.log(error) res.status(404).json({ message: `apiKey with ID ${safeQuery.data.id} not found and wasn't updated`, error }) }); } diff --git a/pages/api/api-keys/new.ts b/pages/api/api-keys/new.ts index 0fbf6bbf33..05a59ab7ac 100644 --- a/pages/api/api-keys/new.ts +++ b/pages/api/api-keys/new.ts @@ -24,7 +24,6 @@ async function createApiKey(req: NextApiRequest, res: NextApiResponse res.status(201).json({ data: apiKey })) .catch((error) => { - // console.log(error); res.status(400).json({ message: "Could not create apiKey", error: error }) } ) diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 491989884f..3509fbcd02 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -12,7 +12,6 @@ export default async function eventType(req: NextApiRequest, res: NextApiRespons const eventTypes = await prisma.eventType.findMany(); res.status(200).json({ data: { ...eventTypes } }); } catch (error) { - console.log(error); // FIXME: Add zod for validation/error handling res.status(400).json({ error: error }); } diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 3d03dcf205..119ce2c708 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -12,7 +12,6 @@ export default async function user(req: NextApiRequest, res: NextApiResponse Date: Sat, 26 Mar 2022 01:53:56 +0100 Subject: [PATCH 026/658] feat: Adds teams endpoints and zod validations --- lib/validations/team.ts | 19 ++++++++++++++++++ pages/api/team/[id]/delete.ts | 36 ++++++++++++++++++++++++++++++++++ pages/api/team/[id]/edit.ts | 37 +++++++++++++++++++++++++++++++++++ pages/api/team/[id]/index.ts | 31 +++++++++++++++++++++++++++++ pages/api/team/index.ts | 19 ++++++++++++++++++ pages/api/team/new.ts | 30 ++++++++++++++++++++++++++++ 6 files changed, 172 insertions(+) create mode 100644 lib/validations/team.ts create mode 100644 pages/api/team/[id]/delete.ts create mode 100644 pages/api/team/[id]/edit.ts create mode 100644 pages/api/team/[id]/index.ts create mode 100644 pages/api/team/index.ts create mode 100644 pages/api/team/new.ts diff --git a/lib/validations/team.ts b/lib/validations/team.ts new file mode 100644 index 0000000000..9ed08f90d5 --- /dev/null +++ b/lib/validations/team.ts @@ -0,0 +1,19 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +const schemaTeam = z + .object({ + slug: z.string().min(3), + name: z.string().min(3), + hideBranding: z.boolean().default(false), + bio: z.string().min(3).optional(), + logo: z.string().optional(), + }) + .strict(); // Adding strict so that we can disallow passing in extra fields +const withValidTeam = withValidation({ + schema: schemaTeam, + type: "Zod", + mode: "body", +}); + +export { schemaTeam, withValidTeam }; diff --git a/pages/api/team/[id]/delete.ts b/pages/api/team/[id]/delete.ts new file mode 100644 index 0000000000..aee327a197 --- /dev/null +++ b/pages/api/team/[id]/delete.ts @@ -0,0 +1,36 @@ +import prisma from "@calcom/prisma"; + +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/queryIdTransformParseInt"; + + +type ResponseData = { + message?: string; + error?: unknown; +}; + +export async function team(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryId.safeParse(query); + if (safe.success) { + if (method === "DELETE") { + // DELETE WILL DELETE THE EVENT TYPE + prisma.team + .delete({ where: { id: safe.data.id } }) + .then(() => { + // We only remove the team type from the database if there's an existing resource. + res.status(200).json({ message: `team-type with id: ${safe.data.id} deleted successfully` }); + }) + .catch((error) => { + // This catches the error thrown by prisma.team.delete() if the resource is not found. + res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); + }); + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only DELETE Method allowed in /team-types/[id]/delete endpoint" }); + } + } +} + +export default withValidQueryIdTransformParseInt(team); diff --git a/pages/api/team/[id]/edit.ts b/pages/api/team/[id]/edit.ts new file mode 100644 index 0000000000..ac0fdc1517 --- /dev/null +++ b/pages/api/team/[id]/edit.ts @@ -0,0 +1,37 @@ +import prisma from "@calcom/prisma"; + +import { Team } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaTeam, withValidTeam } from "@lib/validations/team"; +import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/queryIdTransformParseInt"; + +type ResponseData = { + data?: Team; + message?: string; + error?: unknown; +}; + +export async function editTeam(req: NextApiRequest, res: NextApiResponse) { + const { query, body, method } = req; + const safeQuery = await schemaQueryId.safeParse(query); + const safeBody = await schemaTeam.safeParse(body); + + if (method === "PATCH") { + if (safeQuery.success && safeBody.success) { + await prisma.team.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }).then(team => { + res.status(200).json({ data: team }); + }).catch(error => { + res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + }); + } + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only PATCH Method allowed for updating team-types" }); + } +} + +export default withValidQueryIdTransformParseInt(withValidTeam(editTeam)); diff --git a/pages/api/team/[id]/index.ts b/pages/api/team/[id]/index.ts new file mode 100644 index 0000000000..50a600ca58 --- /dev/null +++ b/pages/api/team/[id]/index.ts @@ -0,0 +1,31 @@ +import prisma from "@calcom/prisma"; + +import { Team } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/queryIdTransformParseInt"; + +type ResponseData = { + data?: Team; + message?: string; + error?: unknown; +}; + +export async function team(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryId.safeParse(query); + if (safe.success) { + if (method === "GET") { + const team = await prisma.team.findUnique({ where: { id: safe.data.id } }); + + if (team) res.status(200).json({ data: team }); + if (!team) res.status(404).json({ message: "Event type not found" }); + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only GET Method allowed" }); + } + } +} + + +export default withValidQueryIdTransformParseInt(team); diff --git a/pages/api/team/index.ts b/pages/api/team/index.ts new file mode 100644 index 0000000000..d00f092c99 --- /dev/null +++ b/pages/api/team/index.ts @@ -0,0 +1,19 @@ +import prisma from "@calcom/prisma"; + +import { Team } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +type ResponseData = { + data?: Team[]; + error?: unknown; +}; + +export default async function team(req: NextApiRequest, res: NextApiResponse) { + try { + const teams = await prisma.team.findMany(); + res.status(200).json({ data: { ...teams } }); + } catch (error) { + // FIXME: Add zod for validation/error handling + res.status(400).json({ error: error }); + } +} diff --git a/pages/api/team/new.ts b/pages/api/team/new.ts new file mode 100644 index 0000000000..ebcb513777 --- /dev/null +++ b/pages/api/team/new.ts @@ -0,0 +1,30 @@ +import prisma from "@calcom/prisma"; + +import { Team } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaTeam, withValidTeam } from "@lib/validations/team"; + +type ResponseData = { + data?: Team; + message?: string; + error?: string; +}; + +async function createTeam(req: NextApiRequest, res: NextApiResponse) { + const { body, method } = req; + if (method === "POST") { + const safe = schemaTeam.safeParse(body); + if (safe.success && safe.data) { + await prisma.team + .create({ data: safe.data }) + .then((team) => res.status(201).json({ data: team })) + .catch((error) => res.status(400).json({ message: "Could not create team", error: error })); + } + } else { + // Reject any other HTTP method than POST + res.status(405).json({ error: "Only POST Method allowed" }); + } +} + +export default withValidTeam(createTeam); From 62a917c7a8b5037f7d7d4e13d41c53347d788bfd Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 26 Mar 2022 02:16:46 +0100 Subject: [PATCH 027/658] renames team -> teams adds tests for users and teams --- __tests__/teams/[id]/team.id.test.edit.ts | 93 +++++++++++++++++++++ __tests__/teams/[id]/team.id.test.index.ts | 80 ++++++++++++++++++ __tests__/users/[id]/user.id.test.edit.ts | 95 ++++++++++++++++++++++ __tests__/users/[id]/user.id.test.index.ts | 80 ++++++++++++++++++ jest.config.ts | 4 +- pages/api/api-keys/[id]/delete.ts | 4 +- pages/api/{team => teams}/[id]/delete.ts | 0 pages/api/{team => teams}/[id]/edit.ts | 2 +- pages/api/{team => teams}/[id]/index.ts | 0 pages/api/{team => teams}/index.ts | 0 pages/api/{team => teams}/new.ts | 0 pages/api/users/[id]/edit.ts | 2 +- 12 files changed, 355 insertions(+), 5 deletions(-) create mode 100644 __tests__/teams/[id]/team.id.test.edit.ts create mode 100644 __tests__/teams/[id]/team.id.test.index.ts create mode 100644 __tests__/users/[id]/user.id.test.edit.ts create mode 100644 __tests__/users/[id]/user.id.test.index.ts rename pages/api/{team => teams}/[id]/delete.ts (100%) rename pages/api/{team => teams}/[id]/edit.ts (97%) rename pages/api/{team => teams}/[id]/index.ts (100%) rename pages/api/{team => teams}/index.ts (100%) rename pages/api/{team => teams}/new.ts (100%) diff --git a/__tests__/teams/[id]/team.id.test.edit.ts b/__tests__/teams/[id]/team.id.test.edit.ts new file mode 100644 index 0000000000..7c81bf5dde --- /dev/null +++ b/__tests__/teams/[id]/team.id.test.edit.ts @@ -0,0 +1,93 @@ +import handleTeamEdit from "@api/teams/[id]/edit"; +import { createMocks } from "node-mocks-http"; + +import prisma from "@calcom/prisma"; + +describe("PATCH /api/teams/[id]/edit with valid id and body updates a team", () => { + it("returns a message with the specified teams", async () => { + const { req, res } = createMocks({ + method: "PATCH", + query: { + id: "1", + }, + body: { + name: "Updated team", + slug: "updated-team", + }, + }); + const team = await prisma.team.findUnique({ where: { id: parseInt(req.query.id) } }); + await handleTeamEdit(req, res); + + expect(res._getStatusCode()).toBe(200); + // if (team) team.name = "Updated name"; + expect(JSON.parse(res._getData())).toStrictEqual({ data: team }); + }); +}); + +describe("PATCH /api/teams/[id]/edit with invalid id returns 404", () => { + it("returns a message with the specified teams", async () => { + const { req, res } = createMocks({ + method: "PATCH", + query: { + id: "0", + }, + body: { + name: "Updated name", + slug: "updated-slug", + }, + }); + const team = await prisma.team.findUnique({ where: { id: parseInt(req.query.id) } }); + await handleTeamEdit(req, res); + + expect(res._getStatusCode()).toBe(404); + expect(JSON.parse(res._getData())).toStrictEqual({ "error": { + "clientVersion": "3.10.0", + "code": "P2025", + "meta": { + "cause": "Record to update not found.", + }, + }, + "message": "Event type with ID 0 not found and wasn't updated", }); + }); +}); + +describe("PATCH /api/teams/[id]/edit with valid id and no body returns 400 error and zod validation errors", () => { + it("returns a message with the specified teams", async () => { + const { req, res } = createMocks({ + method: "PATCH", + query: { + id: "2", + }, + }); + await handleTeamEdit(req, res); + + expect(res._getStatusCode()).toBe(400); + + // Ugly parsing of zod validation errors, not for final production but works for testing + expect(JSON.parse(res._getData())).toStrictEqual([{"code": "invalid_type", "expected": "string", "message": "Required", "path": ["slug"], "received": "undefined"}, {"code": "invalid_type", "expected": "string", "message": "Required", "path": ["name"], "received": "undefined"}]); + }); +}); + +describe("POST /api/teams/[id]/edit fails, only PATCH allowed", () => { + it("returns a message with the specified teams", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + query: { + id: "1", + }, + body: { + name: "Updated name", + slug: "updated-slug", + }, + }); + await handleTeamEdit(req, res); + + expect(res._getStatusCode()).toBe(405); + expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only PATCH Method allowed for updating teams" }); + }); +}); + +afterAll((done) => { + prisma.$disconnect().then(); + done(); +}); diff --git a/__tests__/teams/[id]/team.id.test.index.ts b/__tests__/teams/[id]/team.id.test.index.ts new file mode 100644 index 0000000000..73d6ac1eaf --- /dev/null +++ b/__tests__/teams/[id]/team.id.test.index.ts @@ -0,0 +1,80 @@ +import handleTeam from "@api/teams/[id]"; +import { createMocks } from "node-mocks-http"; + +import prisma from "@calcom/prisma"; + +describe("GET /api/teams/[id] with valid id as string returns an team-type", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "GET", + query: { + id: "1", + }, + }); + const team = await prisma.team.findUnique({ where: { id: 1 } }); + await handleTeam(req, res); + + expect(res._getStatusCode()).toBe(200); + expect(JSON.parse(res._getData())).toStrictEqual({ data: team }); + }); +}); + +// This can never happen under our normal nextjs setup where query is always a string | string[]. +// But seemed a good example for testing an error validation +describe("GET /api/teams/[id] errors if query id is number, requires a string", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "GET", + query: { + id: 1, // passing query as a number, which should fail as nextjs will try to parse it as a string + }, + }); + await handleTeam(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(JSON.parse(res._getData())).toStrictEqual([ + { + code: "invalid_type", + expected: "string", + received: "number", + path: ["id"], + message: "Expected string, received number", + }, + ]); + }); +}); + +describe("GET /api/teams/[id] an id not present in db like 0, throws 404 not found", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "GET", + query: { + id: "0", // There's no team type with id 0 + }, + }); + await handleTeam(req, res); + + expect(res._getStatusCode()).toBe(404); + expect(JSON.parse(res._getData())).toStrictEqual({ message: "Event type not found" }); + }); +}); + +describe("POST /api/teams/[id] fails, only GET allowed", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + query: { + id: "1", + }, + }); + await handleTeam(req, res); + + expect(res._getStatusCode()).toBe(405); + expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); + }); +}); + +afterAll((done) => { + prisma.$disconnect().then(); + done(); +}); diff --git a/__tests__/users/[id]/user.id.test.edit.ts b/__tests__/users/[id]/user.id.test.edit.ts new file mode 100644 index 0000000000..ee9206298c --- /dev/null +++ b/__tests__/users/[id]/user.id.test.edit.ts @@ -0,0 +1,95 @@ +import handleEventTypeEdit from "@api/event-types/[id]/edit"; +import { createMocks } from "node-mocks-http"; + +import prisma from "@calcom/prisma"; + +describe("PATCH /api/event-types/[id]/edit with valid id and body updates an event-type", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "PATCH", + query: { + id: "2", + }, + body: { + title: "Updated title", + slug: "updated-slug", + length: 1, + }, + }); + const event = await prisma.eventType.findUnique({ where: { id: parseInt(req.query.id) } }); + await handleEventTypeEdit(req, res); + + expect(res._getStatusCode()).toBe(200); + if (event) event.title = "Updated title"; + expect(JSON.parse(res._getData())).toStrictEqual({ data: event }); + }); +}); + +describe("PATCH /api/event-types/[id]/edit with invalid id returns 404", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "PATCH", + query: { + id: "0", + }, + body: { + title: "Updated title", + slug: "updated-slug", + length: 1, + }, + }); + const event = await prisma.eventType.findUnique({ where: { id: parseInt(req.query.id) } }); + await handleEventTypeEdit(req, res); + + expect(res._getStatusCode()).toBe(404); + if (event) event.title = "Updated title"; + expect(JSON.parse(res._getData())).toStrictEqual({ "error": { + "clientVersion": "3.10.0", + "code": "P2025", + "meta": { + "cause": "Record to update not found.", + }, + }, + "message": "Event type with ID 0 not found and wasn't updated", }); + }); +}); + +describe("PATCH /api/event-types/[id]/edit with valid id and no body returns 400 error and zod validation errors", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "PATCH", + query: { + id: "2", + }, + }); + await handleEventTypeEdit(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(JSON.parse(res._getData())).toStrictEqual([{"code": "invalid_type", "expected": "string", "message": "Required", "path": ["title"], "received": "undefined"}, {"code": "invalid_type", "expected": "string", "message": "Required", "path": ["slug"], "received": "undefined"}, {"code": "invalid_type", "expected": "number", "message": "Required", "path": ["length"], "received": "undefined"}]); + }); +}); + +describe("POST /api/event-types/[id]/edit fails, only PATCH allowed", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + query: { + id: "1", + }, + body: { + title: "Updated title", + slug: "updated-slug", + length: 1, + }, + }); + await handleEventTypeEdit(req, res); + + expect(res._getStatusCode()).toBe(405); + expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only PATCH Method allowed for updating event-types" }); + }); +}); + +afterAll((done) => { + prisma.$disconnect().then(); + done(); +}); diff --git a/__tests__/users/[id]/user.id.test.index.ts b/__tests__/users/[id]/user.id.test.index.ts new file mode 100644 index 0000000000..246a8bf0a8 --- /dev/null +++ b/__tests__/users/[id]/user.id.test.index.ts @@ -0,0 +1,80 @@ +import handleUser from "@api/users/[id]"; +import { createMocks } from "node-mocks-http"; + +import prisma from "@calcom/prisma"; + +describe("GET /api/users/[id] with valid id as string returns an user-type", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "GET", + query: { + id: "1", + }, + }); + const user = await prisma.user.findUnique({ where: { id: 1 } }); + await handleUser(req, res); + + expect(res._getStatusCode()).toBe(200); + expect(JSON.parse(res._getData())).toStrictEqual({ data: user }); + }); +}); + +// This can never happen under our normal nextjs setup where query is always a string | string[]. +// But seemed a good example for testing an error validation +describe("GET /api/users/[id] errors if query id is number, requires a string", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "GET", + query: { + id: 1, // passing query as a number, which should fail as nextjs will try to parse it as a string + }, + }); + await handleUser(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(JSON.parse(res._getData())).toStrictEqual([ + { + code: "invalid_type", + expected: "string", + received: "number", + path: ["id"], + message: "Expected string, received number", + }, + ]); + }); +}); + +describe("GET /api/users/[id] an id not present in db like 0, throws 404 not found", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "GET", + query: { + id: "0", // There's no user type with id 0 + }, + }); + await handleUser(req, res); + + expect(res._getStatusCode()).toBe(404); + expect(JSON.parse(res._getData())).toStrictEqual({ message: "Event type not found" }); + }); +}); + +describe("POST /api/users/[id] fails, only GET allowed", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + query: { + id: "1", + }, + }); + await handleUser(req, res); + + expect(res._getStatusCode()).toBe(405); + expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); + }); +}); + +afterAll((done) => { + prisma.$disconnect().then(); + done(); +}); diff --git a/jest.config.ts b/jest.config.ts index d6ad32763e..0baa4ba5b5 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -7,7 +7,9 @@ const config = { clearMocks: true, coverageDirectory: "./coverage", collectCoverage: true, - + "collectCoverageFrom": [ + "pages/api/**/*.ts" + ], // An array of regexp pattern strings used to skip coverage collection // coveragePathIgnorePatterns: [ // "/node_modules/" diff --git a/pages/api/api-keys/[id]/delete.ts b/pages/api/api-keys/[id]/delete.ts index 488712d91d..487ff496c0 100644 --- a/pages/api/api-keys/[id]/delete.ts +++ b/pages/api/api-keys/[id]/delete.ts @@ -1,7 +1,7 @@ import prisma from "@calcom/prisma"; import { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryId, withValidQueryIdString } from "@lib/validations/queryIdString"; +import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/queryIdString"; type ResponseData = { message?: string; @@ -10,7 +10,7 @@ type ResponseData = { export async function apiKey(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; - const safe = await schemaQueryId.safeParse(query); + const safe = await schemaQueryIdAsString.safeParse(query); if (safe.success) { if (method === "DELETE") { // DELETE WILL DELETE THE EVENT TYPE diff --git a/pages/api/team/[id]/delete.ts b/pages/api/teams/[id]/delete.ts similarity index 100% rename from pages/api/team/[id]/delete.ts rename to pages/api/teams/[id]/delete.ts diff --git a/pages/api/team/[id]/edit.ts b/pages/api/teams/[id]/edit.ts similarity index 97% rename from pages/api/team/[id]/edit.ts rename to pages/api/teams/[id]/edit.ts index ac0fdc1517..daaf27657a 100644 --- a/pages/api/team/[id]/edit.ts +++ b/pages/api/teams/[id]/edit.ts @@ -30,7 +30,7 @@ export async function editTeam(req: NextApiRequest, res: NextApiResponse Date: Sat, 26 Mar 2022 02:22:28 +0100 Subject: [PATCH 028/658] fixes tests by passing stringifyISODates to createdDate and emailVerified --- __tests__/users/[id]/user.id.test.index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/__tests__/users/[id]/user.id.test.index.ts b/__tests__/users/[id]/user.id.test.index.ts index 246a8bf0a8..5d833747d4 100644 --- a/__tests__/users/[id]/user.id.test.index.ts +++ b/__tests__/users/[id]/user.id.test.index.ts @@ -2,6 +2,7 @@ import handleUser from "@api/users/[id]"; import { createMocks } from "node-mocks-http"; import prisma from "@calcom/prisma"; +import { stringifyISODate } from "@lib/utils/stringifyISODate"; describe("GET /api/users/[id] with valid id as string returns an user-type", () => { it("returns a message with the specified events", async () => { @@ -15,7 +16,7 @@ describe("GET /api/users/[id] with valid id as string returns an user-type", () await handleUser(req, res); expect(res._getStatusCode()).toBe(200); - expect(JSON.parse(res._getData())).toStrictEqual({ data: user }); + expect(JSON.parse(res._getData())).toEqual({ data: {...user, createdDate: stringifyISODate(user?.createdDate), emailVerified: stringifyISODate(user?.emailVerified)} }); }); }); From 7998e8fc2ca6d17524a628961289892fc62465d5 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 26 Mar 2022 05:28:53 +0100 Subject: [PATCH 029/658] feat: 50% almost code coverage --- .../api-keys/[id]/api-key.id.delete.test.ts | 88 ++++++++++++ .../api-key.id.edit.test.ts} | 9 +- .../api-key.id.index.test.ts} | 5 +- __tests__/api-keys/api-key.index.test.ts | 87 ++++++++++++ __tests__/api-keys/api-key.new.test.ts | 133 ++++++++++++++++++ .../[id]/event-type.id.edit.test.ts} | 5 +- ...t.index.ts => event-type.id.index.test.ts} | 5 +- __tests__/teams/[id]/team.id.test.edit.ts | 5 +- __tests__/teams/[id]/team.id.test.index.ts | 5 +- .../[id]/user.id.edit.test.ts} | 5 +- ...id.test.index.ts => user.id.index.test.ts} | 5 +- jest.config.ts | 15 +- jest.setup.ts | 6 + lib/utils/stringifyISODate.ts | 5 + lib/validations/apiKey.ts | 3 + package.json | 2 +- pages/api/api-keys/[id]/delete.ts | 14 +- pages/api/api-keys/[id]/index.ts | 6 +- pages/api/api-keys/index.ts | 25 ++-- pages/api/api-keys/new.ts | 21 ++- pages/api/event-types/index.ts | 3 +- pages/api/event-types/new.ts | 3 +- pages/api/users/index.ts | 3 +- pages/api/users/new.ts | 3 +- tsconfig.json | 4 +- 25 files changed, 393 insertions(+), 72 deletions(-) create mode 100644 __tests__/api-keys/[id]/api-key.id.delete.test.ts rename __tests__/api-keys/{api-key.id.test.edit.ts => [id]/api-key.id.edit.test.ts} (92%) rename __tests__/api-keys/{api-key.id.test.index.ts => [id]/api-key.id.index.test.ts} (97%) create mode 100644 __tests__/api-keys/api-key.index.test.ts create mode 100644 __tests__/api-keys/api-key.new.test.ts rename __tests__/{users/[id]/user.id.test.edit.ts => event-types/[id]/event-type.id.edit.test.ts} (97%) rename __tests__/event-types/[id]/{event-type.id.test.index.ts => event-type.id.index.test.ts} (97%) rename __tests__/{event-types/[id]/event-type.id.test.edit.ts => users/[id]/user.id.edit.test.ts} (97%) rename __tests__/users/[id]/{user.id.test.index.ts => user.id.index.test.ts} (97%) create mode 100644 jest.setup.ts diff --git a/__tests__/api-keys/[id]/api-key.id.delete.test.ts b/__tests__/api-keys/[id]/api-key.id.delete.test.ts new file mode 100644 index 0000000000..3bc2626a5d --- /dev/null +++ b/__tests__/api-keys/[id]/api-key.id.delete.test.ts @@ -0,0 +1,88 @@ +import handleDeleteApiKey from "@api/api-keys/[id]/delete"; +import { createMocks } from "node-mocks-http"; + +import prisma from "@calcom/prisma"; + +describe("DELETE /api/api-keys/[id]/delete with valid id as string returns an apiKey", () => { + it("returns a message with the specified apiKeys", async () => { + const apiKey = await prisma.apiKey.findFirst() + const { req, res } = createMocks({ + method: "DELETE", + query: { + id: apiKey?.id, + }, + }); + // const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.id} }); + await handleDeleteApiKey(req, res); + + // console.log(res) + expect(res._getStatusCode()).toBe(204); + expect(JSON.parse(res._getData())).toEqual({message: `api-key with id: ${apiKey?.id} deleted successfully`}); + }); +}); + +// This can never happen under our normal nextjs setup where query is always a string | string[]. +// But seemed a good example for testing an error validation +describe("DELETE /api/api-keys/[id]/delete errors if query id is number, requires a string", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "DELETE", + query: { + id: 1, // passing query as a number, which should fail as nextjs will try to parse it as a string + }, + }); + await handleDeleteApiKey(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(JSON.parse(res._getData())).toStrictEqual([ + { + code: "invalid_type", + expected: "string", + received: "number", + path: ["id"], + message: "Expected string, received number", + }, + ]); + }); +}); + +describe("DELETE /api/api-keys/[id]/delete an id not present in db like 0, throws 404 not found", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "DELETE", + query: { + id: "0", // There's no apiKey with id 0 + }, + }); + await handleDeleteApiKey(req, res); + + expect(res._getStatusCode()).toBe(404); + expect(JSON.parse(res._getData())).toStrictEqual({ + "error": { + "clientVersion": "3.10.0", + "code": "P2025", + "meta": { + "cause": "Record to delete does not exist.", + }, + }, + "message": "Resource with id:0 was not found", + }); + }); +}); + +describe("POST /api/api-keys/[id]/delete fails, only DELETE allowed", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + query: { + id: "1", + }, + }); + await handleDeleteApiKey(req, res); + + expect(res._getStatusCode()).toBe(405); + expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only DELETE Method allowed" }); + }); +}); + + diff --git a/__tests__/api-keys/api-key.id.test.edit.ts b/__tests__/api-keys/[id]/api-key.id.edit.test.ts similarity index 92% rename from __tests__/api-keys/api-key.id.test.edit.ts rename to __tests__/api-keys/[id]/api-key.id.edit.test.ts index 0e0f5f88b8..3d4b4f35dc 100644 --- a/__tests__/api-keys/api-key.id.test.edit.ts +++ b/__tests__/api-keys/[id]/api-key.id.edit.test.ts @@ -4,8 +4,8 @@ import { createMocks } from "node-mocks-http"; import prisma from "@calcom/prisma"; import {stringifyISODate} from "@lib/utils/stringifyISODate"; -describe("PATCH /api/api-keys/[id]/edit with valid id and body updates an apiKey-type", () => { - it("returns a message with the specified apiKeys", async () => { +describe("PATCH /api/api-keys/[id]/edit with valid id and body with note", () => { + it("returns a 200 and the updated apiKey note", async () => { const { req, res } = createMocks({ method: "PATCH", query: { @@ -86,7 +86,4 @@ describe("POST /api/api-keys/[id]/edit fails, only PATCH allowed", () => { }); }); -afterAll((done) => { - prisma.$disconnect().then(); - done(); -}); + diff --git a/__tests__/api-keys/api-key.id.test.index.ts b/__tests__/api-keys/[id]/api-key.id.index.test.ts similarity index 97% rename from __tests__/api-keys/api-key.id.test.index.ts rename to __tests__/api-keys/[id]/api-key.id.index.test.ts index 010d034e1f..bdd8996b47 100644 --- a/__tests__/api-keys/api-key.id.test.index.ts +++ b/__tests__/api-keys/[id]/api-key.id.index.test.ts @@ -75,7 +75,4 @@ describe("POST /api/api-keys/[id] fails, only GET allowed", () => { }); }); -afterAll((done) => { - prisma.$disconnect().then(); - done(); -}); + diff --git a/__tests__/api-keys/api-key.index.test.ts b/__tests__/api-keys/api-key.index.test.ts new file mode 100644 index 0000000000..5c54a88d8d --- /dev/null +++ b/__tests__/api-keys/api-key.index.test.ts @@ -0,0 +1,87 @@ +import handleApiKeys from "@api/api-keys"; +import { createMocks } from "node-mocks-http"; + +import prisma from "@calcom/prisma"; +import {stringifyISODate} from "@lib/utils/stringifyISODate"; + +describe("GET /api/api-keys without any params", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "GET", + query: {}, + }); + let apiKeys = await prisma.apiKey.findMany(); + await handleApiKeys(req, res); + + expect(res._getStatusCode()).toBe(200); + apiKeys = apiKeys.map(apiKey => (apiKey = {...apiKey, createdAt: stringifyISODate(apiKey?.createdAt), expiresAt: stringifyISODate(apiKey?.expiresAt)})); + expect(JSON.parse(res._getData())).toStrictEqual(JSON.parse(JSON.stringify({ data: {...apiKeys} }))); + }); +}); + +// This can never happen under our normal nextjs setup where query is always a string | string[]. +// But seemed a good example for testing an error validation +// describe("GET /api/api-keys/[id] errors if query id is number, requires a string", () => { +// it("returns a message with the specified apiKeys", async () => { +// const { req, res } = createMocks({ +// method: "GET", +// query: { +// id: 1, // passing query as a number, which should fail as nextjs will try to parse it as a string +// }, +// }); +// await handleApiKeys(req, res); + +// expect(res._getStatusCode()).toBe(400); +// expect(JSON.parse(res._getData())).toStrictEqual([ +// { +// code: "invalid_type", +// expected: "string", +// received: "number", +// path: ["id"], +// message: "Expected string, received number", +// }, +// ]); +// }); +// }); + +// describe("GET /api/api-keys/[id] an id not present in db like 0, throws 404 not found", () => { +// it("returns a message with the specified apiKeys", async () => { +// const { req, res } = createMocks({ +// method: "GET", +// query: { +// id: "0", // There's no apiKey with id 0 +// }, +// }); +// await handleApiKey(req, res); + +// expect(res._getStatusCode()).toBe(404); +// expect(JSON.parse(res._getData())).toStrictEqual({ message: "API key was not found" }); +// }); +// }); + +describe("POST /api/api-keys/ fails, only GET allowed", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + }); + await handleApiKeys(req, res); + expect(res._getStatusCode()).toBe(405); + expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); + }); +}); + +// describe("GET /api/api-keys/ without prisma", () => { +// it("returns a message with the specified apiKeys", async () => { +// prisma.$disconnect().then(); + +// const { req, res } = createMocks({ +// method: "GET", +// }); +// await handleApiKeys(req, res); + +// expect(res._getStatusCode()).toBe(400); +// expect(JSON.parse(res._getData())).toStrictEqual({ message: "API key was not found" }); +// }); +// }); + + diff --git a/__tests__/api-keys/api-key.new.test.ts b/__tests__/api-keys/api-key.new.test.ts new file mode 100644 index 0000000000..e5763f83d5 --- /dev/null +++ b/__tests__/api-keys/api-key.new.test.ts @@ -0,0 +1,133 @@ +import handleNewApiKey from "@api/api-keys/new"; +import { createMocks } from "node-mocks-http"; + +import prisma from "@calcom/prisma"; +// import {stringifyISODate} from "@lib/utils/stringifyISODate"; + +// describe("PATCH /api/api-keys/[id]/edit with valid id and body with note", () => { +// it("returns a 200 and the updated apiKey note", async () => { +// const { req, res } = createMocks({ +// method: "PATCH", +// query: { +// id: "cl16zg6860000wwylnsgva00b", +// }, +// body: { +// note: "Updated note", +// }, +// }); +// const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.id } }); +// await handleNewApiKey(req, res); + +// expect(res._getStatusCode()).toBe(200); +// expect(JSON.parse(res._getData())).toEqual({ data: {...apiKey, createdAt: stringifyISODate(apiKey?.createdAt), expiresAt: stringifyISODate(apiKey?.expiresAt)} }); +// }); +// }); + +// // describe("PATCH /api/api-keys/[id]/edit with invalid id returns 404", () => { +// // it("returns a message with the specified apiKeys", async () => { +// // const { req, res } = createMocks({ +// // method: "PATCH", +// // query: { +// // id: "cl16zg6860000wwylnsgva00a", +// // }, +// // body: { +// // note: "Updated note", +// // }, +// // }); +// // const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.id } }); +// // await handleNewApiKey(req, res); + +// // expect(res._getStatusCode()).toBe(404); +// // if (apiKey) apiKey.note = "Updated note"; +// // expect(JSON.parse(res._getData())).toStrictEqual({ "error": { +// // "clientVersion": "3.10.0", +// // "code": "P2025", +// // "meta": { +// // "cause": "Record to update not found.", +// // }, +// // }, +// // "message": "apiKey with ID cl16zg6860000wwylnsgva00a not found and wasn't updated", }); +// // }); +// // }); + +// describe("PATCH /api/api-keys/[id]/edit with valid id and no body returns 200 with an apiKey with no note and default expireAt", () => { +// it("returns a message with the specified apiKeys", async () => { +// const apiKey = await prisma.apiKey.create({data:{} }); +// const { req, res } = createMocks({ +// method: "PATCH", +// query: { +// id: apiKey?.id, +// }, +// }); +// await handleNewApiKey(req, res); + +// expect(apiKey?.note).toBeNull(); +// expect(res._getStatusCode()).toBe(200); +// expect(JSON.parse(res._getData())).toEqual({ data: {...apiKey, createdAt: stringifyISODate(apiKey?.createdAt), expiresAt: stringifyISODate(apiKey?.expiresAt)} }); + +// }); +// }); + +describe("POST /api/api-keys/new with a note", () => { + it("returns a 201, and the created api key", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + body: { + note: "Updated note", + }, + }); + await handleNewApiKey(req, res); + + expect(res._getStatusCode()).toBe(201); + expect(JSON.parse(res._getData()).data.note).toStrictEqual("Updated note"); + }); +}); + + +describe("POST /api/api-keys/new with a slug param", () => { + it("returns error 400, and the details about invalid slug body param", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + body: { + note: "Updated note", + slug: "slug", + }, + }); + await handleNewApiKey(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(JSON.parse(res._getData())).toStrictEqual( + [{"code": "unrecognized_keys", "keys": ["slug"], "message": "Unrecognized key(s) in object: 'slug'", "path": []}] + ); + }); +}); + + +describe("GET /api/api-keys/new fails, only POST allowed", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "GET", // This POST method is not allowed + }); + await handleNewApiKey(req, res); + + expect(res._getStatusCode()).toBe(405); + expect(JSON.parse(res._getData())).toStrictEqual({ error: "Only POST Method allowed" }); + }); +}); + +describe("GET /api/api-keys/new fails, only POST allowed", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + body: { + fail: true + // note: '123', + // slug: 12, + }, + }); + await handleNewApiKey(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(JSON.parse(res._getData())).toStrictEqual({ error: "Only POST Method allowed" }); + }); +}); \ No newline at end of file diff --git a/__tests__/users/[id]/user.id.test.edit.ts b/__tests__/event-types/[id]/event-type.id.edit.test.ts similarity index 97% rename from __tests__/users/[id]/user.id.test.edit.ts rename to __tests__/event-types/[id]/event-type.id.edit.test.ts index ee9206298c..b3cd506a37 100644 --- a/__tests__/users/[id]/user.id.test.edit.ts +++ b/__tests__/event-types/[id]/event-type.id.edit.test.ts @@ -89,7 +89,4 @@ describe("POST /api/event-types/[id]/edit fails, only PATCH allowed", () => { }); }); -afterAll((done) => { - prisma.$disconnect().then(); - done(); -}); + diff --git a/__tests__/event-types/[id]/event-type.id.test.index.ts b/__tests__/event-types/[id]/event-type.id.index.test.ts similarity index 97% rename from __tests__/event-types/[id]/event-type.id.test.index.ts rename to __tests__/event-types/[id]/event-type.id.index.test.ts index 61f7e718fe..46b4e0af21 100644 --- a/__tests__/event-types/[id]/event-type.id.test.index.ts +++ b/__tests__/event-types/[id]/event-type.id.index.test.ts @@ -74,7 +74,4 @@ describe("POST /api/event-types/[id] fails, only GET allowed", () => { }); }); -afterAll((done) => { - prisma.$disconnect().then(); - done(); -}); + diff --git a/__tests__/teams/[id]/team.id.test.edit.ts b/__tests__/teams/[id]/team.id.test.edit.ts index 7c81bf5dde..43df801088 100644 --- a/__tests__/teams/[id]/team.id.test.edit.ts +++ b/__tests__/teams/[id]/team.id.test.edit.ts @@ -87,7 +87,4 @@ describe("POST /api/teams/[id]/edit fails, only PATCH allowed", () => { }); }); -afterAll((done) => { - prisma.$disconnect().then(); - done(); -}); + diff --git a/__tests__/teams/[id]/team.id.test.index.ts b/__tests__/teams/[id]/team.id.test.index.ts index 73d6ac1eaf..1f0aec27f9 100644 --- a/__tests__/teams/[id]/team.id.test.index.ts +++ b/__tests__/teams/[id]/team.id.test.index.ts @@ -74,7 +74,4 @@ describe("POST /api/teams/[id] fails, only GET allowed", () => { }); }); -afterAll((done) => { - prisma.$disconnect().then(); - done(); -}); + diff --git a/__tests__/event-types/[id]/event-type.id.test.edit.ts b/__tests__/users/[id]/user.id.edit.test.ts similarity index 97% rename from __tests__/event-types/[id]/event-type.id.test.edit.ts rename to __tests__/users/[id]/user.id.edit.test.ts index ee9206298c..b3cd506a37 100644 --- a/__tests__/event-types/[id]/event-type.id.test.edit.ts +++ b/__tests__/users/[id]/user.id.edit.test.ts @@ -89,7 +89,4 @@ describe("POST /api/event-types/[id]/edit fails, only PATCH allowed", () => { }); }); -afterAll((done) => { - prisma.$disconnect().then(); - done(); -}); + diff --git a/__tests__/users/[id]/user.id.test.index.ts b/__tests__/users/[id]/user.id.index.test.ts similarity index 97% rename from __tests__/users/[id]/user.id.test.index.ts rename to __tests__/users/[id]/user.id.index.test.ts index 5d833747d4..512677981a 100644 --- a/__tests__/users/[id]/user.id.test.index.ts +++ b/__tests__/users/[id]/user.id.index.test.ts @@ -75,7 +75,4 @@ describe("POST /api/users/[id] fails, only GET allowed", () => { }); }); -afterAll((done) => { - prisma.$disconnect().then(); - done(); -}); + diff --git a/jest.config.ts b/jest.config.ts index 0baa4ba5b5..d52a95bf87 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -10,6 +10,7 @@ const config = { "collectCoverageFrom": [ "pages/api/**/*.ts" ], + // An array of regexp pattern strings used to skip coverage collection // coveragePathIgnorePatterns: [ // "/node_modules/" @@ -27,8 +28,14 @@ const config = { ], // An object that configures minimum threshold enforcement for coverage results - // coverageThreshold: undefined, - + coverageThreshold: { + global: { + lines: 50, + functions: 40, + branches: 50, + statements: 50, + }, + }, // A path to a custom dependency extractor // dependencyExtractor: undefined, @@ -62,10 +69,10 @@ const config = { // setupFiles: [], // A list of paths to modules that run some code to configure or set up the testing framework before each test - // setupFilesAfterEnv: [], + setupFilesAfterEnv: ['/jest.setup.ts'], // The number of seconds after which a test is considered as slow and reported as such in the results. - slowTestThreshold: 1, + slowTestThreshold: 0.1, // A list of paths to snapshot serializer modules Jest should use for snapshot testing // snapshotSerializers: [], diff --git a/jest.setup.ts b/jest.setup.ts new file mode 100644 index 0000000000..b764cee58f --- /dev/null +++ b/jest.setup.ts @@ -0,0 +1,6 @@ +import prisma from "@calcom/prisma"; + +afterEach((done) => { + prisma.$disconnect().then(); + done(); +}); diff --git a/lib/utils/stringifyISODate.ts b/lib/utils/stringifyISODate.ts index d01b174964..b9317853ad 100644 --- a/lib/utils/stringifyISODate.ts +++ b/lib/utils/stringifyISODate.ts @@ -1,3 +1,8 @@ export const stringifyISODate = (date: Date|undefined): string => { return `${date?.toISOString()}` +} + +export const autoStringifyDateValues = ([key, value]: [string, unknown]): [string, unknown] => { + console.log(key,value) + return [key, typeof value === "object" && value instanceof Date ? stringifyISODate(value) : value] } \ No newline at end of file diff --git a/lib/validations/apiKey.ts b/lib/validations/apiKey.ts index 8b0069d974..a8d89d78f3 100644 --- a/lib/validations/apiKey.ts +++ b/lib/validations/apiKey.ts @@ -3,6 +3,9 @@ import { z } from "zod"; const schemaApiKey = z .object({ + // We need to cast the date as strings as when we get it from the json response + // we serve in api it is a string too (JSON doesn't directly support Date types) + createdAt: z.date().optional().or(z.string().optional()), expiresAt: z.date().optional(), // default is 30 days note: z.string().min(1).optional(), }) diff --git a/package.json b/package.json index f829c22786..b91cd3b07f 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "build": "next build", "lint": "next lint", "lint-fix": "next lint --fix", - "test": "jest --detectOpenHandles --verbose", + "test": "jest --detectOpenHandles", "type-check": "tsc --pretty --noEmit", "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist", "prepare": "husky install", diff --git a/pages/api/api-keys/[id]/delete.ts b/pages/api/api-keys/[id]/delete.ts index 487ff496c0..83b75ffd18 100644 --- a/pages/api/api-keys/[id]/delete.ts +++ b/pages/api/api-keys/[id]/delete.ts @@ -11,24 +11,22 @@ type ResponseData = { export async function apiKey(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; const safe = await schemaQueryIdAsString.safeParse(query); - if (safe.success) { - if (method === "DELETE") { + if (method === "DELETE" && safe.success) { // DELETE WILL DELETE THE EVENT TYPE - prisma.apiKey + await prisma.apiKey .delete({ where: { id: safe.data.id } }) .then(() => { // We only remove the api key from the database if there's an existing resource. - res.status(200).json({ message: `api-key with id: ${safe.data.id} deleted successfully` }); + res.status(204).json({ message: `api-key with id: ${safe.data.id} deleted successfully` }); }) .catch((error) => { // This catches the error thrown by prisma.apiKey.delete() if the resource is not found. - res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); + res.status(404).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); }); - } else { + } else { // Reject any other HTTP method than POST - res.status(405).json({ message: "Only DELETE Method allowed in /api-keys/[id]/delete endpoint" }); + res.status(405).json({ message: "Only DELETE Method allowed" }); } - } } export default withValidQueryIdString(apiKey); diff --git a/pages/api/api-keys/[id]/index.ts b/pages/api/api-keys/[id]/index.ts index f5f1a31ff2..e7af7b15d0 100644 --- a/pages/api/api-keys/[id]/index.ts +++ b/pages/api/api-keys/[id]/index.ts @@ -13,18 +13,18 @@ type ResponseData = { export async function apiKey(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; + if (method === "GET") { const safe = await schemaQueryIdAsString.safeParse(query); if (safe.success) { - if (method === "GET") { const apiKey = await prisma.apiKey.findUnique({ where: { id: safe.data.id } }); if (apiKey) res.status(200).json({ data: apiKey }); if (!apiKey) res.status(404).json({ message: "API key was not found" }); - } else { + } + } else { // Reject any other HTTP method than POST res.status(405).json({ message: "Only GET Method allowed" }); } - } } diff --git a/pages/api/api-keys/index.ts b/pages/api/api-keys/index.ts index 5af005d4e8..2268e5e2ff 100644 --- a/pages/api/api-keys/index.ts +++ b/pages/api/api-keys/index.ts @@ -1,19 +1,28 @@ import prisma from "@calcom/prisma"; -import { ApiKey } from "@calcom/prisma/client";import type { NextApiRequest, NextApiResponse } from "next"; +import { ApiKey } from "@prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; type ResponseData = { data?: ApiKey[]; error?: unknown; + message?: string; }; -export default async function apiKey(req: NextApiRequest, res: NextApiResponse) { - try { +export default async function apiKeys(req: NextApiRequest, res: NextApiResponse) { + const { method } = req; + if (method === "GET") { + // try { const apiKeys = await prisma.apiKey.findMany({}); res.status(200).json({ data: { ...apiKeys } }); - } catch (error) { - // console.log(error); - // FIXME: Add zod for validation/error handling - res.status(400).json({ error: error }); - } + // Without any params this never fails. not sure how to force test unavailable prisma query + // } catch (error) { + // // FIXME: Add zod for validation/error handling + // res.status(400).json({ error: error }); + // } + + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only GET Method allowed" }); + } } diff --git a/pages/api/api-keys/new.ts b/pages/api/api-keys/new.ts index 05a59ab7ac..500c9219c3 100644 --- a/pages/api/api-keys/new.ts +++ b/pages/api/api-keys/new.ts @@ -1,6 +1,6 @@ import prisma from "@calcom/prisma"; -import { ApiKey } from "@calcom/prisma/client"; +import { ApiKey } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; import { schemaApiKey, withValidApiKey } from "@lib/validations/apiKey"; @@ -16,17 +16,24 @@ async function createApiKey(req: NextApiRequest, res: NextApiResponse res.status(201).json({ data: apiKey })) - .catch((error) => { - res.status(400).json({ message: "Could not create apiKey", error: error }) - } - ) + if (apiKey) { + res.status(201).json({ data: apiKey }); + } else { + // Reject any other HTTP method than POST + res.status(405).json({ error: "Only POST Method allowed" }); + } + + // .then((apiKey) => res.status(201).json({ data: apiKey })) + // .catch((error) => { + // res.status(400).json({ message: "Could not create apiKey", error: error }) + // } + // ) } } else { // Reject any other HTTP method than POST diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 3509fbcd02..2ea925d76b 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -1,6 +1,7 @@ import prisma from "@calcom/prisma"; -import { EventType } from "@calcom/prisma/client";import type { NextApiRequest, NextApiResponse } from "next"; +import { EventType } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; type ResponseData = { data?: EventType[]; diff --git a/pages/api/event-types/new.ts b/pages/api/event-types/new.ts index 65d893e96c..c21d481c5d 100644 --- a/pages/api/event-types/new.ts +++ b/pages/api/event-types/new.ts @@ -1,6 +1,7 @@ import prisma from "@calcom/prisma"; -import { EventType } from "@calcom/prisma/client";import type { NextApiRequest, NextApiResponse } from "next"; +import { EventType } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; import { schemaEventType, withValidEventType } from "@lib/validations/eventType"; diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 119ce2c708..33afee9f5e 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -1,6 +1,7 @@ import prisma from "@calcom/prisma"; -import { User } from "@calcom/prisma/client";import type { NextApiRequest, NextApiResponse } from "next"; +import { User } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; type ResponseData = { data?: User[]; diff --git a/pages/api/users/new.ts b/pages/api/users/new.ts index 4dee441ff5..4eba163f6b 100644 --- a/pages/api/users/new.ts +++ b/pages/api/users/new.ts @@ -1,6 +1,7 @@ import prisma from "@calcom/prisma"; -import { User } from "@calcom/prisma/client";import type { NextApiRequest, NextApiResponse } from "next"; +import { User } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; import { schemaUser, withValidUser } from "@lib/validations/user"; diff --git a/tsconfig.json b/tsconfig.json index 5f5a6e1daa..fd13c250c3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -25,7 +25,5 @@ }, }, - "include": [ - "./**/*.ts" - ] + "include": ["./**/*.ts"] } From ac307f71614150f8f44a3098fdfd7e49154ebf17 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 26 Mar 2022 22:29:30 +0100 Subject: [PATCH 030/658] feat: adds bookings and more tests --- README.md | 45 +++++- __tests__/api-keys/api-key.index.test.ts | 87 ------------ __tests__/api-keys/api-key.new.test.ts | 133 ------------------ lib/validations/booking.ts | 65 +++++++++ lib/validations/{ => shared}/queryIdString.ts | 0 .../{ => shared}/queryIdTransformParseInt.ts | 0 pages/api/api-keys/[id]/delete.ts | 2 +- pages/api/api-keys/[id]/edit.ts | 6 +- pages/api/api-keys/[id]/index.ts | 9 +- pages/api/api-keys/new.ts | 19 +-- pages/api/bookings/[id]/delete.ts | 36 +++++ pages/api/bookings/[id]/edit.ts | 37 +++++ pages/api/bookings/[id]/index.ts | 31 ++++ pages/api/bookings/index.ts | 19 +++ pages/api/bookings/new.ts | 30 ++++ pages/api/event-types/[id]/delete.ts | 2 +- pages/api/event-types/[id]/edit.ts | 2 +- pages/api/event-types/[id]/index.ts | 2 +- pages/api/event-types/index.ts | 12 +- pages/api/teams/[id]/delete.ts | 2 +- pages/api/teams/[id]/edit.ts | 2 +- pages/api/teams/[id]/index.ts | 2 +- pages/api/users/[id]/delete.ts | 2 +- pages/api/users/[id]/edit.ts | 2 +- pages/api/users/[id]/index.ts | 2 +- .../api-keys/[id]/api-key.id.delete.test.ts | 0 .../api-keys/[id]/api-key.id.edit.test.ts | 50 +++---- .../api-keys/[id]/api-key.id.index.test.ts | 0 tests/api-keys/api-key.index.test.ts | 31 ++++ tests/api-keys/api-key.new.test.ts | 71 ++++++++++ .../[id]/event-type.id.edit.test.ts | 0 .../[id]/event-type.id.index.test.ts | 0 tests/event-types/event-type.index.test.ts | 31 ++++ tests/event-types/event-type.new.test.ts | 68 +++++++++ .../teams/[id]/team.id.test.edit.ts | 0 .../teams/[id]/team.id.test.index.ts | 0 .../users/[id]/user.id.edit.test.ts | 0 .../users/[id]/user.id.index.test.ts | 0 38 files changed, 515 insertions(+), 285 deletions(-) delete mode 100644 __tests__/api-keys/api-key.index.test.ts delete mode 100644 __tests__/api-keys/api-key.new.test.ts create mode 100644 lib/validations/booking.ts rename lib/validations/{ => shared}/queryIdString.ts (100%) rename lib/validations/{ => shared}/queryIdTransformParseInt.ts (100%) create mode 100644 pages/api/bookings/[id]/delete.ts create mode 100644 pages/api/bookings/[id]/edit.ts create mode 100644 pages/api/bookings/[id]/index.ts create mode 100644 pages/api/bookings/index.ts create mode 100644 pages/api/bookings/new.ts rename {__tests__ => tests}/api-keys/[id]/api-key.id.delete.test.ts (100%) rename {__tests__ => tests}/api-keys/[id]/api-key.id.edit.test.ts (69%) rename {__tests__ => tests}/api-keys/[id]/api-key.id.index.test.ts (100%) create mode 100644 tests/api-keys/api-key.index.test.ts create mode 100644 tests/api-keys/api-key.new.test.ts rename {__tests__ => tests}/event-types/[id]/event-type.id.edit.test.ts (100%) rename {__tests__ => tests}/event-types/[id]/event-type.id.index.test.ts (100%) create mode 100644 tests/event-types/event-type.index.test.ts create mode 100644 tests/event-types/event-type.new.test.ts rename {__tests__ => tests}/teams/[id]/team.id.test.edit.ts (100%) rename {__tests__ => tests}/teams/[id]/team.id.test.index.ts (100%) rename {__tests__ => tests}/users/[id]/user.id.edit.test.ts (100%) rename {__tests__ => tests}/users/[id]/user.id.index.test.ts (100%) diff --git a/README.md b/README.md index f8834ae82d..dc598bf1e8 100644 --- a/README.md +++ b/README.md @@ -41,4 +41,47 @@ Since this will only support an API, we redirect the requests to root to the /ap We also added a redirect for future-proofing API versioning when we might need it, without having to resort to dirty hacks like a v1/v2 folders with lots of duplicated code, instead we redirect /api/v*/:rest to /api/:rest?version=* -The priority is the booking-related API routes so people can build their own booking flow, then event type management routes, then availability management routes etc \ No newline at end of file +The priority is the booking-related API routes so people can build their own booking flow, then event type management routes, then availability management routes etc + + +How to add a new model or endpoint + +Basically there's three places of the codebase you need to think about for each feature. + +/pages/api/ +- This is the most important one, and where your endpoint will live. You will leverage nextjs dynamic routes and expose one file for each endpoint you want to support ideally. + +## How the codebase is organized. + +## The example resource -model- and it's endpoints + +### `pages/api/endpoint/` + +GET pages/api/endpoint/index.ts - Read All of your resource +POST pages/api/endpoint/new.ts - Create new resource + +### `pages/api/endpoint/[id]/` + +GET pages/api/endpoint/[id]/index.ts - Read All of your resource +PATCH pages/api/endpoint/[id]/edit.ts - Create new resource +DELETE pages/api/endpoint/[id]/delete.ts - Create new resource + + +## `/tests/` + +This is where all your endpoint's tests live, we mock prisma calls. We aim for at least 50% global coverage. Test each of your endpoints. + +### `/tests/endpoint/` + +/tests/endpoint/resource.index.test.ts - Test for your pages/api/endpoint/index.ts file +tests/endpoint/resource.new.test.ts - Create new resource + +### `/tests/endpoint/[id]/` + +`/tests/endpoint/[id]/resource.index.test.ts` - Read All of your resource +`/tests/endpoint/[id]/resource.edit.test.ts` - Create new resource +`/tests/endpoint/[id]/resource.delete.test.ts` - Create new resource + +## `/lib/validations/yourEndpoint.ts` + +- This is where our model validations, live, we try to make a 1:1 for db models, and also extract out any re-usable code into the /lib/validations/shared/ sub-folder. diff --git a/__tests__/api-keys/api-key.index.test.ts b/__tests__/api-keys/api-key.index.test.ts deleted file mode 100644 index 5c54a88d8d..0000000000 --- a/__tests__/api-keys/api-key.index.test.ts +++ /dev/null @@ -1,87 +0,0 @@ -import handleApiKeys from "@api/api-keys"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; -import {stringifyISODate} from "@lib/utils/stringifyISODate"; - -describe("GET /api/api-keys without any params", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "GET", - query: {}, - }); - let apiKeys = await prisma.apiKey.findMany(); - await handleApiKeys(req, res); - - expect(res._getStatusCode()).toBe(200); - apiKeys = apiKeys.map(apiKey => (apiKey = {...apiKey, createdAt: stringifyISODate(apiKey?.createdAt), expiresAt: stringifyISODate(apiKey?.expiresAt)})); - expect(JSON.parse(res._getData())).toStrictEqual(JSON.parse(JSON.stringify({ data: {...apiKeys} }))); - }); -}); - -// This can never happen under our normal nextjs setup where query is always a string | string[]. -// But seemed a good example for testing an error validation -// describe("GET /api/api-keys/[id] errors if query id is number, requires a string", () => { -// it("returns a message with the specified apiKeys", async () => { -// const { req, res } = createMocks({ -// method: "GET", -// query: { -// id: 1, // passing query as a number, which should fail as nextjs will try to parse it as a string -// }, -// }); -// await handleApiKeys(req, res); - -// expect(res._getStatusCode()).toBe(400); -// expect(JSON.parse(res._getData())).toStrictEqual([ -// { -// code: "invalid_type", -// expected: "string", -// received: "number", -// path: ["id"], -// message: "Expected string, received number", -// }, -// ]); -// }); -// }); - -// describe("GET /api/api-keys/[id] an id not present in db like 0, throws 404 not found", () => { -// it("returns a message with the specified apiKeys", async () => { -// const { req, res } = createMocks({ -// method: "GET", -// query: { -// id: "0", // There's no apiKey with id 0 -// }, -// }); -// await handleApiKey(req, res); - -// expect(res._getStatusCode()).toBe(404); -// expect(JSON.parse(res._getData())).toStrictEqual({ message: "API key was not found" }); -// }); -// }); - -describe("POST /api/api-keys/ fails, only GET allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - }); - await handleApiKeys(req, res); - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); - }); -}); - -// describe("GET /api/api-keys/ without prisma", () => { -// it("returns a message with the specified apiKeys", async () => { -// prisma.$disconnect().then(); - -// const { req, res } = createMocks({ -// method: "GET", -// }); -// await handleApiKeys(req, res); - -// expect(res._getStatusCode()).toBe(400); -// expect(JSON.parse(res._getData())).toStrictEqual({ message: "API key was not found" }); -// }); -// }); - - diff --git a/__tests__/api-keys/api-key.new.test.ts b/__tests__/api-keys/api-key.new.test.ts deleted file mode 100644 index e5763f83d5..0000000000 --- a/__tests__/api-keys/api-key.new.test.ts +++ /dev/null @@ -1,133 +0,0 @@ -import handleNewApiKey from "@api/api-keys/new"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; -// import {stringifyISODate} from "@lib/utils/stringifyISODate"; - -// describe("PATCH /api/api-keys/[id]/edit with valid id and body with note", () => { -// it("returns a 200 and the updated apiKey note", async () => { -// const { req, res } = createMocks({ -// method: "PATCH", -// query: { -// id: "cl16zg6860000wwylnsgva00b", -// }, -// body: { -// note: "Updated note", -// }, -// }); -// const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.id } }); -// await handleNewApiKey(req, res); - -// expect(res._getStatusCode()).toBe(200); -// expect(JSON.parse(res._getData())).toEqual({ data: {...apiKey, createdAt: stringifyISODate(apiKey?.createdAt), expiresAt: stringifyISODate(apiKey?.expiresAt)} }); -// }); -// }); - -// // describe("PATCH /api/api-keys/[id]/edit with invalid id returns 404", () => { -// // it("returns a message with the specified apiKeys", async () => { -// // const { req, res } = createMocks({ -// // method: "PATCH", -// // query: { -// // id: "cl16zg6860000wwylnsgva00a", -// // }, -// // body: { -// // note: "Updated note", -// // }, -// // }); -// // const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.id } }); -// // await handleNewApiKey(req, res); - -// // expect(res._getStatusCode()).toBe(404); -// // if (apiKey) apiKey.note = "Updated note"; -// // expect(JSON.parse(res._getData())).toStrictEqual({ "error": { -// // "clientVersion": "3.10.0", -// // "code": "P2025", -// // "meta": { -// // "cause": "Record to update not found.", -// // }, -// // }, -// // "message": "apiKey with ID cl16zg6860000wwylnsgva00a not found and wasn't updated", }); -// // }); -// // }); - -// describe("PATCH /api/api-keys/[id]/edit with valid id and no body returns 200 with an apiKey with no note and default expireAt", () => { -// it("returns a message with the specified apiKeys", async () => { -// const apiKey = await prisma.apiKey.create({data:{} }); -// const { req, res } = createMocks({ -// method: "PATCH", -// query: { -// id: apiKey?.id, -// }, -// }); -// await handleNewApiKey(req, res); - -// expect(apiKey?.note).toBeNull(); -// expect(res._getStatusCode()).toBe(200); -// expect(JSON.parse(res._getData())).toEqual({ data: {...apiKey, createdAt: stringifyISODate(apiKey?.createdAt), expiresAt: stringifyISODate(apiKey?.expiresAt)} }); - -// }); -// }); - -describe("POST /api/api-keys/new with a note", () => { - it("returns a 201, and the created api key", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - body: { - note: "Updated note", - }, - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(201); - expect(JSON.parse(res._getData()).data.note).toStrictEqual("Updated note"); - }); -}); - - -describe("POST /api/api-keys/new with a slug param", () => { - it("returns error 400, and the details about invalid slug body param", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - body: { - note: "Updated note", - slug: "slug", - }, - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual( - [{"code": "unrecognized_keys", "keys": ["slug"], "message": "Unrecognized key(s) in object: 'slug'", "path": []}] - ); - }); -}); - - -describe("GET /api/api-keys/new fails, only POST allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "GET", // This POST method is not allowed - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ error: "Only POST Method allowed" }); - }); -}); - -describe("GET /api/api-keys/new fails, only POST allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - body: { - fail: true - // note: '123', - // slug: 12, - }, - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual({ error: "Only POST Method allowed" }); - }); -}); \ No newline at end of file diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts new file mode 100644 index 0000000000..fb50c9c9ad --- /dev/null +++ b/lib/validations/booking.ts @@ -0,0 +1,65 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +const schemaBooking = z + .object({ + uid: z.string().min(3), + title: z.string().min(3), + description: z.string().min(3).optional(), + startTime: z.date().or(z.string()), + endTime: z.date(), + location: z.string().min(3).optional(), + createdAt: z.date().or(z.string()), + updatedAt: z.date(), + confirmed: z.boolean().default(true), + rejected: z.boolean().default(false), + paid: z.boolean().default(false), + + // bufferTime: z.number().default(0), + // // attendees: z.array((schemaSchedule)).optional(), + + // startTime: z.string().min(3), + // endTime: z.string().min(3), + // email: z.string().email(), // max is a full day. + // emailVerified: z.date().optional(), + // password: z.string().optional(), + // bio: z.string().min(3).optional(), + // avatar: z.string().optional(), + // timeZone: z.string().default("Europe/London"), + // weekStart: z.string().default("Sunday"), + // bufferTime: z.number().default(0), + // theme: z.string().optional(), + // trialEndsAt: z.date().optional(), + // eventTypes: z.array((schemaEventType)).optional(), + // // credentials: z.array((schemaCredentials)).optional(), + // // teams: z.array((schemaMembership)).optional(), + // // bookings: z.array((schemaBooking)).optional(), + // // schedules: z.array((schemaSchedule)).optional(), + // defaultScheduleId: z.number().optional(), + // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), + // completedOnboarding: z.boolean().default(false), + // locale: z.string().optional(), + // timeFormat: z.number().optional().default(12), + // twoFactorEnabled: z.boolean().default(false), + // twoFactorSecret: z.string().optional(), + // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), + // identityProviderId: z.string().optional(), + // // availavility: z.array((schemaAvailavility)).optional(), + // invitedTo: z.number().optional(), + // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), + // // webhooks: z.array((schemaWebhook)).optional(), + // brandColor: z.string().default("#292929"), + // darkBrandColor: z.string().default("#fafafa"), + // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here + // away: z.boolean().default(false), + // metadata: z.object({}).optional(), + // verified: z.boolean().default(false), + }) + .strict(); // Adding strict so that we can disallow passing in extra fields +const withValidBooking = withValidation({ + schema: schemaBooking, + type: "Zod", + mode: "body", +}); + +export { schemaBooking, withValidBooking }; diff --git a/lib/validations/queryIdString.ts b/lib/validations/shared/queryIdString.ts similarity index 100% rename from lib/validations/queryIdString.ts rename to lib/validations/shared/queryIdString.ts diff --git a/lib/validations/queryIdTransformParseInt.ts b/lib/validations/shared/queryIdTransformParseInt.ts similarity index 100% rename from lib/validations/queryIdTransformParseInt.ts rename to lib/validations/shared/queryIdTransformParseInt.ts diff --git a/pages/api/api-keys/[id]/delete.ts b/pages/api/api-keys/[id]/delete.ts index 83b75ffd18..dbd64971f9 100644 --- a/pages/api/api-keys/[id]/delete.ts +++ b/pages/api/api-keys/[id]/delete.ts @@ -1,7 +1,7 @@ import prisma from "@calcom/prisma"; import { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/queryIdString"; +import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; type ResponseData = { message?: string; diff --git a/pages/api/api-keys/[id]/edit.ts b/pages/api/api-keys/[id]/edit.ts index 445cb429b4..117e494eb9 100644 --- a/pages/api/api-keys/[id]/edit.ts +++ b/pages/api/api-keys/[id]/edit.ts @@ -4,7 +4,7 @@ import { ApiKey } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; import { schemaApiKey, withValidApiKey } from "@lib/validations/apiKey"; -import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/queryIdString"; +import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; type ResponseData = { data?: ApiKey; @@ -17,8 +17,7 @@ export async function editApiKey(req: NextApiRequest, res: NextApiResponse { res.status(404).json({ message: `apiKey with ID ${safeQuery.data.id} not found and wasn't updated`, error }) }); - } } else { // Reject any other HTTP method than POST res.status(405).json({ message: "Only PATCH Method allowed for updating API keys" }); diff --git a/pages/api/api-keys/[id]/index.ts b/pages/api/api-keys/[id]/index.ts index e7af7b15d0..169e1c121d 100644 --- a/pages/api/api-keys/[id]/index.ts +++ b/pages/api/api-keys/[id]/index.ts @@ -3,7 +3,7 @@ import prisma from "@calcom/prisma"; import { ApiKey } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/queryIdString"; +import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; type ResponseData = { data?: ApiKey; @@ -13,14 +13,11 @@ type ResponseData = { export async function apiKey(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; - if (method === "GET") { const safe = await schemaQueryIdAsString.safeParse(query); - if (safe.success) { + if (method === "GET" && safe.success) { const apiKey = await prisma.apiKey.findUnique({ where: { id: safe.data.id } }); - - if (apiKey) res.status(200).json({ data: apiKey }); if (!apiKey) res.status(404).json({ message: "API key was not found" }); - } + else res.status(200).json({ data: apiKey }); } else { // Reject any other HTTP method than POST res.status(405).json({ message: "Only GET Method allowed" }); diff --git a/pages/api/api-keys/new.ts b/pages/api/api-keys/new.ts index 500c9219c3..4a88584d67 100644 --- a/pages/api/api-keys/new.ts +++ b/pages/api/api-keys/new.ts @@ -13,9 +13,8 @@ type ResponseData = { async function createApiKey(req: NextApiRequest, res: NextApiResponse) { const { body, method } = req; - if (method === "POST") { - const safe = schemaApiKey.safeParse(body); - if (safe.success && safe.data) { + const safe = schemaApiKey.safeParse(body); + if (method === "POST" && safe.success) { const apiKey = await prisma.apiKey .create({ data: { @@ -24,17 +23,9 @@ async function createApiKey(req: NextApiRequest, res: NextApiResponse res.status(201).json({ data: apiKey })) - // .catch((error) => { - // res.status(400).json({ message: "Could not create apiKey", error: error }) - // } - // ) - } + } else { + res.status(404).json({message: "API Key not created"}); + } } else { // Reject any other HTTP method than POST res.status(405).json({ error: "Only POST Method allowed" }); diff --git a/pages/api/bookings/[id]/delete.ts b/pages/api/bookings/[id]/delete.ts new file mode 100644 index 0000000000..1196e505eb --- /dev/null +++ b/pages/api/bookings/[id]/delete.ts @@ -0,0 +1,36 @@ +import prisma from "@calcom/prisma"; + +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + + +type ResponseData = { + message?: string; + error?: unknown; +}; + +export async function booking(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryId.safeParse(query); + if (safe.success) { + if (method === "DELETE") { + // DELETE WILL DELETE THE EVENT TYPE + prisma.booking + .delete({ where: { id: safe.data.id } }) + .then(() => { + // We only remove the booking type from the database if there's an existing resource. + res.status(200).json({ message: `booking-type with id: ${safe.data.id} deleted successfully` }); + }) + .catch((error) => { + // This catches the error thrown by prisma.booking.delete() if the resource is not found. + res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); + }); + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only DELETE Method allowed in /booking-types/[id]/delete endpoint" }); + } + } +} + +export default withValidQueryIdTransformParseInt(booking); diff --git a/pages/api/bookings/[id]/edit.ts b/pages/api/bookings/[id]/edit.ts new file mode 100644 index 0000000000..1fc77f9c25 --- /dev/null +++ b/pages/api/bookings/[id]/edit.ts @@ -0,0 +1,37 @@ +import prisma from "@calcom/prisma"; + +import { Booking } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaBooking, withValidBooking } from "@lib/validations/booking"; +import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: Booking; + message?: string; + error?: unknown; +}; + +export async function editBooking(req: NextApiRequest, res: NextApiResponse) { + const { query, body, method } = req; + const safeQuery = await schemaQueryId.safeParse(query); + const safeBody = await schemaBooking.safeParse(body); + + if (method === "PATCH") { + if (safeQuery.success && safeBody.success) { + await prisma.booking.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }).then(booking => { + res.status(200).json({ data: booking }); + }).catch(error => { + res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + }); + } + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only PATCH Method allowed for updating bookings" }); + } +} + +export default withValidQueryIdTransformParseInt(withValidBooking(editBooking)); diff --git a/pages/api/bookings/[id]/index.ts b/pages/api/bookings/[id]/index.ts new file mode 100644 index 0000000000..11c84ba5c8 --- /dev/null +++ b/pages/api/bookings/[id]/index.ts @@ -0,0 +1,31 @@ +import prisma from "@calcom/prisma"; + +import { Booking } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: Booking; + message?: string; + error?: unknown; +}; + +export async function booking(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryId.safeParse(query); + if (safe.success) { + if (method === "GET") { + const booking = await prisma.booking.findUnique({ where: { id: safe.data.id } }); + + if (booking) res.status(200).json({ data: booking }); + if (!booking) res.status(404).json({ message: "Event type not found" }); + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only GET Method allowed" }); + } + } +} + + +export default withValidQueryIdTransformParseInt(booking); diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts new file mode 100644 index 0000000000..20b9a41a7e --- /dev/null +++ b/pages/api/bookings/index.ts @@ -0,0 +1,19 @@ +import prisma from "@calcom/prisma"; + +import { Booking } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +type ResponseData = { + data?: Booking[]; + error?: unknown; +}; + +export default async function booking(req: NextApiRequest, res: NextApiResponse) { + try { + const bookings = await prisma.booking.findMany(); + res.status(200).json({ data: { ...bookings } }); + } catch (error) { + // FIXME: Add zod for validation/error handling + res.status(400).json({ error: error }); + } +} diff --git a/pages/api/bookings/new.ts b/pages/api/bookings/new.ts new file mode 100644 index 0000000000..296875608f --- /dev/null +++ b/pages/api/bookings/new.ts @@ -0,0 +1,30 @@ +import prisma from "@calcom/prisma"; + +import { Booking } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaBooking, withValidBooking } from "@lib/validations/booking"; + +type ResponseData = { + data?: Booking; + message?: string; + error?: string; +}; + +async function createBooking(req: NextApiRequest, res: NextApiResponse) { + const { body, method } = req; + if (method === "POST") { + const safe = schemaBooking.safeParse(body); + if (safe.success && safe.data) { + await prisma.booking + .create({ data: safe.data }) + .then((booking) => res.status(201).json({ data: booking })) + .catch((error) => res.status(400).json({ message: "Could not create booking type", error: error })); + } + } else { + // Reject any other HTTP method than POST + res.status(405).json({ error: "Only POST Method allowed" }); + } +} + +export default withValidBooking(createBooking); diff --git a/pages/api/event-types/[id]/delete.ts b/pages/api/event-types/[id]/delete.ts index 52f2cd74b7..f6341df094 100644 --- a/pages/api/event-types/[id]/delete.ts +++ b/pages/api/event-types/[id]/delete.ts @@ -2,7 +2,7 @@ import prisma from "@calcom/prisma"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/queryIdTransformParseInt"; +import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { diff --git a/pages/api/event-types/[id]/edit.ts b/pages/api/event-types/[id]/edit.ts index 0194678226..276b0ba34a 100644 --- a/pages/api/event-types/[id]/edit.ts +++ b/pages/api/event-types/[id]/edit.ts @@ -4,7 +4,7 @@ import { EventType } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; import { schemaEventType, withValidEventType } from "@lib/validations/eventType"; -import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/queryIdTransformParseInt"; +import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: EventType; diff --git a/pages/api/event-types/[id]/index.ts b/pages/api/event-types/[id]/index.ts index 1c4bc056fb..44eaa46c77 100644 --- a/pages/api/event-types/[id]/index.ts +++ b/pages/api/event-types/[id]/index.ts @@ -3,7 +3,7 @@ import prisma from "@calcom/prisma"; import { EventType } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/queryIdTransformParseInt"; +import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: EventType; diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 2ea925d76b..534ebf828f 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -5,15 +5,17 @@ import type { NextApiRequest, NextApiResponse } from "next"; type ResponseData = { data?: EventType[]; + message?: string; error?: unknown; }; export default async function eventType(req: NextApiRequest, res: NextApiResponse) { - try { + const { method } = req; + if (method === "GET") { const eventTypes = await prisma.eventType.findMany(); res.status(200).json({ data: { ...eventTypes } }); - } catch (error) { - // FIXME: Add zod for validation/error handling - res.status(400).json({ error: error }); - } + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only GET Method allowed" }); + } } diff --git a/pages/api/teams/[id]/delete.ts b/pages/api/teams/[id]/delete.ts index aee327a197..26a5df4919 100644 --- a/pages/api/teams/[id]/delete.ts +++ b/pages/api/teams/[id]/delete.ts @@ -2,7 +2,7 @@ import prisma from "@calcom/prisma"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/queryIdTransformParseInt"; +import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { diff --git a/pages/api/teams/[id]/edit.ts b/pages/api/teams/[id]/edit.ts index daaf27657a..eb3636aac4 100644 --- a/pages/api/teams/[id]/edit.ts +++ b/pages/api/teams/[id]/edit.ts @@ -4,7 +4,7 @@ import { Team } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; import { schemaTeam, withValidTeam } from "@lib/validations/team"; -import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/queryIdTransformParseInt"; +import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: Team; diff --git a/pages/api/teams/[id]/index.ts b/pages/api/teams/[id]/index.ts index 50a600ca58..d21c33e266 100644 --- a/pages/api/teams/[id]/index.ts +++ b/pages/api/teams/[id]/index.ts @@ -3,7 +3,7 @@ import prisma from "@calcom/prisma"; import { Team } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/queryIdTransformParseInt"; +import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: Team; diff --git a/pages/api/users/[id]/delete.ts b/pages/api/users/[id]/delete.ts index 3c35fd5844..860b684a64 100644 --- a/pages/api/users/[id]/delete.ts +++ b/pages/api/users/[id]/delete.ts @@ -2,7 +2,7 @@ import prisma from "@calcom/prisma"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/queryIdTransformParseInt"; +import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { diff --git a/pages/api/users/[id]/edit.ts b/pages/api/users/[id]/edit.ts index 877cd7f35a..7b26f306f8 100644 --- a/pages/api/users/[id]/edit.ts +++ b/pages/api/users/[id]/edit.ts @@ -4,7 +4,7 @@ import { User } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; import { schemaUser, withValidUser } from "@lib/validations/user"; -import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/queryIdTransformParseInt"; +import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: User; diff --git a/pages/api/users/[id]/index.ts b/pages/api/users/[id]/index.ts index 7b6c991f2b..a5fcf369fa 100644 --- a/pages/api/users/[id]/index.ts +++ b/pages/api/users/[id]/index.ts @@ -3,7 +3,7 @@ import prisma from "@calcom/prisma"; import { User } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/queryIdTransformParseInt"; +import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: User; diff --git a/__tests__/api-keys/[id]/api-key.id.delete.test.ts b/tests/api-keys/[id]/api-key.id.delete.test.ts similarity index 100% rename from __tests__/api-keys/[id]/api-key.id.delete.test.ts rename to tests/api-keys/[id]/api-key.id.delete.test.ts diff --git a/__tests__/api-keys/[id]/api-key.id.edit.test.ts b/tests/api-keys/[id]/api-key.id.edit.test.ts similarity index 69% rename from __tests__/api-keys/[id]/api-key.id.edit.test.ts rename to tests/api-keys/[id]/api-key.id.edit.test.ts index 3d4b4f35dc..c0d2e3631c 100644 --- a/__tests__/api-keys/[id]/api-key.id.edit.test.ts +++ b/tests/api-keys/[id]/api-key.id.edit.test.ts @@ -23,32 +23,32 @@ describe("PATCH /api/api-keys/[id]/edit with valid id and body with note", () => }); }); -// describe("PATCH /api/api-keys/[id]/edit with invalid id returns 404", () => { -// it("returns a message with the specified apiKeys", async () => { -// const { req, res } = createMocks({ -// method: "PATCH", -// query: { -// id: "cl16zg6860000wwylnsgva00a", -// }, -// body: { -// note: "Updated note", -// }, -// }); -// const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.id } }); -// await handleapiKeyEdit(req, res); +describe("PATCH /api/api-keys/[id]/edit with invalid id returns 404", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "PATCH", + query: { + id: "cl16zg6860000wwylnsgva00a", + }, + body: { + note: "Updated note", + }, + }); + const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.id } }); + await handleapiKeyEdit(req, res); -// expect(res._getStatusCode()).toBe(404); -// if (apiKey) apiKey.note = "Updated note"; -// expect(JSON.parse(res._getData())).toStrictEqual({ "error": { -// "clientVersion": "3.10.0", -// "code": "P2025", -// "meta": { -// "cause": "Record to update not found.", -// }, -// }, -// "message": "apiKey with ID cl16zg6860000wwylnsgva00a not found and wasn't updated", }); -// }); -// }); + expect(res._getStatusCode()).toBe(404); + if (apiKey) apiKey.note = "Updated note"; + expect(JSON.parse(res._getData())).toStrictEqual({ "error": { + "clientVersion": "3.10.0", + "code": "P2025", + "meta": { + "cause": "Record to update not found.", + }, + }, + "message": "apiKey with ID cl16zg6860000wwylnsgva00a not found and wasn't updated", }); + }); +}); describe("PATCH /api/api-keys/[id]/edit with valid id and no body returns 200 with an apiKey with no note and default expireAt", () => { it("returns a message with the specified apiKeys", async () => { diff --git a/__tests__/api-keys/[id]/api-key.id.index.test.ts b/tests/api-keys/[id]/api-key.id.index.test.ts similarity index 100% rename from __tests__/api-keys/[id]/api-key.id.index.test.ts rename to tests/api-keys/[id]/api-key.id.index.test.ts diff --git a/tests/api-keys/api-key.index.test.ts b/tests/api-keys/api-key.index.test.ts new file mode 100644 index 0000000000..87e1bd24b5 --- /dev/null +++ b/tests/api-keys/api-key.index.test.ts @@ -0,0 +1,31 @@ +import handleApiKeys from "@api/api-keys"; +import { createMocks } from "node-mocks-http"; + +import prisma from "@calcom/prisma"; +import {stringifyISODate} from "@lib/utils/stringifyISODate"; + +describe("GET /api/api-keys without any params", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "GET", + query: {}, + }); + let apiKeys = await prisma.apiKey.findMany(); + await handleApiKeys(req, res); + + expect(res._getStatusCode()).toBe(200); + apiKeys = apiKeys.map(apiKey => (apiKey = {...apiKey, createdAt: stringifyISODate(apiKey?.createdAt), expiresAt: stringifyISODate(apiKey?.expiresAt)})); + expect(JSON.parse(res._getData())).toStrictEqual(JSON.parse(JSON.stringify({ data: {...apiKeys} }))); + }); +}); + +describe("POST /api/api-keys/ fails, only GET allowed", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + }); + await handleApiKeys(req, res); + expect(res._getStatusCode()).toBe(405); + expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); + }); +}); diff --git a/tests/api-keys/api-key.new.test.ts b/tests/api-keys/api-key.new.test.ts new file mode 100644 index 0000000000..9507bdbd71 --- /dev/null +++ b/tests/api-keys/api-key.new.test.ts @@ -0,0 +1,71 @@ +import handleNewApiKey from "@api/api-keys/new"; +import { createMocks } from "node-mocks-http"; + +describe("POST /api/api-keys/new with a note", () => { + it("returns a 201, and the created api key", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + body: { + note: "Updated note", + }, + }); + await handleNewApiKey(req, res); + + expect(res._getStatusCode()).toBe(201); + expect(JSON.parse(res._getData()).data.note).toStrictEqual("Updated note"); + }); +}); + +describe("POST /api/api-keys/new with a slug param", () => { + it("returns error 400, and the details about invalid slug body param", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + body: { + note: "Updated note", + slug: "slug", + }, + }); + await handleNewApiKey(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(JSON.parse(res._getData())).toStrictEqual( + [{"code": "unrecognized_keys", "keys": ["slug"], "message": "Unrecognized key(s) in object: 'slug'", "path": []}] + ); + }); +}); + + +describe("GET /api/api-keys/new fails, only POST allowed", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "GET", // This POST method is not allowed + }); + await handleNewApiKey(req, res); + + expect(res._getStatusCode()).toBe(405); + expect(JSON.parse(res._getData())).toStrictEqual({ error: "Only POST Method allowed" }); + }); +}); + + +// FIXME: test 405 when prisma fails look for how to test prisma errors +describe("GET /api/api-keys/new fails, only POST allowed", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + body: { + nonExistentParam: true + // note: '123', + // slug: 12, + }, + }); + await handleNewApiKey(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(JSON.parse(res._getData())).toStrictEqual([{ + "code": "unrecognized_keys", + "keys": ["nonExistentParam"], + "message": "Unrecognized key(s) in object: 'nonExistentParam'", "path": [] + }]); + }); +}); \ No newline at end of file diff --git a/__tests__/event-types/[id]/event-type.id.edit.test.ts b/tests/event-types/[id]/event-type.id.edit.test.ts similarity index 100% rename from __tests__/event-types/[id]/event-type.id.edit.test.ts rename to tests/event-types/[id]/event-type.id.edit.test.ts diff --git a/__tests__/event-types/[id]/event-type.id.index.test.ts b/tests/event-types/[id]/event-type.id.index.test.ts similarity index 100% rename from __tests__/event-types/[id]/event-type.id.index.test.ts rename to tests/event-types/[id]/event-type.id.index.test.ts diff --git a/tests/event-types/event-type.index.test.ts b/tests/event-types/event-type.index.test.ts new file mode 100644 index 0000000000..668d88a9d7 --- /dev/null +++ b/tests/event-types/event-type.index.test.ts @@ -0,0 +1,31 @@ +import handleApiKeys from "@api/event-types"; +import { createMocks } from "node-mocks-http"; + +import prisma from "@calcom/prisma"; +// import {stringifyISODate} from "@lib/utils/stringifyISODate"; + +describe("GET /api/event-types without any params", () => { + it("returns a message with the specified eventTypes", async () => { + const { req, res } = createMocks({ + method: "GET", + query: {}, + }); + const eventTypes = await prisma.eventType.findMany(); + await handleApiKeys(req, res); + + expect(res._getStatusCode()).toBe(200); + // eventTypes = eventTypes.map(eventType => (eventType = {...eventType, createdAt: stringifyISODate(eventType?.createdAt), expiresAt: stringifyISODate(eventType?.expiresAt)})); + expect(JSON.parse(res._getData())).toStrictEqual(JSON.parse(JSON.stringify({ data: {...eventTypes} }))); + }); +}); + +describe("POST /api/event-types/ fails, only GET allowed", () => { + it("returns a message with the specified eventTypes", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + }); + await handleApiKeys(req, res); + expect(res._getStatusCode()).toBe(405); + expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); + }); +}); diff --git a/tests/event-types/event-type.new.test.ts b/tests/event-types/event-type.new.test.ts new file mode 100644 index 0000000000..01dab107a9 --- /dev/null +++ b/tests/event-types/event-type.new.test.ts @@ -0,0 +1,68 @@ +import handleNewApiKey from "@api/api-keys/new"; +import { createMocks } from "node-mocks-http"; + +describe("POST /api/api-keys/new with a note", () => { + it("returns a 201, and the created api key", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + body: { + note: "Updated note", + }, + }); + await handleNewApiKey(req, res); + + expect(res._getStatusCode()).toBe(201); + expect(JSON.parse(res._getData()).data.note).toStrictEqual("Updated note"); + }); +}); + + +describe("POST /api/api-keys/new with a slug param", () => { + it("returns error 400, and the details about invalid slug body param", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + body: { + note: "Updated note", + slug: "slug", + }, + }); + await handleNewApiKey(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(JSON.parse(res._getData())).toStrictEqual( + [{"code": "unrecognized_keys", "keys": ["slug"], "message": "Unrecognized key(s) in object: 'slug'", "path": []}] + ); + }); +}); + + +describe("GET /api/api-keys/new fails, only POST allowed", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "GET", // This POST method is not allowed + }); + await handleNewApiKey(req, res); + + expect(res._getStatusCode()).toBe(405); + expect(JSON.parse(res._getData())).toStrictEqual({ error: "Only POST Method allowed" }); + }); +}); + + +// FIXME: test 405 when prisma fails look for how to test prisma errors +// describe("GET /api/api-keys/new fails, only POST allowed", () => { +// it("returns a message with the specified apiKeys", async () => { +// const { req, res } = createMocks({ +// method: "POST", // This POST method is not allowed +// body: { +// fail: true +// // note: '123', +// // slug: 12, +// }, +// }); +// await handleNewApiKey(req, res); + +// expect(res._getStatusCode()).toBe(400); +// expect(JSON.parse(res._getData())).toStrictEqual({ error: "Only POST Method allowed" }); +// }); +// }); \ No newline at end of file diff --git a/__tests__/teams/[id]/team.id.test.edit.ts b/tests/teams/[id]/team.id.test.edit.ts similarity index 100% rename from __tests__/teams/[id]/team.id.test.edit.ts rename to tests/teams/[id]/team.id.test.edit.ts diff --git a/__tests__/teams/[id]/team.id.test.index.ts b/tests/teams/[id]/team.id.test.index.ts similarity index 100% rename from __tests__/teams/[id]/team.id.test.index.ts rename to tests/teams/[id]/team.id.test.index.ts diff --git a/__tests__/users/[id]/user.id.edit.test.ts b/tests/users/[id]/user.id.edit.test.ts similarity index 100% rename from __tests__/users/[id]/user.id.edit.test.ts rename to tests/users/[id]/user.id.edit.test.ts diff --git a/__tests__/users/[id]/user.id.index.test.ts b/tests/users/[id]/user.id.index.test.ts similarity index 100% rename from __tests__/users/[id]/user.id.index.test.ts rename to tests/users/[id]/user.id.index.test.ts From 936572e7e149f3fd1c1a36bdd01a01e78cdde656 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 27 Mar 2022 00:58:22 +0100 Subject: [PATCH 031/658] feat: adds availabilitesi and attendees endpoints, some cleanup less try/catch more if/else --- .gitignore | 1 + lib/utils/stringifyISODate.ts | 3 +- lib/validations/apiKey.ts | 3 +- lib/validations/attendee.ts | 20 ++++ lib/validations/availability.ts | 65 +++++++++++++ lib/validations/booking-reference.ts | 65 +++++++++++++ lib/validations/credential.ts | 65 +++++++++++++ lib/validations/daily-event-reference.ts | 65 +++++++++++++ lib/validations/destination-calendar.ts | 65 +++++++++++++ lib/validations/membership.ts | 65 +++++++++++++ lib/validations/payment.ts | 65 +++++++++++++ lib/validations/schedule.ts | 65 +++++++++++++ lib/validations/selected-calendar.ts | 65 +++++++++++++ .../shared/queryIdTransformParseInt.ts | 6 +- lib/validations/webhook.ts | 65 +++++++++++++ pages/api/api-keys/[id]/delete.ts | 7 +- pages/api/api-keys/[id]/edit.ts | 6 +- pages/api/api-keys/[id]/index.ts | 6 +- pages/api/api-keys/index.ts | 12 +-- pages/api/api-keys/new.ts | 22 ++--- pages/api/attendees/[id]/delete.ts | 35 +++++++ pages/api/attendees/[id]/edit.ts | 33 +++++++ pages/api/attendees/[id]/index.ts | 27 ++++++ pages/api/attendees/index.ts | 19 ++++ pages/api/attendees/new.ts | 27 ++++++ pages/api/availabilities/[id]/delete.ts | 27 ++++++ pages/api/availabilities/[id]/edit.ts | 33 +++++++ pages/api/availabilities/[id]/index.ts | 28 ++++++ pages/api/availabilities/index.ts | 19 ++++ pages/api/availabilities/new.ts | 30 ++++++ pages/api/bookings/[id]/delete.ts | 37 ++++---- pages/api/bookings/[id]/edit.ts | 4 +- pages/api/bookings/[id]/index.ts | 21 ++--- pages/api/event-types/[id]/delete.ts | 36 ++++---- pages/api/event-types/[id]/edit.ts | 4 +- pages/api/event-types/[id]/index.ts | 21 ++--- pages/api/teams/[id]/delete.ts | 36 ++++---- pages/api/teams/[id]/edit.ts | 4 +- pages/api/teams/[id]/index.ts | 21 ++--- pages/api/users/[id]/delete.ts | 36 ++++---- pages/api/users/[id]/edit.ts | 4 +- pages/api/users/[id]/index.ts | 20 ++-- tests/bookings/[id]/booking.id.edit.test.ts | 92 +++++++++++++++++++ tests/bookings/[id]/booking.id.index.test.ts | 85 +++++++++++++++++ tests/bookings/booking.index.test.ts | 31 +++++++ tests/bookings/booking.new.test.ts | 71 ++++++++++++++ ...m.id.test.edit.ts => team.id.edit.test.ts} | 0 ...id.test.index.ts => team.id.index.test.ts} | 0 48 files changed, 1365 insertions(+), 172 deletions(-) create mode 100644 lib/validations/attendee.ts create mode 100644 lib/validations/availability.ts create mode 100644 lib/validations/booking-reference.ts create mode 100644 lib/validations/credential.ts create mode 100644 lib/validations/daily-event-reference.ts create mode 100644 lib/validations/destination-calendar.ts create mode 100644 lib/validations/membership.ts create mode 100644 lib/validations/payment.ts create mode 100644 lib/validations/schedule.ts create mode 100644 lib/validations/selected-calendar.ts create mode 100644 lib/validations/webhook.ts create mode 100644 pages/api/attendees/[id]/delete.ts create mode 100644 pages/api/attendees/[id]/edit.ts create mode 100644 pages/api/attendees/[id]/index.ts create mode 100644 pages/api/attendees/index.ts create mode 100644 pages/api/attendees/new.ts create mode 100644 pages/api/availabilities/[id]/delete.ts create mode 100644 pages/api/availabilities/[id]/edit.ts create mode 100644 pages/api/availabilities/[id]/index.ts create mode 100644 pages/api/availabilities/index.ts create mode 100644 pages/api/availabilities/new.ts create mode 100644 tests/bookings/[id]/booking.id.edit.test.ts create mode 100644 tests/bookings/[id]/booking.id.index.test.ts create mode 100644 tests/bookings/booking.index.test.ts create mode 100644 tests/bookings/booking.new.test.ts rename tests/teams/[id]/{team.id.test.edit.ts => team.id.edit.test.ts} (100%) rename tests/teams/[id]/{team.id.test.index.ts => team.id.index.test.ts} (100%) diff --git a/.gitignore b/.gitignore index a50ad511f9..b04bde734a 100644 --- a/.gitignore +++ b/.gitignore @@ -45,6 +45,7 @@ yarn-error.log* .idea ### VisualStudioCode template +.vscode/ .vscode/* !.vscode/settings.json !.vscode/tasks.json diff --git a/lib/utils/stringifyISODate.ts b/lib/utils/stringifyISODate.ts index b9317853ad..bb2ec71339 100644 --- a/lib/utils/stringifyISODate.ts +++ b/lib/utils/stringifyISODate.ts @@ -1,8 +1,7 @@ export const stringifyISODate = (date: Date|undefined): string => { return `${date?.toISOString()}` } - +// FIXME: debug this, supposed to take an array/object and auto strinfy date-like values export const autoStringifyDateValues = ([key, value]: [string, unknown]): [string, unknown] => { - console.log(key,value) return [key, typeof value === "object" && value instanceof Date ? stringifyISODate(value) : value] } \ No newline at end of file diff --git a/lib/validations/apiKey.ts b/lib/validations/apiKey.ts index a8d89d78f3..044e3768f3 100644 --- a/lib/validations/apiKey.ts +++ b/lib/validations/apiKey.ts @@ -9,7 +9,8 @@ const schemaApiKey = z expiresAt: z.date().optional(), // default is 30 days note: z.string().min(1).optional(), }) - .strict(); // Adding strict so that we can disallow passing in extra fields + .strict(); + const withValidApiKey = withValidation({ schema: schemaApiKey, type: "Zod", diff --git a/lib/validations/attendee.ts b/lib/validations/attendee.ts new file mode 100644 index 0000000000..290b337779 --- /dev/null +++ b/lib/validations/attendee.ts @@ -0,0 +1,20 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +const schemaAttendee = z + .object({ + id: z.number(), + email: z.string().min(3), + name: z.string().min(3).email(), + timeZone: z.string().default("Europe/London"), + locale: z.string().optional(), + bookingId: z.number(), + }) + .strict(); +const withValidAttendee = withValidation({ + schema: schemaAttendee, + type: "Zod", + mode: "body", +}); + +export { schemaAttendee, withValidAttendee }; diff --git a/lib/validations/availability.ts b/lib/validations/availability.ts new file mode 100644 index 0000000000..b9ecf2fe20 --- /dev/null +++ b/lib/validations/availability.ts @@ -0,0 +1,65 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +const schemaAvailability = z + .object({ + uid: z.string().min(3), + title: z.string().min(3), + description: z.string().min(3).optional(), + startTime: z.date().or(z.string()), + endTime: z.date(), + location: z.string().min(3).optional(), + createdAt: z.date().or(z.string()), + updatedAt: z.date(), + confirmed: z.boolean().default(true), + rejected: z.boolean().default(false), + paid: z.boolean().default(false), + + // bufferTime: z.number().default(0), + // // attendees: z.array((schemaSchedule)).optional(), + + // startTime: z.string().min(3), + // endTime: z.string().min(3), + // email: z.string().email(), // max is a full day. + // emailVerified: z.date().optional(), + // password: z.string().optional(), + // bio: z.string().min(3).optional(), + // avatar: z.string().optional(), + // timeZone: z.string().default("Europe/London"), + // weekStart: z.string().default("Sunday"), + // bufferTime: z.number().default(0), + // theme: z.string().optional(), + // trialEndsAt: z.date().optional(), + // eventTypes: z.array((schemaEventType)).optional(), + // // credentials: z.array((schemaCredentials)).optional(), + // // teams: z.array((schemaMembership)).optional(), + // // bookings: z.array((schemaAvailability)).optional(), + // // schedules: z.array((schemaSchedule)).optional(), + // defaultScheduleId: z.number().optional(), + // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), + // completedOnboarding: z.boolean().default(false), + // locale: z.string().optional(), + // timeFormat: z.number().optional().default(12), + // twoFactorEnabled: z.boolean().default(false), + // twoFactorSecret: z.string().optional(), + // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), + // identityProviderId: z.string().optional(), + // // availavility: z.array((schemaAvailavility)).optional(), + // invitedTo: z.number().optional(), + // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), + // // webhooks: z.array((schemaWebhook)).optional(), + // brandColor: z.string().default("#292929"), + // darkBrandColor: z.string().default("#fafafa"), + // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here + // away: z.boolean().default(false), + // metadata: z.object({}).optional(), + // verified: z.boolean().default(false), + }) + .strict(); // Adding strict so that we can disallow passing in extra fields +const withValidAvailability = withValidation({ + schema: schemaAvailability, + type: "Zod", + mode: "body", +}); + +export { schemaAvailability, withValidAvailability }; diff --git a/lib/validations/booking-reference.ts b/lib/validations/booking-reference.ts new file mode 100644 index 0000000000..fb50c9c9ad --- /dev/null +++ b/lib/validations/booking-reference.ts @@ -0,0 +1,65 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +const schemaBooking = z + .object({ + uid: z.string().min(3), + title: z.string().min(3), + description: z.string().min(3).optional(), + startTime: z.date().or(z.string()), + endTime: z.date(), + location: z.string().min(3).optional(), + createdAt: z.date().or(z.string()), + updatedAt: z.date(), + confirmed: z.boolean().default(true), + rejected: z.boolean().default(false), + paid: z.boolean().default(false), + + // bufferTime: z.number().default(0), + // // attendees: z.array((schemaSchedule)).optional(), + + // startTime: z.string().min(3), + // endTime: z.string().min(3), + // email: z.string().email(), // max is a full day. + // emailVerified: z.date().optional(), + // password: z.string().optional(), + // bio: z.string().min(3).optional(), + // avatar: z.string().optional(), + // timeZone: z.string().default("Europe/London"), + // weekStart: z.string().default("Sunday"), + // bufferTime: z.number().default(0), + // theme: z.string().optional(), + // trialEndsAt: z.date().optional(), + // eventTypes: z.array((schemaEventType)).optional(), + // // credentials: z.array((schemaCredentials)).optional(), + // // teams: z.array((schemaMembership)).optional(), + // // bookings: z.array((schemaBooking)).optional(), + // // schedules: z.array((schemaSchedule)).optional(), + // defaultScheduleId: z.number().optional(), + // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), + // completedOnboarding: z.boolean().default(false), + // locale: z.string().optional(), + // timeFormat: z.number().optional().default(12), + // twoFactorEnabled: z.boolean().default(false), + // twoFactorSecret: z.string().optional(), + // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), + // identityProviderId: z.string().optional(), + // // availavility: z.array((schemaAvailavility)).optional(), + // invitedTo: z.number().optional(), + // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), + // // webhooks: z.array((schemaWebhook)).optional(), + // brandColor: z.string().default("#292929"), + // darkBrandColor: z.string().default("#fafafa"), + // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here + // away: z.boolean().default(false), + // metadata: z.object({}).optional(), + // verified: z.boolean().default(false), + }) + .strict(); // Adding strict so that we can disallow passing in extra fields +const withValidBooking = withValidation({ + schema: schemaBooking, + type: "Zod", + mode: "body", +}); + +export { schemaBooking, withValidBooking }; diff --git a/lib/validations/credential.ts b/lib/validations/credential.ts new file mode 100644 index 0000000000..fb50c9c9ad --- /dev/null +++ b/lib/validations/credential.ts @@ -0,0 +1,65 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +const schemaBooking = z + .object({ + uid: z.string().min(3), + title: z.string().min(3), + description: z.string().min(3).optional(), + startTime: z.date().or(z.string()), + endTime: z.date(), + location: z.string().min(3).optional(), + createdAt: z.date().or(z.string()), + updatedAt: z.date(), + confirmed: z.boolean().default(true), + rejected: z.boolean().default(false), + paid: z.boolean().default(false), + + // bufferTime: z.number().default(0), + // // attendees: z.array((schemaSchedule)).optional(), + + // startTime: z.string().min(3), + // endTime: z.string().min(3), + // email: z.string().email(), // max is a full day. + // emailVerified: z.date().optional(), + // password: z.string().optional(), + // bio: z.string().min(3).optional(), + // avatar: z.string().optional(), + // timeZone: z.string().default("Europe/London"), + // weekStart: z.string().default("Sunday"), + // bufferTime: z.number().default(0), + // theme: z.string().optional(), + // trialEndsAt: z.date().optional(), + // eventTypes: z.array((schemaEventType)).optional(), + // // credentials: z.array((schemaCredentials)).optional(), + // // teams: z.array((schemaMembership)).optional(), + // // bookings: z.array((schemaBooking)).optional(), + // // schedules: z.array((schemaSchedule)).optional(), + // defaultScheduleId: z.number().optional(), + // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), + // completedOnboarding: z.boolean().default(false), + // locale: z.string().optional(), + // timeFormat: z.number().optional().default(12), + // twoFactorEnabled: z.boolean().default(false), + // twoFactorSecret: z.string().optional(), + // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), + // identityProviderId: z.string().optional(), + // // availavility: z.array((schemaAvailavility)).optional(), + // invitedTo: z.number().optional(), + // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), + // // webhooks: z.array((schemaWebhook)).optional(), + // brandColor: z.string().default("#292929"), + // darkBrandColor: z.string().default("#fafafa"), + // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here + // away: z.boolean().default(false), + // metadata: z.object({}).optional(), + // verified: z.boolean().default(false), + }) + .strict(); // Adding strict so that we can disallow passing in extra fields +const withValidBooking = withValidation({ + schema: schemaBooking, + type: "Zod", + mode: "body", +}); + +export { schemaBooking, withValidBooking }; diff --git a/lib/validations/daily-event-reference.ts b/lib/validations/daily-event-reference.ts new file mode 100644 index 0000000000..fb50c9c9ad --- /dev/null +++ b/lib/validations/daily-event-reference.ts @@ -0,0 +1,65 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +const schemaBooking = z + .object({ + uid: z.string().min(3), + title: z.string().min(3), + description: z.string().min(3).optional(), + startTime: z.date().or(z.string()), + endTime: z.date(), + location: z.string().min(3).optional(), + createdAt: z.date().or(z.string()), + updatedAt: z.date(), + confirmed: z.boolean().default(true), + rejected: z.boolean().default(false), + paid: z.boolean().default(false), + + // bufferTime: z.number().default(0), + // // attendees: z.array((schemaSchedule)).optional(), + + // startTime: z.string().min(3), + // endTime: z.string().min(3), + // email: z.string().email(), // max is a full day. + // emailVerified: z.date().optional(), + // password: z.string().optional(), + // bio: z.string().min(3).optional(), + // avatar: z.string().optional(), + // timeZone: z.string().default("Europe/London"), + // weekStart: z.string().default("Sunday"), + // bufferTime: z.number().default(0), + // theme: z.string().optional(), + // trialEndsAt: z.date().optional(), + // eventTypes: z.array((schemaEventType)).optional(), + // // credentials: z.array((schemaCredentials)).optional(), + // // teams: z.array((schemaMembership)).optional(), + // // bookings: z.array((schemaBooking)).optional(), + // // schedules: z.array((schemaSchedule)).optional(), + // defaultScheduleId: z.number().optional(), + // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), + // completedOnboarding: z.boolean().default(false), + // locale: z.string().optional(), + // timeFormat: z.number().optional().default(12), + // twoFactorEnabled: z.boolean().default(false), + // twoFactorSecret: z.string().optional(), + // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), + // identityProviderId: z.string().optional(), + // // availavility: z.array((schemaAvailavility)).optional(), + // invitedTo: z.number().optional(), + // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), + // // webhooks: z.array((schemaWebhook)).optional(), + // brandColor: z.string().default("#292929"), + // darkBrandColor: z.string().default("#fafafa"), + // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here + // away: z.boolean().default(false), + // metadata: z.object({}).optional(), + // verified: z.boolean().default(false), + }) + .strict(); // Adding strict so that we can disallow passing in extra fields +const withValidBooking = withValidation({ + schema: schemaBooking, + type: "Zod", + mode: "body", +}); + +export { schemaBooking, withValidBooking }; diff --git a/lib/validations/destination-calendar.ts b/lib/validations/destination-calendar.ts new file mode 100644 index 0000000000..fb50c9c9ad --- /dev/null +++ b/lib/validations/destination-calendar.ts @@ -0,0 +1,65 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +const schemaBooking = z + .object({ + uid: z.string().min(3), + title: z.string().min(3), + description: z.string().min(3).optional(), + startTime: z.date().or(z.string()), + endTime: z.date(), + location: z.string().min(3).optional(), + createdAt: z.date().or(z.string()), + updatedAt: z.date(), + confirmed: z.boolean().default(true), + rejected: z.boolean().default(false), + paid: z.boolean().default(false), + + // bufferTime: z.number().default(0), + // // attendees: z.array((schemaSchedule)).optional(), + + // startTime: z.string().min(3), + // endTime: z.string().min(3), + // email: z.string().email(), // max is a full day. + // emailVerified: z.date().optional(), + // password: z.string().optional(), + // bio: z.string().min(3).optional(), + // avatar: z.string().optional(), + // timeZone: z.string().default("Europe/London"), + // weekStart: z.string().default("Sunday"), + // bufferTime: z.number().default(0), + // theme: z.string().optional(), + // trialEndsAt: z.date().optional(), + // eventTypes: z.array((schemaEventType)).optional(), + // // credentials: z.array((schemaCredentials)).optional(), + // // teams: z.array((schemaMembership)).optional(), + // // bookings: z.array((schemaBooking)).optional(), + // // schedules: z.array((schemaSchedule)).optional(), + // defaultScheduleId: z.number().optional(), + // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), + // completedOnboarding: z.boolean().default(false), + // locale: z.string().optional(), + // timeFormat: z.number().optional().default(12), + // twoFactorEnabled: z.boolean().default(false), + // twoFactorSecret: z.string().optional(), + // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), + // identityProviderId: z.string().optional(), + // // availavility: z.array((schemaAvailavility)).optional(), + // invitedTo: z.number().optional(), + // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), + // // webhooks: z.array((schemaWebhook)).optional(), + // brandColor: z.string().default("#292929"), + // darkBrandColor: z.string().default("#fafafa"), + // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here + // away: z.boolean().default(false), + // metadata: z.object({}).optional(), + // verified: z.boolean().default(false), + }) + .strict(); // Adding strict so that we can disallow passing in extra fields +const withValidBooking = withValidation({ + schema: schemaBooking, + type: "Zod", + mode: "body", +}); + +export { schemaBooking, withValidBooking }; diff --git a/lib/validations/membership.ts b/lib/validations/membership.ts new file mode 100644 index 0000000000..fb50c9c9ad --- /dev/null +++ b/lib/validations/membership.ts @@ -0,0 +1,65 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +const schemaBooking = z + .object({ + uid: z.string().min(3), + title: z.string().min(3), + description: z.string().min(3).optional(), + startTime: z.date().or(z.string()), + endTime: z.date(), + location: z.string().min(3).optional(), + createdAt: z.date().or(z.string()), + updatedAt: z.date(), + confirmed: z.boolean().default(true), + rejected: z.boolean().default(false), + paid: z.boolean().default(false), + + // bufferTime: z.number().default(0), + // // attendees: z.array((schemaSchedule)).optional(), + + // startTime: z.string().min(3), + // endTime: z.string().min(3), + // email: z.string().email(), // max is a full day. + // emailVerified: z.date().optional(), + // password: z.string().optional(), + // bio: z.string().min(3).optional(), + // avatar: z.string().optional(), + // timeZone: z.string().default("Europe/London"), + // weekStart: z.string().default("Sunday"), + // bufferTime: z.number().default(0), + // theme: z.string().optional(), + // trialEndsAt: z.date().optional(), + // eventTypes: z.array((schemaEventType)).optional(), + // // credentials: z.array((schemaCredentials)).optional(), + // // teams: z.array((schemaMembership)).optional(), + // // bookings: z.array((schemaBooking)).optional(), + // // schedules: z.array((schemaSchedule)).optional(), + // defaultScheduleId: z.number().optional(), + // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), + // completedOnboarding: z.boolean().default(false), + // locale: z.string().optional(), + // timeFormat: z.number().optional().default(12), + // twoFactorEnabled: z.boolean().default(false), + // twoFactorSecret: z.string().optional(), + // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), + // identityProviderId: z.string().optional(), + // // availavility: z.array((schemaAvailavility)).optional(), + // invitedTo: z.number().optional(), + // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), + // // webhooks: z.array((schemaWebhook)).optional(), + // brandColor: z.string().default("#292929"), + // darkBrandColor: z.string().default("#fafafa"), + // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here + // away: z.boolean().default(false), + // metadata: z.object({}).optional(), + // verified: z.boolean().default(false), + }) + .strict(); // Adding strict so that we can disallow passing in extra fields +const withValidBooking = withValidation({ + schema: schemaBooking, + type: "Zod", + mode: "body", +}); + +export { schemaBooking, withValidBooking }; diff --git a/lib/validations/payment.ts b/lib/validations/payment.ts new file mode 100644 index 0000000000..fb50c9c9ad --- /dev/null +++ b/lib/validations/payment.ts @@ -0,0 +1,65 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +const schemaBooking = z + .object({ + uid: z.string().min(3), + title: z.string().min(3), + description: z.string().min(3).optional(), + startTime: z.date().or(z.string()), + endTime: z.date(), + location: z.string().min(3).optional(), + createdAt: z.date().or(z.string()), + updatedAt: z.date(), + confirmed: z.boolean().default(true), + rejected: z.boolean().default(false), + paid: z.boolean().default(false), + + // bufferTime: z.number().default(0), + // // attendees: z.array((schemaSchedule)).optional(), + + // startTime: z.string().min(3), + // endTime: z.string().min(3), + // email: z.string().email(), // max is a full day. + // emailVerified: z.date().optional(), + // password: z.string().optional(), + // bio: z.string().min(3).optional(), + // avatar: z.string().optional(), + // timeZone: z.string().default("Europe/London"), + // weekStart: z.string().default("Sunday"), + // bufferTime: z.number().default(0), + // theme: z.string().optional(), + // trialEndsAt: z.date().optional(), + // eventTypes: z.array((schemaEventType)).optional(), + // // credentials: z.array((schemaCredentials)).optional(), + // // teams: z.array((schemaMembership)).optional(), + // // bookings: z.array((schemaBooking)).optional(), + // // schedules: z.array((schemaSchedule)).optional(), + // defaultScheduleId: z.number().optional(), + // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), + // completedOnboarding: z.boolean().default(false), + // locale: z.string().optional(), + // timeFormat: z.number().optional().default(12), + // twoFactorEnabled: z.boolean().default(false), + // twoFactorSecret: z.string().optional(), + // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), + // identityProviderId: z.string().optional(), + // // availavility: z.array((schemaAvailavility)).optional(), + // invitedTo: z.number().optional(), + // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), + // // webhooks: z.array((schemaWebhook)).optional(), + // brandColor: z.string().default("#292929"), + // darkBrandColor: z.string().default("#fafafa"), + // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here + // away: z.boolean().default(false), + // metadata: z.object({}).optional(), + // verified: z.boolean().default(false), + }) + .strict(); // Adding strict so that we can disallow passing in extra fields +const withValidBooking = withValidation({ + schema: schemaBooking, + type: "Zod", + mode: "body", +}); + +export { schemaBooking, withValidBooking }; diff --git a/lib/validations/schedule.ts b/lib/validations/schedule.ts new file mode 100644 index 0000000000..fb50c9c9ad --- /dev/null +++ b/lib/validations/schedule.ts @@ -0,0 +1,65 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +const schemaBooking = z + .object({ + uid: z.string().min(3), + title: z.string().min(3), + description: z.string().min(3).optional(), + startTime: z.date().or(z.string()), + endTime: z.date(), + location: z.string().min(3).optional(), + createdAt: z.date().or(z.string()), + updatedAt: z.date(), + confirmed: z.boolean().default(true), + rejected: z.boolean().default(false), + paid: z.boolean().default(false), + + // bufferTime: z.number().default(0), + // // attendees: z.array((schemaSchedule)).optional(), + + // startTime: z.string().min(3), + // endTime: z.string().min(3), + // email: z.string().email(), // max is a full day. + // emailVerified: z.date().optional(), + // password: z.string().optional(), + // bio: z.string().min(3).optional(), + // avatar: z.string().optional(), + // timeZone: z.string().default("Europe/London"), + // weekStart: z.string().default("Sunday"), + // bufferTime: z.number().default(0), + // theme: z.string().optional(), + // trialEndsAt: z.date().optional(), + // eventTypes: z.array((schemaEventType)).optional(), + // // credentials: z.array((schemaCredentials)).optional(), + // // teams: z.array((schemaMembership)).optional(), + // // bookings: z.array((schemaBooking)).optional(), + // // schedules: z.array((schemaSchedule)).optional(), + // defaultScheduleId: z.number().optional(), + // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), + // completedOnboarding: z.boolean().default(false), + // locale: z.string().optional(), + // timeFormat: z.number().optional().default(12), + // twoFactorEnabled: z.boolean().default(false), + // twoFactorSecret: z.string().optional(), + // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), + // identityProviderId: z.string().optional(), + // // availavility: z.array((schemaAvailavility)).optional(), + // invitedTo: z.number().optional(), + // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), + // // webhooks: z.array((schemaWebhook)).optional(), + // brandColor: z.string().default("#292929"), + // darkBrandColor: z.string().default("#fafafa"), + // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here + // away: z.boolean().default(false), + // metadata: z.object({}).optional(), + // verified: z.boolean().default(false), + }) + .strict(); // Adding strict so that we can disallow passing in extra fields +const withValidBooking = withValidation({ + schema: schemaBooking, + type: "Zod", + mode: "body", +}); + +export { schemaBooking, withValidBooking }; diff --git a/lib/validations/selected-calendar.ts b/lib/validations/selected-calendar.ts new file mode 100644 index 0000000000..fb50c9c9ad --- /dev/null +++ b/lib/validations/selected-calendar.ts @@ -0,0 +1,65 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +const schemaBooking = z + .object({ + uid: z.string().min(3), + title: z.string().min(3), + description: z.string().min(3).optional(), + startTime: z.date().or(z.string()), + endTime: z.date(), + location: z.string().min(3).optional(), + createdAt: z.date().or(z.string()), + updatedAt: z.date(), + confirmed: z.boolean().default(true), + rejected: z.boolean().default(false), + paid: z.boolean().default(false), + + // bufferTime: z.number().default(0), + // // attendees: z.array((schemaSchedule)).optional(), + + // startTime: z.string().min(3), + // endTime: z.string().min(3), + // email: z.string().email(), // max is a full day. + // emailVerified: z.date().optional(), + // password: z.string().optional(), + // bio: z.string().min(3).optional(), + // avatar: z.string().optional(), + // timeZone: z.string().default("Europe/London"), + // weekStart: z.string().default("Sunday"), + // bufferTime: z.number().default(0), + // theme: z.string().optional(), + // trialEndsAt: z.date().optional(), + // eventTypes: z.array((schemaEventType)).optional(), + // // credentials: z.array((schemaCredentials)).optional(), + // // teams: z.array((schemaMembership)).optional(), + // // bookings: z.array((schemaBooking)).optional(), + // // schedules: z.array((schemaSchedule)).optional(), + // defaultScheduleId: z.number().optional(), + // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), + // completedOnboarding: z.boolean().default(false), + // locale: z.string().optional(), + // timeFormat: z.number().optional().default(12), + // twoFactorEnabled: z.boolean().default(false), + // twoFactorSecret: z.string().optional(), + // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), + // identityProviderId: z.string().optional(), + // // availavility: z.array((schemaAvailavility)).optional(), + // invitedTo: z.number().optional(), + // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), + // // webhooks: z.array((schemaWebhook)).optional(), + // brandColor: z.string().default("#292929"), + // darkBrandColor: z.string().default("#fafafa"), + // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here + // away: z.boolean().default(false), + // metadata: z.object({}).optional(), + // verified: z.boolean().default(false), + }) + .strict(); // Adding strict so that we can disallow passing in extra fields +const withValidBooking = withValidation({ + schema: schemaBooking, + type: "Zod", + mode: "body", +}); + +export { schemaBooking, withValidBooking }; diff --git a/lib/validations/shared/queryIdTransformParseInt.ts b/lib/validations/shared/queryIdTransformParseInt.ts index f99ea64e18..d185d1a255 100644 --- a/lib/validations/shared/queryIdTransformParseInt.ts +++ b/lib/validations/shared/queryIdTransformParseInt.ts @@ -3,7 +3,7 @@ import { z } from "zod"; // Extracted out as utility function so can be reused // at different endpoints that require this validation. -const schemaQueryId = z +const schemaQueryIdParseInt = z .object({ // since nextjs parses query params as strings, // we need to cast them to numbers using z.transform() and parseInt() @@ -15,9 +15,9 @@ const schemaQueryId = z .strict(); const withValidQueryIdTransformParseInt = withValidation({ - schema: schemaQueryId, + schema: schemaQueryIdParseInt, type: "Zod", mode: "query", }); -export { schemaQueryId, withValidQueryIdTransformParseInt }; +export { schemaQueryIdParseInt, withValidQueryIdTransformParseInt }; diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts new file mode 100644 index 0000000000..fb50c9c9ad --- /dev/null +++ b/lib/validations/webhook.ts @@ -0,0 +1,65 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +const schemaBooking = z + .object({ + uid: z.string().min(3), + title: z.string().min(3), + description: z.string().min(3).optional(), + startTime: z.date().or(z.string()), + endTime: z.date(), + location: z.string().min(3).optional(), + createdAt: z.date().or(z.string()), + updatedAt: z.date(), + confirmed: z.boolean().default(true), + rejected: z.boolean().default(false), + paid: z.boolean().default(false), + + // bufferTime: z.number().default(0), + // // attendees: z.array((schemaSchedule)).optional(), + + // startTime: z.string().min(3), + // endTime: z.string().min(3), + // email: z.string().email(), // max is a full day. + // emailVerified: z.date().optional(), + // password: z.string().optional(), + // bio: z.string().min(3).optional(), + // avatar: z.string().optional(), + // timeZone: z.string().default("Europe/London"), + // weekStart: z.string().default("Sunday"), + // bufferTime: z.number().default(0), + // theme: z.string().optional(), + // trialEndsAt: z.date().optional(), + // eventTypes: z.array((schemaEventType)).optional(), + // // credentials: z.array((schemaCredentials)).optional(), + // // teams: z.array((schemaMembership)).optional(), + // // bookings: z.array((schemaBooking)).optional(), + // // schedules: z.array((schemaSchedule)).optional(), + // defaultScheduleId: z.number().optional(), + // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), + // completedOnboarding: z.boolean().default(false), + // locale: z.string().optional(), + // timeFormat: z.number().optional().default(12), + // twoFactorEnabled: z.boolean().default(false), + // twoFactorSecret: z.string().optional(), + // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), + // identityProviderId: z.string().optional(), + // // availavility: z.array((schemaAvailavility)).optional(), + // invitedTo: z.number().optional(), + // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), + // // webhooks: z.array((schemaWebhook)).optional(), + // brandColor: z.string().default("#292929"), + // darkBrandColor: z.string().default("#fafafa"), + // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here + // away: z.boolean().default(false), + // metadata: z.object({}).optional(), + // verified: z.boolean().default(false), + }) + .strict(); // Adding strict so that we can disallow passing in extra fields +const withValidBooking = withValidation({ + schema: schemaBooking, + type: "Zod", + mode: "body", +}); + +export { schemaBooking, withValidBooking }; diff --git a/pages/api/api-keys/[id]/delete.ts b/pages/api/api-keys/[id]/delete.ts index dbd64971f9..b5644e6ce8 100644 --- a/pages/api/api-keys/[id]/delete.ts +++ b/pages/api/api-keys/[id]/delete.ts @@ -11,6 +11,7 @@ type ResponseData = { export async function apiKey(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; const safe = await schemaQueryIdAsString.safeParse(query); + if (method === "DELETE" && safe.success) { // DELETE WILL DELETE THE EVENT TYPE await prisma.apiKey @@ -23,10 +24,8 @@ export async function apiKey(req: NextApiRequest, res: NextApiResponse { res.status(404).json({ message: `apiKey with ID ${safeQuery.data.id} not found and wasn't updated`, error }) }); - } else { - // Reject any other HTTP method than POST - res.status(405).json({ message: "Only PATCH Method allowed for updating API keys" }); - } + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only PATCH Method allowed for updating API keys" }); } export default withValidQueryIdString(withValidApiKey(editApiKey)); diff --git a/pages/api/api-keys/[id]/index.ts b/pages/api/api-keys/[id]/index.ts index 169e1c121d..49b3a7f6a2 100644 --- a/pages/api/api-keys/[id]/index.ts +++ b/pages/api/api-keys/[id]/index.ts @@ -18,10 +18,8 @@ export async function apiKey(req: NextApiRequest, res: NextApiResponse) { const { method } = req; if (method === "GET") { - // try { const apiKeys = await prisma.apiKey.findMany({}); res.status(200).json({ data: { ...apiKeys } }); - // Without any params this never fails. not sure how to force test unavailable prisma query - // } catch (error) { - // // FIXME: Add zod for validation/error handling - // res.status(400).json({ error: error }); - // } - - } else { - // Reject any other HTTP method than POST - res.status(405).json({ message: "Only GET Method allowed" }); - } + } else res.status(405).json({ message: "Only GET Method allowed" }); } diff --git a/pages/api/api-keys/new.ts b/pages/api/api-keys/new.ts index 4a88584d67..8787824fbd 100644 --- a/pages/api/api-keys/new.ts +++ b/pages/api/api-keys/new.ts @@ -15,21 +15,13 @@ async function createApiKey(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryIdParseInt.safeParse(query); + + if (method === "DELETE" && safe.success) { + // DELETE WILL DELETE THE EVENT TYPE + prisma.attendee + .delete({ where: { id: safe.data.id } }) + .then(() => { + // We only remove the attendee type from the database if there's an existing resource. + res.status(200).json({ message: `attendee-type with id: ${safe.data.id} deleted successfully` }); + }) + .catch((error) => { + // This catches the error thrown by prisma.attendee.delete() if the resource is not found. + res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); + }); + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only DELETE Method allowed in /attendee-types/[id]/delete endpoint" }); + } +} + +export default withValidQueryIdTransformParseInt(attendee); diff --git a/pages/api/attendees/[id]/edit.ts b/pages/api/attendees/[id]/edit.ts new file mode 100644 index 0000000000..42a742a46b --- /dev/null +++ b/pages/api/attendees/[id]/edit.ts @@ -0,0 +1,33 @@ +import prisma from "@calcom/prisma"; + +import { Attendee } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaAttendee, withValidAttendee } from "@lib/validations/attendee"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: Attendee; + message?: string; + error?: unknown; +}; + +export async function editAttendee(req: NextApiRequest, res: NextApiResponse) { + const { query, body, method } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaAttendee.safeParse(body); + + if (method === "PATCH" && safeQuery.success && safeBody.success) { + await prisma.attendee.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }).then(attendee => { + res.status(200).json({ data: attendee }); + }).catch(error => { + res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + }); + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only PATCH Method allowed for updating attendees" }); +} + +export default withValidQueryIdTransformParseInt(withValidAttendee(editAttendee)); diff --git a/pages/api/attendees/[id]/index.ts b/pages/api/attendees/[id]/index.ts new file mode 100644 index 0000000000..a5521dd057 --- /dev/null +++ b/pages/api/attendees/[id]/index.ts @@ -0,0 +1,27 @@ +import prisma from "@calcom/prisma"; + +import { Attendee } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: Attendee; + message?: string; + error?: unknown; +}; + +export async function attendee(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryIdParseInt.safeParse(query); + + if (method === "GET" && safe.success) { + const attendee = await prisma.attendee.findUnique({ where: { id: safe.data.id } }); + + if (attendee) res.status(200).json({ data: attendee }); + if (!attendee) res.status(404).json({ message: "Event type not found" }); + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only GET Method allowed" }); +} + +export default withValidQueryIdTransformParseInt(attendee); diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts new file mode 100644 index 0000000000..121457759f --- /dev/null +++ b/pages/api/attendees/index.ts @@ -0,0 +1,19 @@ +import prisma from "@calcom/prisma"; + +import { Attendee } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +type ResponseData = { + data?: Attendee[]; + error?: unknown; +}; + +export default async function attendee(req: NextApiRequest, res: NextApiResponse) { + try { + const attendees = await prisma.attendee.findMany(); + res.status(200).json({ data: { ...attendees } }); + } catch (error) { + // FIXME: Add zod for validation/error handling + res.status(400).json({ error: error }); + } +} diff --git a/pages/api/attendees/new.ts b/pages/api/attendees/new.ts new file mode 100644 index 0000000000..12762f14f0 --- /dev/null +++ b/pages/api/attendees/new.ts @@ -0,0 +1,27 @@ +import prisma from "@calcom/prisma"; + +import { Attendee } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaAttendee, withValidAttendee } from "@lib/validations/attendee"; + +type ResponseData = { + data?: Attendee; + message?: string; + error?: string; +}; + +async function createAttendee(req: NextApiRequest, res: NextApiResponse) { + const { body, method } = req; + const safe = schemaAttendee.safeParse(body); + + if (method === "POST" && safe.success) { + await prisma.attendee + .create({ data: safe.data }) + .then((attendee) => res.status(201).json({ data: attendee })) + .catch((error) => res.status(400).json({ message: "Could not create attendee type", error: error })); + // Reject any other HTTP method than POST + } else res.status(405).json({ error: "Only POST Method allowed" }); +} + +export default withValidAttendee(createAttendee); diff --git a/pages/api/availabilities/[id]/delete.ts b/pages/api/availabilities/[id]/delete.ts new file mode 100644 index 0000000000..cd3c840801 --- /dev/null +++ b/pages/api/availabilities/[id]/delete.ts @@ -0,0 +1,27 @@ +import prisma from "@calcom/prisma"; + +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + + +type ResponseData = { + message?: string; + error?: unknown; +}; + +export async function availability(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryIdParseInt.safeParse(query); + if (method === "DELETE" && safe.success && safe.data) { + const availability = await prisma.availability + .delete({ where: { id: safe.data.id } }) + // We only remove the availability type from the database if there's an existing resource. + if (availability) res.status(200).json({ message: `availability with id: ${safe.data.id} deleted successfully` }); + // This catches the error thrown by prisma.availability.delete() if the resource is not found. + else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only DELETE Method allowed in /availabilities/[id]/delete endpoint" }); +} + +export default withValidQueryIdTransformParseInt(availability); diff --git a/pages/api/availabilities/[id]/edit.ts b/pages/api/availabilities/[id]/edit.ts new file mode 100644 index 0000000000..3b9f3d7707 --- /dev/null +++ b/pages/api/availabilities/[id]/edit.ts @@ -0,0 +1,33 @@ +import prisma from "@calcom/prisma"; + +import { Availability } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaAvailability, withValidAvailability,} from "@lib/validations/availability"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: Availability; + message?: string; + error?: unknown; +}; + +export async function editAvailability(req: NextApiRequest, res: NextApiResponse) { + const { query, body, method } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaAvailability.safeParse(body); + + if (method === "PATCH" && safeQuery.success && safeBody.success) { + await prisma.availability.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }).then(availability => { + res.status(200).json({ data: availability }); + }).catch(error => { + res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + }); + // Reject any other HTTP method than PATCH + } else res.status(405).json({ message: "Only PATCH Method allowed for updating availabilities" }); +} + +export default withValidQueryIdTransformParseInt(withValidAvailability(editAvailability)); diff --git a/pages/api/availabilities/[id]/index.ts b/pages/api/availabilities/[id]/index.ts new file mode 100644 index 0000000000..7d10930907 --- /dev/null +++ b/pages/api/availabilities/[id]/index.ts @@ -0,0 +1,28 @@ +import prisma from "@calcom/prisma"; + +import { Availability } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: Availability; + message?: string; + error?: unknown; +}; + +export async function availability(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryIdParseInt.safeParse(query); + + if (method === "GET" && safe.success) { + const availability = await prisma.availability.findUnique({ where: { id: safe.data.id } }); + + if (availability) res.status(200).json({ data: availability }); + if (!availability) res.status(404).json({ message: "Event type not found" }); + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only GET Method allowed" }); +} + + +export default withValidQueryIdTransformParseInt(availability); diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts new file mode 100644 index 0000000000..f529fd6ed2 --- /dev/null +++ b/pages/api/availabilities/index.ts @@ -0,0 +1,19 @@ +import prisma from "@calcom/prisma"; + +import { Availability } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +type ResponseData = { + data?: Availability[]; + error?: unknown; +}; + +export default async function availability(req: NextApiRequest, res: NextApiResponse) { + try { + const availabilities = await prisma.availability.findMany(); + res.status(200).json({ data: { ...availabilities } }); + } catch (error) { + // FIXME: Add zod for validation/error handling + res.status(400).json({ error: error }); + } +} diff --git a/pages/api/availabilities/new.ts b/pages/api/availabilities/new.ts new file mode 100644 index 0000000000..fdb7abca24 --- /dev/null +++ b/pages/api/availabilities/new.ts @@ -0,0 +1,30 @@ +import prisma from "@calcom/prisma"; + +import { Availability } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaAvailability, withValidAvailability } from "@lib/validations/availability"; + +type ResponseData = { + data?: Availability; + message?: string; + error?: string; +}; + +async function createAvailability(req: NextApiRequest, res: NextApiResponse) { + const { body, method } = req; + if (method === "POST") { + const safe = schemaAvailability.safeParse(body); + if (safe.success && safe.data) { + await prisma.availability + .create({ data: safe.data }) + .then((availability) => res.status(201).json({ data: availability })) + .catch((error) => res.status(400).json({ message: "Could not create availability type", error: error })); + } + } else { + // Reject any other HTTP method than POST + res.status(405).json({ error: "Only POST Method allowed" }); + } +} + +export default withValidAvailability(createAvailability); diff --git a/pages/api/bookings/[id]/delete.ts b/pages/api/bookings/[id]/delete.ts index 1196e505eb..62fa836955 100644 --- a/pages/api/bookings/[id]/delete.ts +++ b/pages/api/bookings/[id]/delete.ts @@ -2,7 +2,7 @@ import prisma from "@calcom/prisma"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { @@ -12,24 +12,23 @@ type ResponseData = { export async function booking(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; - const safe = await schemaQueryId.safeParse(query); - if (safe.success) { - if (method === "DELETE") { - // DELETE WILL DELETE THE EVENT TYPE - prisma.booking - .delete({ where: { id: safe.data.id } }) - .then(() => { - // We only remove the booking type from the database if there's an existing resource. - res.status(200).json({ message: `booking-type with id: ${safe.data.id} deleted successfully` }); - }) - .catch((error) => { - // This catches the error thrown by prisma.booking.delete() if the resource is not found. - res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); - }); - } else { - // Reject any other HTTP method than POST - res.status(405).json({ message: "Only DELETE Method allowed in /booking-types/[id]/delete endpoint" }); - } + const safe = await schemaQueryIdParseInt.safeParse(query); + + if (method === "DELETE" && safe.success) { + // DELETE WILL DELETE THE EVENT TYPE + prisma.booking + .delete({ where: { id: safe.data.id } }) + .then(() => { + // We only remove the booking type from the database if there's an existing resource. + res.status(200).json({ message: `booking-type with id: ${safe.data.id} deleted successfully` }); + }) + .catch((error) => { + // This catches the error thrown by prisma.booking.delete() if the resource is not found. + res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); + }); + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only DELETE Method allowed in /booking-types/[id]/delete endpoint" }); } } diff --git a/pages/api/bookings/[id]/edit.ts b/pages/api/bookings/[id]/edit.ts index 1fc77f9c25..9d78fbaa00 100644 --- a/pages/api/bookings/[id]/edit.ts +++ b/pages/api/bookings/[id]/edit.ts @@ -4,7 +4,7 @@ import { Booking } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; import { schemaBooking, withValidBooking } from "@lib/validations/booking"; -import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: Booking; @@ -14,7 +14,7 @@ type ResponseData = { export async function editBooking(req: NextApiRequest, res: NextApiResponse) { const { query, body, method } = req; - const safeQuery = await schemaQueryId.safeParse(query); + const safeQuery = await schemaQueryIdParseInt.safeParse(query); const safeBody = await schemaBooking.safeParse(body); if (method === "PATCH") { diff --git a/pages/api/bookings/[id]/index.ts b/pages/api/bookings/[id]/index.ts index 11c84ba5c8..dbe47a5f91 100644 --- a/pages/api/bookings/[id]/index.ts +++ b/pages/api/bookings/[id]/index.ts @@ -3,7 +3,7 @@ import prisma from "@calcom/prisma"; import { Booking } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: Booking; @@ -13,17 +13,16 @@ type ResponseData = { export async function booking(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; - const safe = await schemaQueryId.safeParse(query); - if (safe.success) { - if (method === "GET") { - const booking = await prisma.booking.findUnique({ where: { id: safe.data.id } }); + const safe = await schemaQueryIdParseInt.safeParse(query); - if (booking) res.status(200).json({ data: booking }); - if (!booking) res.status(404).json({ message: "Event type not found" }); - } else { - // Reject any other HTTP method than POST - res.status(405).json({ message: "Only GET Method allowed" }); - } + if (method === "GET" && safe.success) { + const booking = await prisma.booking.findUnique({ where: { id: safe.data.id } }); + + if (booking) res.status(200).json({ data: booking }); + if (!booking) res.status(404).json({ message: "Event type not found" }); + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only GET Method allowed" }); } } diff --git a/pages/api/event-types/[id]/delete.ts b/pages/api/event-types/[id]/delete.ts index f6341df094..72bca44879 100644 --- a/pages/api/event-types/[id]/delete.ts +++ b/pages/api/event-types/[id]/delete.ts @@ -2,7 +2,7 @@ import prisma from "@calcom/prisma"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { @@ -12,24 +12,22 @@ type ResponseData = { export async function eventType(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; - const safe = await schemaQueryId.safeParse(query); - if (safe.success) { - if (method === "DELETE") { - // DELETE WILL DELETE THE EVENT TYPE - prisma.eventType - .delete({ where: { id: safe.data.id } }) - .then(() => { - // We only remove the event type from the database if there's an existing resource. - res.status(200).json({ message: `event-type with id: ${safe.data.id} deleted successfully` }); - }) - .catch((error) => { - // This catches the error thrown by prisma.eventType.delete() if the resource is not found. - res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); - }); - } else { - // Reject any other HTTP method than POST - res.status(405).json({ message: "Only DELETE Method allowed in /event-types/[id]/delete endpoint" }); - } + const safe = await schemaQueryIdParseInt.safeParse(query); + if (method === "DELETE" && safe.success) { + // DELETE WILL DELETE THE EVENT TYPE + prisma.eventType + .delete({ where: { id: safe.data.id } }) + .then(() => { + // We only remove the event type from the database if there's an existing resource. + res.status(200).json({ message: `event-type with id: ${safe.data.id} deleted successfully` }); + }) + .catch((error) => { + // This catches the error thrown by prisma.eventType.delete() if the resource is not found. + res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); + }); + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only DELETE Method allowed in /event-types/[id]/delete endpoint" }); } } diff --git a/pages/api/event-types/[id]/edit.ts b/pages/api/event-types/[id]/edit.ts index 276b0ba34a..becd6b5255 100644 --- a/pages/api/event-types/[id]/edit.ts +++ b/pages/api/event-types/[id]/edit.ts @@ -4,7 +4,7 @@ import { EventType } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; import { schemaEventType, withValidEventType } from "@lib/validations/eventType"; -import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: EventType; @@ -14,7 +14,7 @@ type ResponseData = { export async function editEventType(req: NextApiRequest, res: NextApiResponse) { const { query, body, method } = req; - const safeQuery = await schemaQueryId.safeParse(query); + const safeQuery = await schemaQueryIdParseInt.safeParse(query); const safeBody = await schemaEventType.safeParse(body); if (method === "PATCH") { diff --git a/pages/api/event-types/[id]/index.ts b/pages/api/event-types/[id]/index.ts index 44eaa46c77..9b8a159ab3 100644 --- a/pages/api/event-types/[id]/index.ts +++ b/pages/api/event-types/[id]/index.ts @@ -3,7 +3,7 @@ import prisma from "@calcom/prisma"; import { EventType } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: EventType; @@ -13,17 +13,16 @@ type ResponseData = { export async function eventType(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; - const safe = await schemaQueryId.safeParse(query); - if (safe.success) { - if (method === "GET") { - const event = await prisma.eventType.findUnique({ where: { id: safe.data.id } }); + const safe = await schemaQueryIdParseInt.safeParse(query); - if (event) res.status(200).json({ data: event }); - if (!event) res.status(404).json({ message: "Event type not found" }); - } else { - // Reject any other HTTP method than POST - res.status(405).json({ message: "Only GET Method allowed" }); - } + if (method === "GET" && safe.success) { + const event = await prisma.eventType.findUnique({ where: { id: safe.data.id } }); + + if (event) res.status(200).json({ data: event }); + if (!event) res.status(404).json({ message: "Event type not found" }); + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only GET Method allowed" }); } } diff --git a/pages/api/teams/[id]/delete.ts b/pages/api/teams/[id]/delete.ts index 26a5df4919..935d24c12f 100644 --- a/pages/api/teams/[id]/delete.ts +++ b/pages/api/teams/[id]/delete.ts @@ -2,7 +2,7 @@ import prisma from "@calcom/prisma"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { @@ -12,24 +12,22 @@ type ResponseData = { export async function team(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; - const safe = await schemaQueryId.safeParse(query); - if (safe.success) { - if (method === "DELETE") { - // DELETE WILL DELETE THE EVENT TYPE - prisma.team - .delete({ where: { id: safe.data.id } }) - .then(() => { - // We only remove the team type from the database if there's an existing resource. - res.status(200).json({ message: `team-type with id: ${safe.data.id} deleted successfully` }); - }) - .catch((error) => { - // This catches the error thrown by prisma.team.delete() if the resource is not found. - res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); - }); - } else { - // Reject any other HTTP method than POST - res.status(405).json({ message: "Only DELETE Method allowed in /team-types/[id]/delete endpoint" }); - } + const safe = await schemaQueryIdParseInt.safeParse(query); + if (method === "DELETE" && safe.success) { + // DELETE WILL DELETE THE EVENT TYPE + prisma.team + .delete({ where: { id: safe.data.id } }) + .then(() => { + // We only remove the team type from the database if there's an existing resource. + res.status(200).json({ message: `team-type with id: ${safe.data.id} deleted successfully` }); + }) + .catch((error) => { + // This catches the error thrown by prisma.team.delete() if the resource is not found. + res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); + }); + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only DELETE Method allowed in /team-types/[id]/delete endpoint" }); } } diff --git a/pages/api/teams/[id]/edit.ts b/pages/api/teams/[id]/edit.ts index eb3636aac4..c046c97da4 100644 --- a/pages/api/teams/[id]/edit.ts +++ b/pages/api/teams/[id]/edit.ts @@ -4,7 +4,7 @@ import { Team } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; import { schemaTeam, withValidTeam } from "@lib/validations/team"; -import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: Team; @@ -14,7 +14,7 @@ type ResponseData = { export async function editTeam(req: NextApiRequest, res: NextApiResponse) { const { query, body, method } = req; - const safeQuery = await schemaQueryId.safeParse(query); + const safeQuery = await schemaQueryIdParseInt.safeParse(query); const safeBody = await schemaTeam.safeParse(body); if (method === "PATCH") { diff --git a/pages/api/teams/[id]/index.ts b/pages/api/teams/[id]/index.ts index d21c33e266..cd9cd660d4 100644 --- a/pages/api/teams/[id]/index.ts +++ b/pages/api/teams/[id]/index.ts @@ -3,7 +3,7 @@ import prisma from "@calcom/prisma"; import { Team } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: Team; @@ -13,17 +13,16 @@ type ResponseData = { export async function team(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; - const safe = await schemaQueryId.safeParse(query); - if (safe.success) { - if (method === "GET") { - const team = await prisma.team.findUnique({ where: { id: safe.data.id } }); + const safe = await schemaQueryIdParseInt.safeParse(query); + + if (method === "GET" && safe.success) { + const team = await prisma.team.findUnique({ where: { id: safe.data.id } }); - if (team) res.status(200).json({ data: team }); - if (!team) res.status(404).json({ message: "Event type not found" }); - } else { - // Reject any other HTTP method than POST - res.status(405).json({ message: "Only GET Method allowed" }); - } + if (team) res.status(200).json({ data: team }); + if (!team) res.status(404).json({ message: "Event type not found" }); + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only GET Method allowed" }); } } diff --git a/pages/api/users/[id]/delete.ts b/pages/api/users/[id]/delete.ts index 860b684a64..3c9b608ef3 100644 --- a/pages/api/users/[id]/delete.ts +++ b/pages/api/users/[id]/delete.ts @@ -2,7 +2,7 @@ import prisma from "@calcom/prisma"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { @@ -12,24 +12,22 @@ type ResponseData = { export async function user(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; - const safe = await schemaQueryId.safeParse(query); - if (safe.success) { - if (method === "DELETE") { - // DELETE WILL DELETE THE EVENT TYPE - prisma.user - .delete({ where: { id: safe.data.id } }) - .then(() => { - // We only remove the user type from the database if there's an existing resource. - res.status(200).json({ message: `user-type with id: ${safe.data.id} deleted successfully` }); - }) - .catch((error) => { - // This catches the error thrown by prisma.user.delete() if the resource is not found. - res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); - }); - } else { - // Reject any other HTTP method than POST - res.status(405).json({ message: "Only DELETE Method allowed in /user-types/[id]/delete endpoint" }); - } + const safe = await schemaQueryIdParseInt.safeParse(query); + if (method === "DELETE" && safe.success) { + // DELETE WILL DELETE THE EVENT TYPE + prisma.user + .delete({ where: { id: safe.data.id } }) + .then(() => { + // We only remove the user type from the database if there's an existing resource. + res.status(200).json({ message: `user-type with id: ${safe.data.id} deleted successfully` }); + }) + .catch((error) => { + // This catches the error thrown by prisma.user.delete() if the resource is not found. + res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); + }); + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only DELETE Method allowed in /user-types/[id]/delete endpoint" }); } } diff --git a/pages/api/users/[id]/edit.ts b/pages/api/users/[id]/edit.ts index 7b26f306f8..1e5780fc35 100644 --- a/pages/api/users/[id]/edit.ts +++ b/pages/api/users/[id]/edit.ts @@ -4,7 +4,7 @@ import { User } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; import { schemaUser, withValidUser } from "@lib/validations/user"; -import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: User; @@ -14,7 +14,7 @@ type ResponseData = { export async function editUser(req: NextApiRequest, res: NextApiResponse) { const { query, body, method } = req; - const safeQuery = await schemaQueryId.safeParse(query); + const safeQuery = await schemaQueryIdParseInt.safeParse(query); const safeBody = await schemaUser.safeParse(body); if (method === "PATCH") { diff --git a/pages/api/users/[id]/index.ts b/pages/api/users/[id]/index.ts index a5fcf369fa..8852ad6e6f 100644 --- a/pages/api/users/[id]/index.ts +++ b/pages/api/users/[id]/index.ts @@ -3,7 +3,7 @@ import prisma from "@calcom/prisma"; import { User } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryId, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: User; @@ -13,17 +13,15 @@ type ResponseData = { export async function user(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; - const safe = await schemaQueryId.safeParse(query); - if (safe.success) { - if (method === "GET") { - const user = await prisma.user.findUnique({ where: { id: safe.data.id } }); + const safe = await schemaQueryIdParseInt.safeParse(query); + if (method === "GET" && safe.success) { + const user = await prisma.user.findUnique({ where: { id: safe.data.id } }); - if (user) res.status(200).json({ data: user }); - if (!user) res.status(404).json({ message: "Event type not found" }); - } else { - // Reject any other HTTP method than POST - res.status(405).json({ message: "Only GET Method allowed" }); - } + if (user) res.status(200).json({ data: user }); + if (!user) res.status(404).json({ message: "Event type not found" }); + } else { + // Reject any other HTTP method than POST + res.status(405).json({ message: "Only GET Method allowed" }); } } diff --git a/tests/bookings/[id]/booking.id.edit.test.ts b/tests/bookings/[id]/booking.id.edit.test.ts new file mode 100644 index 0000000000..5b7c1ec73f --- /dev/null +++ b/tests/bookings/[id]/booking.id.edit.test.ts @@ -0,0 +1,92 @@ +import handleBookingEdit from "@api/bookings/[id]/edit"; +import { createMocks } from "node-mocks-http"; + +import prisma from "@calcom/prisma"; + +describe("PATCH /api/bookings/[id]/edit with valid id and body updates an booking", () => { + it("returns a message with the specified bookings", async () => { + const { req, res } = createMocks({ + method: "PATCH", + query: { + id: "2", + }, + body: { + title: "Updated title", + slug: "updated-slug", + length: 1, + }, + }); + const booking = await prisma.booking.findUnique({ where: { id: parseInt(req.query.id) } }); + await handleBookingEdit(req, res); + + expect(res._getStatusCode()).toBe(200); + if (booking) booking.title = "Updated title"; + expect(JSON.parse(res._getData())).toStrictEqual({ data: booking }); + }); +}); + +describe("PATCH /api/bookings/[id]/edit with invalid id returns 404", () => { + it("returns a message with the specified bookings", async () => { + const { req, res } = createMocks({ + method: "PATCH", + query: { + id: "0", + }, + body: { + title: "Updated title", + slug: "updated-slug", + length: 1, + }, + }); + const booking = await prisma.booking.findUnique({ where: { id: parseInt(req.query.id) } }); + await handleBookingEdit(req, res); + + expect(res._getStatusCode()).toBe(404); + if (booking) booking.title = "Updated title"; + expect(JSON.parse(res._getData())).toStrictEqual({ "error": { + "clientVersion": "3.10.0", + "code": "P2025", + "meta": { + "cause": "Record to update not found.", + }, + }, + "message": "Event type with ID 0 not found and wasn't updated", }); + }); +}); + +describe("PATCH /api/bookings/[id]/edit with valid id and no body returns 400 error and zod validation errors", () => { + it("returns a message with the specified bookings", async () => { + const { req, res } = createMocks({ + method: "PATCH", + query: { + id: "2", + }, + }); + await handleBookingEdit(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(JSON.parse(res._getData())).toStrictEqual([{"code": "invalid_type", "expected": "string", "message": "Required", "path": ["title"], "received": "undefined"}, {"code": "invalid_type", "expected": "string", "message": "Required", "path": ["slug"], "received": "undefined"}, {"code": "invalid_type", "expected": "number", "message": "Required", "path": ["length"], "received": "undefined"}]); + }); +}); + +describe("POST /api/bookings/[id]/edit fails, only PATCH allowed", () => { + it("returns a message with the specified bookings", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + query: { + id: "1", + }, + body: { + title: "Updated title", + slug: "updated-slug", + length: 1, + }, + }); + await handleBookingEdit(req, res); + + expect(res._getStatusCode()).toBe(405); + expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only PATCH Method allowed for updating bookings" }); + }); +}); + + diff --git a/tests/bookings/[id]/booking.id.index.test.ts b/tests/bookings/[id]/booking.id.index.test.ts new file mode 100644 index 0000000000..d4edede123 --- /dev/null +++ b/tests/bookings/[id]/booking.id.index.test.ts @@ -0,0 +1,85 @@ +import handleBooking from "@api/bookings/[id]"; +import { createMocks } from "node-mocks-http"; + +import prisma from "@calcom/prisma"; +import { stringifyISODate } from "@lib/utils/stringifyISODate"; + +describe("GET /api/bookings/[id] with valid id as string returns an booking", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "GET", + query: { + id: "1", + }, + }); + const booking = await prisma.booking.findUnique({ where: { id: 1 } }); + await handleBooking(req, res); + + expect(res._getStatusCode()).toBe(200); + expect(JSON.parse(res._getData())).toEqual({ + data: { + ...booking, + createdAt: stringifyISODate(booking?.createdAt), + startTime: stringifyISODate(booking?.startTime), + endTime: stringifyISODate(booking?.endTime) + } + }); + }); +}); + +// This can never happen under our normal nextjs setup where query is always a string | string[]. +// But seemed a good example for testing an error validation +describe("GET /api/bookings/[id] errors if query id is number, requires a string", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "GET", + query: { + id: 1, // passing query as a number, which should fail as nextjs will try to parse it as a string + }, + }); + await handleBooking(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(JSON.parse(res._getData())).toStrictEqual([ + { + code: "invalid_type", + expected: "string", + received: "number", + path: ["id"], + message: "Expected string, received number", + }, + ]); + }); +}); + +describe("GET /api/bookings/[id] an id not present in db like 0, throws 404 not found", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "GET", + query: { + id: "0", // There's no booking type with id 0 + }, + }); + await handleBooking(req, res); + + expect(res._getStatusCode()).toBe(404); + expect(JSON.parse(res._getData())).toStrictEqual({ message: "Event type not found" }); + }); +}); + +describe("POST /api/bookings/[id] fails, only GET allowed", () => { + it("returns a message with the specified events", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + query: { + id: "1", + }, + }); + await handleBooking(req, res); + + expect(res._getStatusCode()).toBe(405); + expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); + }); +}); + + diff --git a/tests/bookings/booking.index.test.ts b/tests/bookings/booking.index.test.ts new file mode 100644 index 0000000000..87e1bd24b5 --- /dev/null +++ b/tests/bookings/booking.index.test.ts @@ -0,0 +1,31 @@ +import handleApiKeys from "@api/api-keys"; +import { createMocks } from "node-mocks-http"; + +import prisma from "@calcom/prisma"; +import {stringifyISODate} from "@lib/utils/stringifyISODate"; + +describe("GET /api/api-keys without any params", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "GET", + query: {}, + }); + let apiKeys = await prisma.apiKey.findMany(); + await handleApiKeys(req, res); + + expect(res._getStatusCode()).toBe(200); + apiKeys = apiKeys.map(apiKey => (apiKey = {...apiKey, createdAt: stringifyISODate(apiKey?.createdAt), expiresAt: stringifyISODate(apiKey?.expiresAt)})); + expect(JSON.parse(res._getData())).toStrictEqual(JSON.parse(JSON.stringify({ data: {...apiKeys} }))); + }); +}); + +describe("POST /api/api-keys/ fails, only GET allowed", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + }); + await handleApiKeys(req, res); + expect(res._getStatusCode()).toBe(405); + expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); + }); +}); diff --git a/tests/bookings/booking.new.test.ts b/tests/bookings/booking.new.test.ts new file mode 100644 index 0000000000..9507bdbd71 --- /dev/null +++ b/tests/bookings/booking.new.test.ts @@ -0,0 +1,71 @@ +import handleNewApiKey from "@api/api-keys/new"; +import { createMocks } from "node-mocks-http"; + +describe("POST /api/api-keys/new with a note", () => { + it("returns a 201, and the created api key", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + body: { + note: "Updated note", + }, + }); + await handleNewApiKey(req, res); + + expect(res._getStatusCode()).toBe(201); + expect(JSON.parse(res._getData()).data.note).toStrictEqual("Updated note"); + }); +}); + +describe("POST /api/api-keys/new with a slug param", () => { + it("returns error 400, and the details about invalid slug body param", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + body: { + note: "Updated note", + slug: "slug", + }, + }); + await handleNewApiKey(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(JSON.parse(res._getData())).toStrictEqual( + [{"code": "unrecognized_keys", "keys": ["slug"], "message": "Unrecognized key(s) in object: 'slug'", "path": []}] + ); + }); +}); + + +describe("GET /api/api-keys/new fails, only POST allowed", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "GET", // This POST method is not allowed + }); + await handleNewApiKey(req, res); + + expect(res._getStatusCode()).toBe(405); + expect(JSON.parse(res._getData())).toStrictEqual({ error: "Only POST Method allowed" }); + }); +}); + + +// FIXME: test 405 when prisma fails look for how to test prisma errors +describe("GET /api/api-keys/new fails, only POST allowed", () => { + it("returns a message with the specified apiKeys", async () => { + const { req, res } = createMocks({ + method: "POST", // This POST method is not allowed + body: { + nonExistentParam: true + // note: '123', + // slug: 12, + }, + }); + await handleNewApiKey(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(JSON.parse(res._getData())).toStrictEqual([{ + "code": "unrecognized_keys", + "keys": ["nonExistentParam"], + "message": "Unrecognized key(s) in object: 'nonExistentParam'", "path": [] + }]); + }); +}); \ No newline at end of file diff --git a/tests/teams/[id]/team.id.test.edit.ts b/tests/teams/[id]/team.id.edit.test.ts similarity index 100% rename from tests/teams/[id]/team.id.test.edit.ts rename to tests/teams/[id]/team.id.edit.test.ts diff --git a/tests/teams/[id]/team.id.test.index.ts b/tests/teams/[id]/team.id.index.test.ts similarity index 100% rename from tests/teams/[id]/team.id.test.index.ts rename to tests/teams/[id]/team.id.index.test.ts From 396c5b8d8caca612b38078cbc862966b9b49b4e7 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 27 Mar 2022 01:08:00 +0100 Subject: [PATCH 032/658] chore: refactor all delete endpoints to use if/else instead of .catch() and .error() --- pages/api/api-keys/[id]/delete.ts | 24 ++++++++++-------------- pages/api/attendees/[id]/delete.ts | 22 +++++++--------------- pages/api/bookings/[id]/delete.ts | 26 +++++++++----------------- pages/api/event-types/[id]/delete.ts | 25 +++++++++---------------- pages/api/teams/[id]/delete.ts | 25 +++++++++---------------- pages/api/users/[id]/delete.ts | 25 +++++++++---------------- 6 files changed, 53 insertions(+), 94 deletions(-) diff --git a/pages/api/api-keys/[id]/delete.ts b/pages/api/api-keys/[id]/delete.ts index b5644e6ce8..10e6aaef98 100644 --- a/pages/api/api-keys/[id]/delete.ts +++ b/pages/api/api-keys/[id]/delete.ts @@ -1,8 +1,10 @@ import prisma from "@calcom/prisma"; -import { NextApiRequest, NextApiResponse } from "next"; + +import type { NextApiRequest, NextApiResponse } from "next"; import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; + type ResponseData = { message?: string; error?: unknown; @@ -11,19 +13,13 @@ type ResponseData = { export async function apiKey(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; const safe = await schemaQueryIdAsString.safeParse(query); - - if (method === "DELETE" && safe.success) { - // DELETE WILL DELETE THE EVENT TYPE - await prisma.apiKey - .delete({ where: { id: safe.data.id } }) - .then(() => { - // We only remove the api key from the database if there's an existing resource. - res.status(204).json({ message: `api-key with id: ${safe.data.id} deleted successfully` }); - }) - .catch((error) => { - // This catches the error thrown by prisma.apiKey.delete() if the resource is not found. - res.status(404).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); - }); + if (method === "DELETE" && safe.success && safe.data) { + const apiKey = await prisma.apiKey + .delete({ where: { id: safe.data.id } }) + // We only remove the apiKey type from the database if there's an existing resource. + if (apiKey) res.status(200).json({ message: `apiKey with id: ${safe.data.id} deleted successfully` }); + // This catches the error thrown by prisma.apiKey.delete() if the resource is not found. + else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); // Reject any other HTTP method than POST } else res.status(405).json({ message: "Only DELETE Method allowed" }); } diff --git a/pages/api/attendees/[id]/delete.ts b/pages/api/attendees/[id]/delete.ts index 767860af93..47b4a783b7 100644 --- a/pages/api/attendees/[id]/delete.ts +++ b/pages/api/attendees/[id]/delete.ts @@ -13,23 +13,15 @@ type ResponseData = { export async function attendee(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; const safe = await schemaQueryIdParseInt.safeParse(query); - - if (method === "DELETE" && safe.success) { - // DELETE WILL DELETE THE EVENT TYPE - prisma.attendee + if (method === "DELETE" && safe.success && safe.data) { + const attendee = await prisma.attendee .delete({ where: { id: safe.data.id } }) - .then(() => { - // We only remove the attendee type from the database if there's an existing resource. - res.status(200).json({ message: `attendee-type with id: ${safe.data.id} deleted successfully` }); - }) - .catch((error) => { - // This catches the error thrown by prisma.attendee.delete() if the resource is not found. - res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); - }); - } else { + // We only remove the attendee type from the database if there's an existing resource. + if (attendee) res.status(200).json({ message: `attendee with id: ${safe.data.id} deleted successfully` }); + // This catches the error thrown by prisma.attendee.delete() if the resource is not found. + else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); // Reject any other HTTP method than POST - res.status(405).json({ message: "Only DELETE Method allowed in /attendee-types/[id]/delete endpoint" }); - } + } else res.status(405).json({ message: "Only DELETE Method allowed in /availabilities/[id]/delete endpoint" }); } export default withValidQueryIdTransformParseInt(attendee); diff --git a/pages/api/bookings/[id]/delete.ts b/pages/api/bookings/[id]/delete.ts index 62fa836955..4150a66613 100644 --- a/pages/api/bookings/[id]/delete.ts +++ b/pages/api/bookings/[id]/delete.ts @@ -10,26 +10,18 @@ type ResponseData = { error?: unknown; }; -export async function booking(req: NextApiRequest, res: NextApiResponse) { +export async function deleteBooking(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; const safe = await schemaQueryIdParseInt.safeParse(query); - - if (method === "DELETE" && safe.success) { - // DELETE WILL DELETE THE EVENT TYPE - prisma.booking + if (method === "DELETE" && safe.success && safe.data) { + const booking = await prisma.booking .delete({ where: { id: safe.data.id } }) - .then(() => { - // We only remove the booking type from the database if there's an existing resource. - res.status(200).json({ message: `booking-type with id: ${safe.data.id} deleted successfully` }); - }) - .catch((error) => { - // This catches the error thrown by prisma.booking.delete() if the resource is not found. - res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); - }); - } else { + // We only remove the booking type from the database if there's an existing resource. + if (booking) res.status(200).json({ message: `booking with id: ${safe.data.id} deleted successfully` }); + // This catches the error thrown by prisma.booking.delete() if the resource is not found. + else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); // Reject any other HTTP method than POST - res.status(405).json({ message: "Only DELETE Method allowed in /booking-types/[id]/delete endpoint" }); - } + } else res.status(405).json({ message: "Only DELETE Method allowed in /availabilities/[id]/delete endpoint" }); } -export default withValidQueryIdTransformParseInt(booking); +export default withValidQueryIdTransformParseInt(deleteBooking); diff --git a/pages/api/event-types/[id]/delete.ts b/pages/api/event-types/[id]/delete.ts index 72bca44879..d94dc611a2 100644 --- a/pages/api/event-types/[id]/delete.ts +++ b/pages/api/event-types/[id]/delete.ts @@ -10,25 +10,18 @@ type ResponseData = { error?: unknown; }; -export async function eventType(req: NextApiRequest, res: NextApiResponse) { +export async function deleteEventType(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success) { - // DELETE WILL DELETE THE EVENT TYPE - prisma.eventType + if (method === "DELETE" && safe.success && safe.data) { + const eventType = await prisma.eventType .delete({ where: { id: safe.data.id } }) - .then(() => { - // We only remove the event type from the database if there's an existing resource. - res.status(200).json({ message: `event-type with id: ${safe.data.id} deleted successfully` }); - }) - .catch((error) => { - // This catches the error thrown by prisma.eventType.delete() if the resource is not found. - res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); - }); - } else { + // We only remove the eventType type from the database if there's an existing resource. + if (eventType) res.status(200).json({ message: `eventType with id: ${safe.data.id} deleted successfully` }); + // This catches the error thrown by prisma.eventType.delete() if the resource is not found. + else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); // Reject any other HTTP method than POST - res.status(405).json({ message: "Only DELETE Method allowed in /event-types/[id]/delete endpoint" }); - } + } else res.status(405).json({ message: "Only DELETE Method allowed in /availabilities/[id]/delete endpoint" }); } -export default withValidQueryIdTransformParseInt(eventType); +export default withValidQueryIdTransformParseInt(deleteEventType); diff --git a/pages/api/teams/[id]/delete.ts b/pages/api/teams/[id]/delete.ts index 935d24c12f..9ca57af0a4 100644 --- a/pages/api/teams/[id]/delete.ts +++ b/pages/api/teams/[id]/delete.ts @@ -10,25 +10,18 @@ type ResponseData = { error?: unknown; }; -export async function team(req: NextApiRequest, res: NextApiResponse) { +export async function deleteTeam(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success) { - // DELETE WILL DELETE THE EVENT TYPE - prisma.team + if (method === "DELETE" && safe.success && safe.data) { + const team = await prisma.team .delete({ where: { id: safe.data.id } }) - .then(() => { - // We only remove the team type from the database if there's an existing resource. - res.status(200).json({ message: `team-type with id: ${safe.data.id} deleted successfully` }); - }) - .catch((error) => { - // This catches the error thrown by prisma.team.delete() if the resource is not found. - res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); - }); - } else { + // We only remove the team type from the database if there's an existing resource. + if (team) res.status(200).json({ message: `team with id: ${safe.data.id} deleted successfully` }); + // This catches the error thrown by prisma.team.delete() if the resource is not found. + else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); // Reject any other HTTP method than POST - res.status(405).json({ message: "Only DELETE Method allowed in /team-types/[id]/delete endpoint" }); - } + } else res.status(405).json({ message: "Only DELETE Method allowed" }); } -export default withValidQueryIdTransformParseInt(team); +export default withValidQueryIdTransformParseInt(deleteTeam); diff --git a/pages/api/users/[id]/delete.ts b/pages/api/users/[id]/delete.ts index 3c9b608ef3..f7bbf96856 100644 --- a/pages/api/users/[id]/delete.ts +++ b/pages/api/users/[id]/delete.ts @@ -10,25 +10,18 @@ type ResponseData = { error?: unknown; }; -export async function user(req: NextApiRequest, res: NextApiResponse) { +export async function deleteUser(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success) { - // DELETE WILL DELETE THE EVENT TYPE - prisma.user + if (method === "DELETE" && safe.success && safe.data) { + const user = await prisma.user .delete({ where: { id: safe.data.id } }) - .then(() => { - // We only remove the user type from the database if there's an existing resource. - res.status(200).json({ message: `user-type with id: ${safe.data.id} deleted successfully` }); - }) - .catch((error) => { - // This catches the error thrown by prisma.user.delete() if the resource is not found. - res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`, error: error }); - }); - } else { + // We only remove the user type from the database if there's an existing resource. + if (user) res.status(200).json({ message: `user with id: ${safe.data.id} deleted successfully` }); + // This catches the error thrown by prisma.user.delete() if the resource is not found. + else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); // Reject any other HTTP method than POST - res.status(405).json({ message: "Only DELETE Method allowed in /user-types/[id]/delete endpoint" }); - } + } else res.status(405).json({ message: "Only DELETE Method allowed" }); } -export default withValidQueryIdTransformParseInt(user); +export default withValidQueryIdTransformParseInt(deleteUser); From c561b16f8585a9645707613909021deaad3efa6e Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 27 Mar 2022 01:19:49 +0100 Subject: [PATCH 033/658] chore: rename empty validations, enable relations on user zod object --- lib/validations/availability.ts | 2 +- lib/validations/booking-reference.ts | 64 +++--------------------- lib/validations/booking.ts | 42 +--------------- lib/validations/credential.ts | 64 +++--------------------- lib/validations/daily-event-reference.ts | 64 +++--------------------- lib/validations/destination-calendar.ts | 64 +++--------------------- lib/validations/eventType.ts | 2 +- lib/validations/membership.ts | 62 ++--------------------- lib/validations/payment.ts | 64 +++--------------------- lib/validations/schedule.ts | 64 +++--------------------- lib/validations/selected-calendar.ts | 64 +++--------------------- lib/validations/team.ts | 2 +- lib/validations/user.ts | 37 +++++++------- lib/validations/webhook.ts | 63 +++-------------------- 14 files changed, 76 insertions(+), 582 deletions(-) diff --git a/lib/validations/availability.ts b/lib/validations/availability.ts index b9ecf2fe20..d5fc7bbc25 100644 --- a/lib/validations/availability.ts +++ b/lib/validations/availability.ts @@ -55,7 +55,7 @@ const schemaAvailability = z // metadata: z.object({}).optional(), // verified: z.boolean().default(false), }) - .strict(); // Adding strict so that we can disallow passing in extra fields + .strict(); const withValidAvailability = withValidation({ schema: schemaAvailability, type: "Zod", diff --git a/lib/validations/booking-reference.ts b/lib/validations/booking-reference.ts index fb50c9c9ad..3a7298b9ac 100644 --- a/lib/validations/booking-reference.ts +++ b/lib/validations/booking-reference.ts @@ -1,65 +1,13 @@ import { withValidation } from "next-validations"; import { z } from "zod"; -const schemaBooking = z - .object({ - uid: z.string().min(3), - title: z.string().min(3), - description: z.string().min(3).optional(), - startTime: z.date().or(z.string()), - endTime: z.date(), - location: z.string().min(3).optional(), - createdAt: z.date().or(z.string()), - updatedAt: z.date(), - confirmed: z.boolean().default(true), - rejected: z.boolean().default(false), - paid: z.boolean().default(false), - - // bufferTime: z.number().default(0), - // // attendees: z.array((schemaSchedule)).optional(), - - // startTime: z.string().min(3), - // endTime: z.string().min(3), - // email: z.string().email(), // max is a full day. - // emailVerified: z.date().optional(), - // password: z.string().optional(), - // bio: z.string().min(3).optional(), - // avatar: z.string().optional(), - // timeZone: z.string().default("Europe/London"), - // weekStart: z.string().default("Sunday"), - // bufferTime: z.number().default(0), - // theme: z.string().optional(), - // trialEndsAt: z.date().optional(), - // eventTypes: z.array((schemaEventType)).optional(), - // // credentials: z.array((schemaCredentials)).optional(), - // // teams: z.array((schemaMembership)).optional(), - // // bookings: z.array((schemaBooking)).optional(), - // // schedules: z.array((schemaSchedule)).optional(), - // defaultScheduleId: z.number().optional(), - // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), - // completedOnboarding: z.boolean().default(false), - // locale: z.string().optional(), - // timeFormat: z.number().optional().default(12), - // twoFactorEnabled: z.boolean().default(false), - // twoFactorSecret: z.string().optional(), - // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), - // identityProviderId: z.string().optional(), - // // availavility: z.array((schemaAvailavility)).optional(), - // invitedTo: z.number().optional(), - // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), - // // webhooks: z.array((schemaWebhook)).optional(), - // brandColor: z.string().default("#292929"), - // darkBrandColor: z.string().default("#fafafa"), - // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here - // away: z.boolean().default(false), - // metadata: z.object({}).optional(), - // verified: z.boolean().default(false), - }) - .strict(); // Adding strict so that we can disallow passing in extra fields -const withValidBooking = withValidation({ - schema: schemaBooking, +const schemaBookingReference = z + .object({}) + .strict(); +const withValidBookingReference = withValidation({ + schema: schemaBookingReference, type: "Zod", mode: "body", }); -export { schemaBooking, withValidBooking }; +export { schemaBookingReference, withValidBookingReference }; diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index fb50c9c9ad..3959ad9b24 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -14,48 +14,8 @@ const schemaBooking = z confirmed: z.boolean().default(true), rejected: z.boolean().default(false), paid: z.boolean().default(false), - - // bufferTime: z.number().default(0), - // // attendees: z.array((schemaSchedule)).optional(), - - // startTime: z.string().min(3), - // endTime: z.string().min(3), - // email: z.string().email(), // max is a full day. - // emailVerified: z.date().optional(), - // password: z.string().optional(), - // bio: z.string().min(3).optional(), - // avatar: z.string().optional(), - // timeZone: z.string().default("Europe/London"), - // weekStart: z.string().default("Sunday"), - // bufferTime: z.number().default(0), - // theme: z.string().optional(), - // trialEndsAt: z.date().optional(), - // eventTypes: z.array((schemaEventType)).optional(), - // // credentials: z.array((schemaCredentials)).optional(), - // // teams: z.array((schemaMembership)).optional(), - // // bookings: z.array((schemaBooking)).optional(), - // // schedules: z.array((schemaSchedule)).optional(), - // defaultScheduleId: z.number().optional(), - // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), - // completedOnboarding: z.boolean().default(false), - // locale: z.string().optional(), - // timeFormat: z.number().optional().default(12), - // twoFactorEnabled: z.boolean().default(false), - // twoFactorSecret: z.string().optional(), - // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), - // identityProviderId: z.string().optional(), - // // availavility: z.array((schemaAvailavility)).optional(), - // invitedTo: z.number().optional(), - // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), - // // webhooks: z.array((schemaWebhook)).optional(), - // brandColor: z.string().default("#292929"), - // darkBrandColor: z.string().default("#fafafa"), - // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here - // away: z.boolean().default(false), - // metadata: z.object({}).optional(), - // verified: z.boolean().default(false), }) - .strict(); // Adding strict so that we can disallow passing in extra fields + .strict(); const withValidBooking = withValidation({ schema: schemaBooking, type: "Zod", diff --git a/lib/validations/credential.ts b/lib/validations/credential.ts index fb50c9c9ad..b0b142bfd3 100644 --- a/lib/validations/credential.ts +++ b/lib/validations/credential.ts @@ -1,65 +1,13 @@ import { withValidation } from "next-validations"; import { z } from "zod"; -const schemaBooking = z - .object({ - uid: z.string().min(3), - title: z.string().min(3), - description: z.string().min(3).optional(), - startTime: z.date().or(z.string()), - endTime: z.date(), - location: z.string().min(3).optional(), - createdAt: z.date().or(z.string()), - updatedAt: z.date(), - confirmed: z.boolean().default(true), - rejected: z.boolean().default(false), - paid: z.boolean().default(false), - - // bufferTime: z.number().default(0), - // // attendees: z.array((schemaSchedule)).optional(), - - // startTime: z.string().min(3), - // endTime: z.string().min(3), - // email: z.string().email(), // max is a full day. - // emailVerified: z.date().optional(), - // password: z.string().optional(), - // bio: z.string().min(3).optional(), - // avatar: z.string().optional(), - // timeZone: z.string().default("Europe/London"), - // weekStart: z.string().default("Sunday"), - // bufferTime: z.number().default(0), - // theme: z.string().optional(), - // trialEndsAt: z.date().optional(), - // eventTypes: z.array((schemaEventType)).optional(), - // // credentials: z.array((schemaCredentials)).optional(), - // // teams: z.array((schemaMembership)).optional(), - // // bookings: z.array((schemaBooking)).optional(), - // // schedules: z.array((schemaSchedule)).optional(), - // defaultScheduleId: z.number().optional(), - // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), - // completedOnboarding: z.boolean().default(false), - // locale: z.string().optional(), - // timeFormat: z.number().optional().default(12), - // twoFactorEnabled: z.boolean().default(false), - // twoFactorSecret: z.string().optional(), - // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), - // identityProviderId: z.string().optional(), - // // availavility: z.array((schemaAvailavility)).optional(), - // invitedTo: z.number().optional(), - // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), - // // webhooks: z.array((schemaWebhook)).optional(), - // brandColor: z.string().default("#292929"), - // darkBrandColor: z.string().default("#fafafa"), - // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here - // away: z.boolean().default(false), - // metadata: z.object({}).optional(), - // verified: z.boolean().default(false), - }) - .strict(); // Adding strict so that we can disallow passing in extra fields -const withValidBooking = withValidation({ - schema: schemaBooking, +const schemaCredential = z + .object({}) + .strict(); +const withValidCredential = withValidation({ + schema: schemaCredential, type: "Zod", mode: "body", }); -export { schemaBooking, withValidBooking }; +export { schemaCredential, withValidCredential }; diff --git a/lib/validations/daily-event-reference.ts b/lib/validations/daily-event-reference.ts index fb50c9c9ad..48a8a93e62 100644 --- a/lib/validations/daily-event-reference.ts +++ b/lib/validations/daily-event-reference.ts @@ -1,65 +1,13 @@ import { withValidation } from "next-validations"; import { z } from "zod"; -const schemaBooking = z - .object({ - uid: z.string().min(3), - title: z.string().min(3), - description: z.string().min(3).optional(), - startTime: z.date().or(z.string()), - endTime: z.date(), - location: z.string().min(3).optional(), - createdAt: z.date().or(z.string()), - updatedAt: z.date(), - confirmed: z.boolean().default(true), - rejected: z.boolean().default(false), - paid: z.boolean().default(false), - - // bufferTime: z.number().default(0), - // // attendees: z.array((schemaSchedule)).optional(), - - // startTime: z.string().min(3), - // endTime: z.string().min(3), - // email: z.string().email(), // max is a full day. - // emailVerified: z.date().optional(), - // password: z.string().optional(), - // bio: z.string().min(3).optional(), - // avatar: z.string().optional(), - // timeZone: z.string().default("Europe/London"), - // weekStart: z.string().default("Sunday"), - // bufferTime: z.number().default(0), - // theme: z.string().optional(), - // trialEndsAt: z.date().optional(), - // eventTypes: z.array((schemaEventType)).optional(), - // // credentials: z.array((schemaCredentials)).optional(), - // // teams: z.array((schemaMembership)).optional(), - // // bookings: z.array((schemaBooking)).optional(), - // // schedules: z.array((schemaSchedule)).optional(), - // defaultScheduleId: z.number().optional(), - // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), - // completedOnboarding: z.boolean().default(false), - // locale: z.string().optional(), - // timeFormat: z.number().optional().default(12), - // twoFactorEnabled: z.boolean().default(false), - // twoFactorSecret: z.string().optional(), - // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), - // identityProviderId: z.string().optional(), - // // availavility: z.array((schemaAvailavility)).optional(), - // invitedTo: z.number().optional(), - // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), - // // webhooks: z.array((schemaWebhook)).optional(), - // brandColor: z.string().default("#292929"), - // darkBrandColor: z.string().default("#fafafa"), - // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here - // away: z.boolean().default(false), - // metadata: z.object({}).optional(), - // verified: z.boolean().default(false), - }) - .strict(); // Adding strict so that we can disallow passing in extra fields -const withValidBooking = withValidation({ - schema: schemaBooking, +const schemaDailyEventReference = z + .object({}) + .strict(); +const withValidDailyEventReference = withValidation({ + schema: schemaDailyEventReference, type: "Zod", mode: "body", }); -export { schemaBooking, withValidBooking }; +export { schemaDailyEventReference, withValidDailyEventReference }; diff --git a/lib/validations/destination-calendar.ts b/lib/validations/destination-calendar.ts index fb50c9c9ad..34fa856897 100644 --- a/lib/validations/destination-calendar.ts +++ b/lib/validations/destination-calendar.ts @@ -1,65 +1,13 @@ import { withValidation } from "next-validations"; import { z } from "zod"; -const schemaBooking = z - .object({ - uid: z.string().min(3), - title: z.string().min(3), - description: z.string().min(3).optional(), - startTime: z.date().or(z.string()), - endTime: z.date(), - location: z.string().min(3).optional(), - createdAt: z.date().or(z.string()), - updatedAt: z.date(), - confirmed: z.boolean().default(true), - rejected: z.boolean().default(false), - paid: z.boolean().default(false), - - // bufferTime: z.number().default(0), - // // attendees: z.array((schemaSchedule)).optional(), - - // startTime: z.string().min(3), - // endTime: z.string().min(3), - // email: z.string().email(), // max is a full day. - // emailVerified: z.date().optional(), - // password: z.string().optional(), - // bio: z.string().min(3).optional(), - // avatar: z.string().optional(), - // timeZone: z.string().default("Europe/London"), - // weekStart: z.string().default("Sunday"), - // bufferTime: z.number().default(0), - // theme: z.string().optional(), - // trialEndsAt: z.date().optional(), - // eventTypes: z.array((schemaEventType)).optional(), - // // credentials: z.array((schemaCredentials)).optional(), - // // teams: z.array((schemaMembership)).optional(), - // // bookings: z.array((schemaBooking)).optional(), - // // schedules: z.array((schemaSchedule)).optional(), - // defaultScheduleId: z.number().optional(), - // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), - // completedOnboarding: z.boolean().default(false), - // locale: z.string().optional(), - // timeFormat: z.number().optional().default(12), - // twoFactorEnabled: z.boolean().default(false), - // twoFactorSecret: z.string().optional(), - // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), - // identityProviderId: z.string().optional(), - // // availavility: z.array((schemaAvailavility)).optional(), - // invitedTo: z.number().optional(), - // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), - // // webhooks: z.array((schemaWebhook)).optional(), - // brandColor: z.string().default("#292929"), - // darkBrandColor: z.string().default("#fafafa"), - // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here - // away: z.boolean().default(false), - // metadata: z.object({}).optional(), - // verified: z.boolean().default(false), - }) - .strict(); // Adding strict so that we can disallow passing in extra fields -const withValidBooking = withValidation({ - schema: schemaBooking, +const schemaDestinationCalendar = z + .object({}) + .strict(); +const withValidDestinationCalendar = withValidation({ + schema: schemaDestinationCalendar, type: "Zod", mode: "body", }); -export { schemaBooking, withValidBooking }; +export { schemaDestinationCalendar, withValidDestinationCalendar }; diff --git a/lib/validations/eventType.ts b/lib/validations/eventType.ts index d9be43a1e2..34764a21ee 100644 --- a/lib/validations/eventType.ts +++ b/lib/validations/eventType.ts @@ -8,7 +8,7 @@ const schemaEventType = z length: z.number().min(1).max(1440), // max is a full day. description: z.string().min(3).optional(), }) - .strict(); // Adding strict so that we can disallow passing in extra fields + .strict(); const withValidEventType = withValidation({ schema: schemaEventType, type: "Zod", diff --git a/lib/validations/membership.ts b/lib/validations/membership.ts index fb50c9c9ad..4959dafb8a 100644 --- a/lib/validations/membership.ts +++ b/lib/validations/membership.ts @@ -1,65 +1,13 @@ import { withValidation } from "next-validations"; import { z } from "zod"; -const schemaBooking = z - .object({ - uid: z.string().min(3), - title: z.string().min(3), - description: z.string().min(3).optional(), - startTime: z.date().or(z.string()), - endTime: z.date(), - location: z.string().min(3).optional(), - createdAt: z.date().or(z.string()), - updatedAt: z.date(), - confirmed: z.boolean().default(true), - rejected: z.boolean().default(false), - paid: z.boolean().default(false), - - // bufferTime: z.number().default(0), - // // attendees: z.array((schemaSchedule)).optional(), - - // startTime: z.string().min(3), - // endTime: z.string().min(3), - // email: z.string().email(), // max is a full day. - // emailVerified: z.date().optional(), - // password: z.string().optional(), - // bio: z.string().min(3).optional(), - // avatar: z.string().optional(), - // timeZone: z.string().default("Europe/London"), - // weekStart: z.string().default("Sunday"), - // bufferTime: z.number().default(0), - // theme: z.string().optional(), - // trialEndsAt: z.date().optional(), - // eventTypes: z.array((schemaEventType)).optional(), - // // credentials: z.array((schemaCredentials)).optional(), - // // teams: z.array((schemaMembership)).optional(), - // // bookings: z.array((schemaBooking)).optional(), - // // schedules: z.array((schemaSchedule)).optional(), - // defaultScheduleId: z.number().optional(), - // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), - // completedOnboarding: z.boolean().default(false), - // locale: z.string().optional(), - // timeFormat: z.number().optional().default(12), - // twoFactorEnabled: z.boolean().default(false), - // twoFactorSecret: z.string().optional(), - // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), - // identityProviderId: z.string().optional(), - // // availavility: z.array((schemaAvailavility)).optional(), - // invitedTo: z.number().optional(), - // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), - // // webhooks: z.array((schemaWebhook)).optional(), - // brandColor: z.string().default("#292929"), - // darkBrandColor: z.string().default("#fafafa"), - // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here - // away: z.boolean().default(false), - // metadata: z.object({}).optional(), - // verified: z.boolean().default(false), - }) +const schemaMembership = z + .object({}) .strict(); // Adding strict so that we can disallow passing in extra fields -const withValidBooking = withValidation({ - schema: schemaBooking, +const withValidMembership = withValidation({ + schema: schemaMembership, type: "Zod", mode: "body", }); -export { schemaBooking, withValidBooking }; +export { schemaMembership, withValidMembership }; diff --git a/lib/validations/payment.ts b/lib/validations/payment.ts index fb50c9c9ad..b9f019fe0d 100644 --- a/lib/validations/payment.ts +++ b/lib/validations/payment.ts @@ -1,65 +1,13 @@ import { withValidation } from "next-validations"; import { z } from "zod"; -const schemaBooking = z - .object({ - uid: z.string().min(3), - title: z.string().min(3), - description: z.string().min(3).optional(), - startTime: z.date().or(z.string()), - endTime: z.date(), - location: z.string().min(3).optional(), - createdAt: z.date().or(z.string()), - updatedAt: z.date(), - confirmed: z.boolean().default(true), - rejected: z.boolean().default(false), - paid: z.boolean().default(false), - - // bufferTime: z.number().default(0), - // // attendees: z.array((schemaSchedule)).optional(), - - // startTime: z.string().min(3), - // endTime: z.string().min(3), - // email: z.string().email(), // max is a full day. - // emailVerified: z.date().optional(), - // password: z.string().optional(), - // bio: z.string().min(3).optional(), - // avatar: z.string().optional(), - // timeZone: z.string().default("Europe/London"), - // weekStart: z.string().default("Sunday"), - // bufferTime: z.number().default(0), - // theme: z.string().optional(), - // trialEndsAt: z.date().optional(), - // eventTypes: z.array((schemaEventType)).optional(), - // // credentials: z.array((schemaCredentials)).optional(), - // // teams: z.array((schemaMembership)).optional(), - // // bookings: z.array((schemaBooking)).optional(), - // // schedules: z.array((schemaSchedule)).optional(), - // defaultScheduleId: z.number().optional(), - // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), - // completedOnboarding: z.boolean().default(false), - // locale: z.string().optional(), - // timeFormat: z.number().optional().default(12), - // twoFactorEnabled: z.boolean().default(false), - // twoFactorSecret: z.string().optional(), - // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), - // identityProviderId: z.string().optional(), - // // availavility: z.array((schemaAvailavility)).optional(), - // invitedTo: z.number().optional(), - // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), - // // webhooks: z.array((schemaWebhook)).optional(), - // brandColor: z.string().default("#292929"), - // darkBrandColor: z.string().default("#fafafa"), - // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here - // away: z.boolean().default(false), - // metadata: z.object({}).optional(), - // verified: z.boolean().default(false), - }) - .strict(); // Adding strict so that we can disallow passing in extra fields -const withValidBooking = withValidation({ - schema: schemaBooking, +const schemaPayment = z + .object({}) + .strict(); +const withValidPayment = withValidation({ + schema: schemaPayment, type: "Zod", mode: "body", }); -export { schemaBooking, withValidBooking }; +export { schemaPayment, withValidPayment }; diff --git a/lib/validations/schedule.ts b/lib/validations/schedule.ts index fb50c9c9ad..9a0b0f286f 100644 --- a/lib/validations/schedule.ts +++ b/lib/validations/schedule.ts @@ -1,65 +1,13 @@ import { withValidation } from "next-validations"; import { z } from "zod"; -const schemaBooking = z - .object({ - uid: z.string().min(3), - title: z.string().min(3), - description: z.string().min(3).optional(), - startTime: z.date().or(z.string()), - endTime: z.date(), - location: z.string().min(3).optional(), - createdAt: z.date().or(z.string()), - updatedAt: z.date(), - confirmed: z.boolean().default(true), - rejected: z.boolean().default(false), - paid: z.boolean().default(false), - - // bufferTime: z.number().default(0), - // // attendees: z.array((schemaSchedule)).optional(), - - // startTime: z.string().min(3), - // endTime: z.string().min(3), - // email: z.string().email(), // max is a full day. - // emailVerified: z.date().optional(), - // password: z.string().optional(), - // bio: z.string().min(3).optional(), - // avatar: z.string().optional(), - // timeZone: z.string().default("Europe/London"), - // weekStart: z.string().default("Sunday"), - // bufferTime: z.number().default(0), - // theme: z.string().optional(), - // trialEndsAt: z.date().optional(), - // eventTypes: z.array((schemaEventType)).optional(), - // // credentials: z.array((schemaCredentials)).optional(), - // // teams: z.array((schemaMembership)).optional(), - // // bookings: z.array((schemaBooking)).optional(), - // // schedules: z.array((schemaSchedule)).optional(), - // defaultScheduleId: z.number().optional(), - // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), - // completedOnboarding: z.boolean().default(false), - // locale: z.string().optional(), - // timeFormat: z.number().optional().default(12), - // twoFactorEnabled: z.boolean().default(false), - // twoFactorSecret: z.string().optional(), - // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), - // identityProviderId: z.string().optional(), - // // availavility: z.array((schemaAvailavility)).optional(), - // invitedTo: z.number().optional(), - // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), - // // webhooks: z.array((schemaWebhook)).optional(), - // brandColor: z.string().default("#292929"), - // darkBrandColor: z.string().default("#fafafa"), - // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here - // away: z.boolean().default(false), - // metadata: z.object({}).optional(), - // verified: z.boolean().default(false), - }) - .strict(); // Adding strict so that we can disallow passing in extra fields -const withValidBooking = withValidation({ - schema: schemaBooking, +const schemaSchedule = z + .object({}) + .strict(); +const withValidSchedule = withValidation({ + schema: schemaSchedule, type: "Zod", mode: "body", }); -export { schemaBooking, withValidBooking }; +export { schemaSchedule, withValidSchedule }; diff --git a/lib/validations/selected-calendar.ts b/lib/validations/selected-calendar.ts index fb50c9c9ad..b1646e1047 100644 --- a/lib/validations/selected-calendar.ts +++ b/lib/validations/selected-calendar.ts @@ -1,65 +1,13 @@ import { withValidation } from "next-validations"; import { z } from "zod"; -const schemaBooking = z - .object({ - uid: z.string().min(3), - title: z.string().min(3), - description: z.string().min(3).optional(), - startTime: z.date().or(z.string()), - endTime: z.date(), - location: z.string().min(3).optional(), - createdAt: z.date().or(z.string()), - updatedAt: z.date(), - confirmed: z.boolean().default(true), - rejected: z.boolean().default(false), - paid: z.boolean().default(false), - - // bufferTime: z.number().default(0), - // // attendees: z.array((schemaSchedule)).optional(), - - // startTime: z.string().min(3), - // endTime: z.string().min(3), - // email: z.string().email(), // max is a full day. - // emailVerified: z.date().optional(), - // password: z.string().optional(), - // bio: z.string().min(3).optional(), - // avatar: z.string().optional(), - // timeZone: z.string().default("Europe/London"), - // weekStart: z.string().default("Sunday"), - // bufferTime: z.number().default(0), - // theme: z.string().optional(), - // trialEndsAt: z.date().optional(), - // eventTypes: z.array((schemaEventType)).optional(), - // // credentials: z.array((schemaCredentials)).optional(), - // // teams: z.array((schemaMembership)).optional(), - // // bookings: z.array((schemaBooking)).optional(), - // // schedules: z.array((schemaSchedule)).optional(), - // defaultScheduleId: z.number().optional(), - // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), - // completedOnboarding: z.boolean().default(false), - // locale: z.string().optional(), - // timeFormat: z.number().optional().default(12), - // twoFactorEnabled: z.boolean().default(false), - // twoFactorSecret: z.string().optional(), - // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), - // identityProviderId: z.string().optional(), - // // availavility: z.array((schemaAvailavility)).optional(), - // invitedTo: z.number().optional(), - // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), - // // webhooks: z.array((schemaWebhook)).optional(), - // brandColor: z.string().default("#292929"), - // darkBrandColor: z.string().default("#fafafa"), - // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here - // away: z.boolean().default(false), - // metadata: z.object({}).optional(), - // verified: z.boolean().default(false), - }) - .strict(); // Adding strict so that we can disallow passing in extra fields -const withValidBooking = withValidation({ - schema: schemaBooking, +const schemaSelectedCalendar = z + .object({}) + .strict(); +const withValidSelectedCalendar = withValidation({ + schema: schemaSelectedCalendar, type: "Zod", mode: "body", }); -export { schemaBooking, withValidBooking }; +export { schemaSelectedCalendar, withValidSelectedCalendar }; diff --git a/lib/validations/team.ts b/lib/validations/team.ts index 9ed08f90d5..935f49ac1e 100644 --- a/lib/validations/team.ts +++ b/lib/validations/team.ts @@ -9,7 +9,7 @@ const schemaTeam = z bio: z.string().min(3).optional(), logo: z.string().optional(), }) - .strict(); // Adding strict so that we can disallow passing in extra fields + .strict(); const withValidTeam = withValidation({ schema: schemaTeam, type: "Zod", diff --git a/lib/validations/user.ts b/lib/validations/user.ts index 4b24b168af..b0fd00848c 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -1,15 +1,16 @@ import { withValidation } from "next-validations"; -import { schemaEventType } from "./eventType"; -// import { schemaCredential } from "./credential"; -// import { schemaMembership } from "./membership"; -// import { schemaBooking } from "./booking"; -// import { schemaSchedule } from "./schedule"; -// import { schemaSelectedCalendar } from "./selectedCalendar"; -// import { schemaAvailability } from "./availability"; -// import { schemaWebhook } from "./webhook"; - import { z } from "zod"; + +import { schemaEventType } from "./eventType"; import { schemaApiKey } from "./apiKey"; +import { schemaDestinationCalendar } from "./destination-calendar"; +import { schemaWebhook } from "./webhook"; +import { schemaAvailability } from "./availability"; +import { schemaSelectedCalendar } from "./selected-calendar"; +import { schemaBooking } from "./booking"; +import { schemaMembership } from "./membership"; +import { schemaSchedule } from "./schedule"; +import { schemaCredential } from "./credential"; const schemaUser = z .object({ @@ -27,12 +28,12 @@ const schemaUser = z theme: z.string().optional(), trialEndsAt: z.date().optional(), eventTypes: z.array((schemaEventType)).optional(), - // credentials: z.array((schemaCredentials)).optional(), - // teams: z.array((schemaMembership)).optional(), - // bookings: z.array((schemaBooking)).optional(), - // schedules: z.array((schemaSchedule)).optional(), + credentials: z.array((schemaCredential)).optional(), + teams: z.array((schemaMembership)).optional(), + bookings: z.array((schemaBooking)).optional(), + schedules: z.array((schemaSchedule)).optional(), defaultScheduleId: z.number().optional(), - // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), + selectedCalendars: z.array((schemaSelectedCalendar)).optional(), completedOnboarding: z.boolean().default(false), locale: z.string().optional(), timeFormat: z.number().optional().default(12), @@ -40,19 +41,19 @@ const schemaUser = z twoFactorSecret: z.string().optional(), identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), identityProviderId: z.string().optional(), - // availavility: z.array((schemaAvailavility)).optional(), + availability: z.array((schemaAvailability)).optional(), invitedTo: z.number().optional(), plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), - // webhooks: z.array((schemaWebhook)).optional(), + webhooks: z.array((schemaWebhook)).optional(), brandColor: z.string().default("#292929"), darkBrandColor: z.string().default("#fafafa"), - // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here + destinationCalendar: z.array(schemaDestinationCalendar).optional(), // FIXME: instanceof doesnt work here away: z.boolean().default(false), metadata: z.object({}).optional(), verified: z.boolean().default(false), apiKeys: z.array((schemaApiKey)).optional(), }) - .strict(); // Adding strict so that we can disallow passing in extra fields + .strict(); const withValidUser = withValidation({ schema: schemaUser, type: "Zod", diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index fb50c9c9ad..1b1a35a2da 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -1,65 +1,14 @@ import { withValidation } from "next-validations"; import { z } from "zod"; -const schemaBooking = z - .object({ - uid: z.string().min(3), - title: z.string().min(3), - description: z.string().min(3).optional(), - startTime: z.date().or(z.string()), - endTime: z.date(), - location: z.string().min(3).optional(), - createdAt: z.date().or(z.string()), - updatedAt: z.date(), - confirmed: z.boolean().default(true), - rejected: z.boolean().default(false), - paid: z.boolean().default(false), +const schemaWebhook = z + .object({}) + .strict(); - // bufferTime: z.number().default(0), - // // attendees: z.array((schemaSchedule)).optional(), - - // startTime: z.string().min(3), - // endTime: z.string().min(3), - // email: z.string().email(), // max is a full day. - // emailVerified: z.date().optional(), - // password: z.string().optional(), - // bio: z.string().min(3).optional(), - // avatar: z.string().optional(), - // timeZone: z.string().default("Europe/London"), - // weekStart: z.string().default("Sunday"), - // bufferTime: z.number().default(0), - // theme: z.string().optional(), - // trialEndsAt: z.date().optional(), - // eventTypes: z.array((schemaEventType)).optional(), - // // credentials: z.array((schemaCredentials)).optional(), - // // teams: z.array((schemaMembership)).optional(), - // // bookings: z.array((schemaBooking)).optional(), - // // schedules: z.array((schemaSchedule)).optional(), - // defaultScheduleId: z.number().optional(), - // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), - // completedOnboarding: z.boolean().default(false), - // locale: z.string().optional(), - // timeFormat: z.number().optional().default(12), - // twoFactorEnabled: z.boolean().default(false), - // twoFactorSecret: z.string().optional(), - // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), - // identityProviderId: z.string().optional(), - // // availavility: z.array((schemaAvailavility)).optional(), - // invitedTo: z.number().optional(), - // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), - // // webhooks: z.array((schemaWebhook)).optional(), - // brandColor: z.string().default("#292929"), - // darkBrandColor: z.string().default("#fafafa"), - // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here - // away: z.boolean().default(false), - // metadata: z.object({}).optional(), - // verified: z.boolean().default(false), - }) - .strict(); // Adding strict so that we can disallow passing in extra fields -const withValidBooking = withValidation({ - schema: schemaBooking, +const withValidWebhook = withValidation({ + schema: schemaWebhook, type: "Zod", mode: "body", }); -export { schemaBooking, withValidBooking }; +export { schemaWebhook, withValidWebhook }; From 0e3131d8665bd17727ef02bb13ba01abf1c571bd Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 27 Mar 2022 15:15:46 +0200 Subject: [PATCH 034/658] feat: improve validations --- lib/validations/apiKey.ts | 3 +- lib/validations/availability.ts | 60 ++++--------------------- lib/validations/booking.ts | 2 +- lib/validations/membership.ts | 2 +- pages/api/attendees/[id]/delete.ts | 2 +- pages/api/availabilities/[id]/delete.ts | 5 +-- 6 files changed, 15 insertions(+), 59 deletions(-) diff --git a/lib/validations/apiKey.ts b/lib/validations/apiKey.ts index 044e3768f3..a8d89d78f3 100644 --- a/lib/validations/apiKey.ts +++ b/lib/validations/apiKey.ts @@ -9,8 +9,7 @@ const schemaApiKey = z expiresAt: z.date().optional(), // default is 30 days note: z.string().min(1).optional(), }) - .strict(); - + .strict(); // Adding strict so that we can disallow passing in extra fields const withValidApiKey = withValidation({ schema: schemaApiKey, type: "Zod", diff --git a/lib/validations/availability.ts b/lib/validations/availability.ts index d5fc7bbc25..1bffc5acec 100644 --- a/lib/validations/availability.ts +++ b/lib/validations/availability.ts @@ -3,57 +3,15 @@ import { z } from "zod"; const schemaAvailability = z .object({ - uid: z.string().min(3), - title: z.string().min(3), - description: z.string().min(3).optional(), - startTime: z.date().or(z.string()), - endTime: z.date(), - location: z.string().min(3).optional(), - createdAt: z.date().or(z.string()), - updatedAt: z.date(), - confirmed: z.boolean().default(true), - rejected: z.boolean().default(false), - paid: z.boolean().default(false), - - // bufferTime: z.number().default(0), - // // attendees: z.array((schemaSchedule)).optional(), - - // startTime: z.string().min(3), - // endTime: z.string().min(3), - // email: z.string().email(), // max is a full day. - // emailVerified: z.date().optional(), - // password: z.string().optional(), - // bio: z.string().min(3).optional(), - // avatar: z.string().optional(), - // timeZone: z.string().default("Europe/London"), - // weekStart: z.string().default("Sunday"), - // bufferTime: z.number().default(0), - // theme: z.string().optional(), - // trialEndsAt: z.date().optional(), - // eventTypes: z.array((schemaEventType)).optional(), - // // credentials: z.array((schemaCredentials)).optional(), - // // teams: z.array((schemaMembership)).optional(), - // // bookings: z.array((schemaAvailability)).optional(), - // // schedules: z.array((schemaSchedule)).optional(), - // defaultScheduleId: z.number().optional(), - // // selectedCalendars: z.array((schemaSelectedCalendar)).optional(), - // completedOnboarding: z.boolean().default(false), - // locale: z.string().optional(), - // timeFormat: z.number().optional().default(12), - // twoFactorEnabled: z.boolean().default(false), - // twoFactorSecret: z.string().optional(), - // identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), - // identityProviderId: z.string().optional(), - // // availavility: z.array((schemaAvailavility)).optional(), - // invitedTo: z.number().optional(), - // plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), - // // webhooks: z.array((schemaWebhook)).optional(), - // brandColor: z.string().default("#292929"), - // darkBrandColor: z.string().default("#fafafa"), - // // destinationCalendar: z.instanceof(schemaEventType).optional(), // FIXME: instanceof doesnt work here - // away: z.boolean().default(false), - // metadata: z.object({}).optional(), - // verified: z.boolean().default(false), + id: z.number(), + userId: z.number(), + eventTypeId: z.number(), + scheduleId: z.number(), + + days: z.array(z.number()), + date: z.date().or(z.string()), + startTime: z.string(), + endTime: z.string(), }) .strict(); const withValidAvailability = withValidation({ diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index 3959ad9b24..7c07aac283 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -10,7 +10,7 @@ const schemaBooking = z endTime: z.date(), location: z.string().min(3).optional(), createdAt: z.date().or(z.string()), - updatedAt: z.date(), + updatedAt: z.date().or(z.string()), confirmed: z.boolean().default(true), rejected: z.boolean().default(false), paid: z.boolean().default(false), diff --git a/lib/validations/membership.ts b/lib/validations/membership.ts index 4959dafb8a..3d52743955 100644 --- a/lib/validations/membership.ts +++ b/lib/validations/membership.ts @@ -3,7 +3,7 @@ import { z } from "zod"; const schemaMembership = z .object({}) - .strict(); // Adding strict so that we can disallow passing in extra fields + .strict(); const withValidMembership = withValidation({ schema: schemaMembership, type: "Zod", diff --git a/pages/api/attendees/[id]/delete.ts b/pages/api/attendees/[id]/delete.ts index 47b4a783b7..21c0efaff4 100644 --- a/pages/api/attendees/[id]/delete.ts +++ b/pages/api/attendees/[id]/delete.ts @@ -21,7 +21,7 @@ export async function attendee(req: NextApiRequest, res: NextApiResponse Date: Mon, 28 Mar 2022 02:51:40 +0200 Subject: [PATCH 035/658] Adds basic api-key auth in users, need to extract out --- lib/utils/stringifyISODate.ts | 5 +---- pages/_middleware.ts | 12 ++++++++++++ pages/api/users/index.ts | 31 ++++++++++++++++++++++++------- pages/api/users/new.ts | 12 ++++-------- tsconfig.json | 3 ++- 5 files changed, 43 insertions(+), 20 deletions(-) create mode 100644 pages/_middleware.ts diff --git a/lib/utils/stringifyISODate.ts b/lib/utils/stringifyISODate.ts index bb2ec71339..17be60bed7 100644 --- a/lib/utils/stringifyISODate.ts +++ b/lib/utils/stringifyISODate.ts @@ -1,7 +1,4 @@ export const stringifyISODate = (date: Date|undefined): string => { return `${date?.toISOString()}` } -// FIXME: debug this, supposed to take an array/object and auto strinfy date-like values -export const autoStringifyDateValues = ([key, value]: [string, unknown]): [string, unknown] => { - return [key, typeof value === "object" && value instanceof Date ? stringifyISODate(value) : value] -} \ No newline at end of file +// TODO: create a function that takes an object and returns a stringified version of dates of it. \ No newline at end of file diff --git a/pages/_middleware.ts b/pages/_middleware.ts new file mode 100644 index 0000000000..d79b68edb6 --- /dev/null +++ b/pages/_middleware.ts @@ -0,0 +1,12 @@ +import { NextRequest, NextResponse } from 'next/server' +// Not much useful yet as prisma.client can't be used in the middlewares (client is not available) +// For now we just throw early if no apiKey is passed, +// but we could also check if the apiKey is valid if we had prisma here. +export async function middleware({ nextUrl }: NextRequest, res: NextResponse) { + const response = NextResponse.next() + const apiKey = nextUrl.searchParams.get('apiKey'); + + if (apiKey) return response + // if no apiKey is passed, we throw early + else throw new Error('You need to pass an apiKey as query param: https://api.cal.com/resource?apiKey=') +} diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 33afee9f5e..dd3665cf14 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -7,13 +7,30 @@ type ResponseData = { data?: User[]; error?: unknown; }; +const dateInPast = function (firstDate: Date, secondDate: Date) { + if (firstDate.setHours(0, 0, 0, 0) <= secondDate.setHours(0, 0, 0, 0)) { + return true; + } + + return false; +}; +const today = new Date(); export default async function user(req: NextApiRequest, res: NextApiResponse) { - try { - const users = await prisma.user.findMany(); - res.status(200).json({ data: { ...users } }); - } catch (error) { - // FIXME: Add zod for validation/error handling - res.status(400).json({ error: error }); - } + const apiKey = req.query.apiKey as string; + const apiInDb = await prisma.apiKey.findUnique({ where: { id: apiKey } }); + if (!apiInDb) throw new Error('API key not found'); + const { expiresAt } = apiInDb; + // if (!apiInDb) res.status(400).json({ error: 'Your api key is not valid' }); + if (expiresAt && dateInPast(expiresAt, today)) { + console.log(apiInDb) + try { + const users = await prisma.user.findMany(); + res.status(200).json({ data: { ...users } }); + } catch (error) { + // FIXME: Add zod for validation/error handling + res.status(400).json({ error: error }); + } + } else res.status(400).json({ error: 'Your api key is not valid' }); + } diff --git a/pages/api/users/new.ts b/pages/api/users/new.ts index 4eba163f6b..ae298fdfb3 100644 --- a/pages/api/users/new.ts +++ b/pages/api/users/new.ts @@ -13,18 +13,14 @@ type ResponseData = { async function createUser(req: NextApiRequest, res: NextApiResponse) { const { body, method } = req; - if (method === "POST") { - const safe = schemaUser.safeParse(body); - if (safe.success && safe.data) { + const safe = schemaUser.safeParse(body); + if (method === "POST" && safe.success) { await prisma.user .create({ data: safe.data }) .then((user) => res.status(201).json({ data: user })) .catch((error) => res.status(400).json({ message: "Could not create user type", error: error })); - } - } else { - // Reject any other HTTP method than POST - res.status(405).json({ error: "Only POST Method allowed" }); - } + // Reject any other HTTP method than POST + } else res.status(405).json({ error: "Only POST Method allowed" }); } export default withValidUser(createUser); diff --git a/tsconfig.json b/tsconfig.json index fd13c250c3..93bbf8be81 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -21,7 +21,8 @@ "jsx": "preserve", "paths": { "@api/*": ["pages/api/*"], - "@lib/*": ["lib/*"] + "@lib/*": ["lib/*"], + "@/*": ["*"] }, }, From 1241ae6cfc4adfaa1ef474a15b9b84d95a0930dc Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 28 Mar 2022 16:05:00 +0200 Subject: [PATCH 036/658] feat: move findAll to return arrays --- pages/api/api-keys/index.ts | 4 ++-- pages/api/attendees/index.ts | 4 ++-- pages/api/availabilities/index.ts | 4 ++-- pages/api/bookings/index.ts | 4 ++-- pages/api/event-types/index.ts | 4 ++-- pages/api/teams/index.ts | 4 ++-- pages/api/users/index.ts | 5 ++--- tests/api-keys/[id]/api-key.id.delete.test.ts | 2 -- 8 files changed, 14 insertions(+), 17 deletions(-) diff --git a/pages/api/api-keys/index.ts b/pages/api/api-keys/index.ts index 37a477f1bf..5155c36c59 100644 --- a/pages/api/api-keys/index.ts +++ b/pages/api/api-keys/index.ts @@ -12,7 +12,7 @@ type ResponseData = { export default async function apiKeys(req: NextApiRequest, res: NextApiResponse) { const { method } = req; if (method === "GET") { - const apiKeys = await prisma.apiKey.findMany({}); - res.status(200).json({ data: { ...apiKeys } }); + const data = await prisma.apiKey.findMany({}); + res.status(200).json({ data }); } else res.status(405).json({ message: "Only GET Method allowed" }); } diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index 121457759f..1a105dd52d 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -10,8 +10,8 @@ type ResponseData = { export default async function attendee(req: NextApiRequest, res: NextApiResponse) { try { - const attendees = await prisma.attendee.findMany(); - res.status(200).json({ data: { ...attendees } }); + const data = await prisma.attendee.findMany(); + res.status(200).json({ data }); } catch (error) { // FIXME: Add zod for validation/error handling res.status(400).json({ error: error }); diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index f529fd6ed2..79f591c06b 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -10,8 +10,8 @@ type ResponseData = { export default async function availability(req: NextApiRequest, res: NextApiResponse) { try { - const availabilities = await prisma.availability.findMany(); - res.status(200).json({ data: { ...availabilities } }); + const data = await prisma.availability.findMany(); + res.status(200).json({ data }); } catch (error) { // FIXME: Add zod for validation/error handling res.status(400).json({ error: error }); diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 20b9a41a7e..edfc31f1c1 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -10,8 +10,8 @@ type ResponseData = { export default async function booking(req: NextApiRequest, res: NextApiResponse) { try { - const bookings = await prisma.booking.findMany(); - res.status(200).json({ data: { ...bookings } }); + const data = await prisma.booking.findMany(); + res.status(200).json({ data }); } catch (error) { // FIXME: Add zod for validation/error handling res.status(400).json({ error: error }); diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 534ebf828f..348d6aca30 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -12,8 +12,8 @@ type ResponseData = { export default async function eventType(req: NextApiRequest, res: NextApiResponse) { const { method } = req; if (method === "GET") { - const eventTypes = await prisma.eventType.findMany(); - res.status(200).json({ data: { ...eventTypes } }); + const data = await prisma.eventType.findMany(); + res.status(200).json({ data }); } else { // Reject any other HTTP method than POST res.status(405).json({ message: "Only GET Method allowed" }); diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index d00f092c99..0b57f21604 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -10,8 +10,8 @@ type ResponseData = { export default async function team(req: NextApiRequest, res: NextApiResponse) { try { - const teams = await prisma.team.findMany(); - res.status(200).json({ data: { ...teams } }); + const data = await prisma.team.findMany(); + res.status(200).json({ data }); } catch (error) { // FIXME: Add zod for validation/error handling res.status(400).json({ error: error }); diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index dd3665cf14..1644c3906b 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -23,10 +23,9 @@ export default async function user(req: NextApiRequest, res: NextApiResponse Date: Mon, 28 Mar 2022 16:05:50 +0200 Subject: [PATCH 037/658] remove unused req --- pages/_middleware.ts | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/pages/_middleware.ts b/pages/_middleware.ts index d79b68edb6..c631934a91 100644 --- a/pages/_middleware.ts +++ b/pages/_middleware.ts @@ -1,12 +1,16 @@ -import { NextRequest, NextResponse } from 'next/server' -// Not much useful yet as prisma.client can't be used in the middlewares (client is not available) -// For now we just throw early if no apiKey is passed, -// but we could also check if the apiKey is valid if we had prisma here. -export async function middleware({ nextUrl }: NextRequest, res: NextResponse) { - const response = NextResponse.next() - const apiKey = nextUrl.searchParams.get('apiKey'); +import { NextRequest, NextResponse } from "next/server"; - if (apiKey) return response +// Not much useful yet as prisma.client can't be used in the middlewares (client is not available) +// For now we just throw early if no apiKey is passed, +// but we could also check if the apiKey is valid if we had prisma here. +export async function middleware({ nextUrl }: NextRequest) { + const response = NextResponse.next(); + const apiKey = nextUrl.searchParams.get("apiKey"); + + if (apiKey) return response; // if no apiKey is passed, we throw early - else throw new Error('You need to pass an apiKey as query param: https://api.cal.com/resource?apiKey=') + else + throw new Error( + "You need to pass an apiKey as query param: https://api.cal.com/resource?apiKey=" + ); } From 99d328c35dd98c7419f98ade49b261c399f0a5aa Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 28 Mar 2022 17:46:12 +0200 Subject: [PATCH 038/658] chore: refactor-out apiKey check into middleware --- lib/helpers | 35 +++++++++++++++++++++++++++++++++++ pages/api/users/index.ts | 30 +++++++----------------------- 2 files changed, 42 insertions(+), 23 deletions(-) create mode 100644 lib/helpers diff --git a/lib/helpers b/lib/helpers new file mode 100644 index 0000000000..1644c3906b --- /dev/null +++ b/lib/helpers @@ -0,0 +1,35 @@ +import prisma from "@calcom/prisma"; + +import { User } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +type ResponseData = { + data?: User[]; + error?: unknown; +}; +const dateInPast = function (firstDate: Date, secondDate: Date) { + if (firstDate.setHours(0, 0, 0, 0) <= secondDate.setHours(0, 0, 0, 0)) { + return true; + } + + return false; +}; +const today = new Date(); + +export default async function user(req: NextApiRequest, res: NextApiResponse) { + const apiKey = req.query.apiKey as string; + const apiInDb = await prisma.apiKey.findUnique({ where: { id: apiKey } }); + if (!apiInDb) throw new Error('API key not found'); + const { expiresAt } = apiInDb; + // if (!apiInDb) res.status(400).json({ error: 'Your api key is not valid' }); + if (expiresAt && dateInPast(expiresAt, today)) { + try { + const data = await prisma.user.findMany(); + res.status(200).json({ data }); + } catch (error) { + // FIXME: Add zod for validation/error handling + res.status(400).json({ error: error }); + } + } else res.status(400).json({ error: 'Your api key is not valid' }); + +} diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 1644c3906b..33afee9f5e 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -7,29 +7,13 @@ type ResponseData = { data?: User[]; error?: unknown; }; -const dateInPast = function (firstDate: Date, secondDate: Date) { - if (firstDate.setHours(0, 0, 0, 0) <= secondDate.setHours(0, 0, 0, 0)) { - return true; - } - - return false; -}; -const today = new Date(); export default async function user(req: NextApiRequest, res: NextApiResponse) { - const apiKey = req.query.apiKey as string; - const apiInDb = await prisma.apiKey.findUnique({ where: { id: apiKey } }); - if (!apiInDb) throw new Error('API key not found'); - const { expiresAt } = apiInDb; - // if (!apiInDb) res.status(400).json({ error: 'Your api key is not valid' }); - if (expiresAt && dateInPast(expiresAt, today)) { - try { - const data = await prisma.user.findMany(); - res.status(200).json({ data }); - } catch (error) { - // FIXME: Add zod for validation/error handling - res.status(400).json({ error: error }); - } - } else res.status(400).json({ error: 'Your api key is not valid' }); - + try { + const users = await prisma.user.findMany(); + res.status(200).json({ data: { ...users } }); + } catch (error) { + // FIXME: Add zod for validation/error handling + res.status(400).json({ error: error }); + } } From 8165977ec34bcb8ba9b5f04c98637c59c887e7eb Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 29 Mar 2022 00:27:14 +0200 Subject: [PATCH 039/658] Adds basic CRUD endpoints for bookingReferences, Crendentials, DailyEventReferences, DestinationCalendars, EventTypeCustomInputs, Memberships, Schedules, and SelectedCalendars --- lib/helpers | 35 -------------- lib/helpers/captureError.ts | 47 +++++++++++++++++++ lib/helpers/verifyApiKey.ts | 36 ++++++++++++++ package.json | 1 + pages/api/booking-references/[id]/delete.ts | 27 +++++++++++ pages/api/booking-references/[id]/edit.ts | 32 +++++++++++++ pages/api/booking-references/[id]/index.ts | 27 +++++++++++ pages/api/booking-references/index.ts | 15 ++++++ pages/api/booking-references/new.ts | 26 ++++++++++ pages/api/credentials/[id]/delete.ts | 27 +++++++++++ pages/api/credentials/[id]/edit.ts | 32 +++++++++++++ pages/api/credentials/[id]/index.ts | 27 +++++++++++ pages/api/credentials/index.ts | 15 ++++++ pages/api/credentials/new.ts | 26 ++++++++++ .../api/daily-event-references/[id]/delete.ts | 27 +++++++++++ pages/api/daily-event-references/[id]/edit.ts | 32 +++++++++++++ .../api/daily-event-references/[id]/index.ts | 27 +++++++++++ pages/api/daily-event-references/index.ts | 15 ++++++ pages/api/daily-event-references/new.ts | 26 ++++++++++ .../api/destination-calendars/[id]/delete.ts | 27 +++++++++++ pages/api/destination-calendars/[id]/edit.ts | 32 +++++++++++++ pages/api/destination-calendars/[id]/index.ts | 27 +++++++++++ pages/api/destination-calendars/index.ts | 15 ++++++ pages/api/destination-calendars/new.ts | 26 ++++++++++ .../event-type-custom-inputs/[id]/delete.ts | 27 +++++++++++ .../api/event-type-custom-inputs/[id]/edit.ts | 32 +++++++++++++ .../event-type-custom-inputs/[id]/index.ts | 27 +++++++++++ pages/api/event-type-custom-inputs/index.ts | 15 ++++++ pages/api/event-type-custom-inputs/new.ts | 26 ++++++++++ pages/api/memberships/[id]/delete.ts | 27 +++++++++++ pages/api/memberships/[id]/edit.ts | 32 +++++++++++++ pages/api/memberships/[id]/index.ts | 27 +++++++++++ pages/api/memberships/index.ts | 15 ++++++ pages/api/memberships/new.ts | 26 ++++++++++ pages/api/schedules/[id]/delete.ts | 27 +++++++++++ pages/api/schedules/[id]/edit.ts | 32 +++++++++++++ pages/api/schedules/[id]/index.ts | 27 +++++++++++ pages/api/schedules/index.ts | 15 ++++++ pages/api/schedules/new.ts | 26 ++++++++++ pages/api/selected-calendars/[id]/delete.ts | 27 +++++++++++ pages/api/selected-calendars/[id]/edit.ts | 32 +++++++++++++ pages/api/selected-calendars/[id]/index.ts | 27 +++++++++++ pages/api/selected-calendars/index.ts | 15 ++++++ pages/api/selected-calendars/new.ts | 26 ++++++++++ pages/api/users/[id]/edit.ts | 19 +++----- pages/api/users/[id]/index.ts | 10 ++-- pages/api/users/index.ts | 10 ++-- pages/api/users/new.ts | 2 +- 48 files changed, 1115 insertions(+), 61 deletions(-) delete mode 100644 lib/helpers create mode 100644 lib/helpers/captureError.ts create mode 100644 lib/helpers/verifyApiKey.ts create mode 100644 pages/api/booking-references/[id]/delete.ts create mode 100644 pages/api/booking-references/[id]/edit.ts create mode 100644 pages/api/booking-references/[id]/index.ts create mode 100644 pages/api/booking-references/index.ts create mode 100644 pages/api/booking-references/new.ts create mode 100644 pages/api/credentials/[id]/delete.ts create mode 100644 pages/api/credentials/[id]/edit.ts create mode 100644 pages/api/credentials/[id]/index.ts create mode 100644 pages/api/credentials/index.ts create mode 100644 pages/api/credentials/new.ts create mode 100644 pages/api/daily-event-references/[id]/delete.ts create mode 100644 pages/api/daily-event-references/[id]/edit.ts create mode 100644 pages/api/daily-event-references/[id]/index.ts create mode 100644 pages/api/daily-event-references/index.ts create mode 100644 pages/api/daily-event-references/new.ts create mode 100644 pages/api/destination-calendars/[id]/delete.ts create mode 100644 pages/api/destination-calendars/[id]/edit.ts create mode 100644 pages/api/destination-calendars/[id]/index.ts create mode 100644 pages/api/destination-calendars/index.ts create mode 100644 pages/api/destination-calendars/new.ts create mode 100644 pages/api/event-type-custom-inputs/[id]/delete.ts create mode 100644 pages/api/event-type-custom-inputs/[id]/edit.ts create mode 100644 pages/api/event-type-custom-inputs/[id]/index.ts create mode 100644 pages/api/event-type-custom-inputs/index.ts create mode 100644 pages/api/event-type-custom-inputs/new.ts create mode 100644 pages/api/memberships/[id]/delete.ts create mode 100644 pages/api/memberships/[id]/edit.ts create mode 100644 pages/api/memberships/[id]/index.ts create mode 100644 pages/api/memberships/index.ts create mode 100644 pages/api/memberships/new.ts create mode 100644 pages/api/schedules/[id]/delete.ts create mode 100644 pages/api/schedules/[id]/edit.ts create mode 100644 pages/api/schedules/[id]/index.ts create mode 100644 pages/api/schedules/index.ts create mode 100644 pages/api/schedules/new.ts create mode 100644 pages/api/selected-calendars/[id]/delete.ts create mode 100644 pages/api/selected-calendars/[id]/edit.ts create mode 100644 pages/api/selected-calendars/[id]/index.ts create mode 100644 pages/api/selected-calendars/index.ts create mode 100644 pages/api/selected-calendars/new.ts diff --git a/lib/helpers b/lib/helpers deleted file mode 100644 index 1644c3906b..0000000000 --- a/lib/helpers +++ /dev/null @@ -1,35 +0,0 @@ -import prisma from "@calcom/prisma"; - -import { User } from "@calcom/prisma/client"; -import type { NextApiRequest, NextApiResponse } from "next"; - -type ResponseData = { - data?: User[]; - error?: unknown; -}; -const dateInPast = function (firstDate: Date, secondDate: Date) { - if (firstDate.setHours(0, 0, 0, 0) <= secondDate.setHours(0, 0, 0, 0)) { - return true; - } - - return false; -}; -const today = new Date(); - -export default async function user(req: NextApiRequest, res: NextApiResponse) { - const apiKey = req.query.apiKey as string; - const apiInDb = await prisma.apiKey.findUnique({ where: { id: apiKey } }); - if (!apiInDb) throw new Error('API key not found'); - const { expiresAt } = apiInDb; - // if (!apiInDb) res.status(400).json({ error: 'Your api key is not valid' }); - if (expiresAt && dateInPast(expiresAt, today)) { - try { - const data = await prisma.user.findMany(); - res.status(200).json({ data }); - } catch (error) { - // FIXME: Add zod for validation/error handling - res.status(400).json({ error: error }); - } - } else res.status(400).json({ error: 'Your api key is not valid' }); - -} diff --git a/lib/helpers/captureError.ts b/lib/helpers/captureError.ts new file mode 100644 index 0000000000..8835a3cb91 --- /dev/null +++ b/lib/helpers/captureError.ts @@ -0,0 +1,47 @@ +import { label, NextMiddleware } from "next-api-middleware"; +import * as Sentry from "@sentry/nextjs"; +import nanoid from "nanoid"; + +// 1 – Create middleware functions + +const captureErrors: NextMiddleware = async (req, res, next) => { + try { + // Catch any errors that are thrown in remaining + // middleware and the API route handler + await next(); + } catch (err) { + const eventId = Sentry.captureException(err); + + res.status(500); + res.json({ error: err }); + } +}; + +const addRequestId: NextMiddleware = async (req, res, next) => { + // Let remaining middleware and API route execute + await next(); + + // Apply header + res.setHeader("X-Response-ID", nanoid()); +}; + +// 2 – Use `label` to assemble all middleware + +const withMiddleware = label( + { + addRequestId, + sentry: captureErrors, // <-- Optionally alias middleware + }, + ["sentry"] // <-- Provide a list of middleware to call automatically +); + +// 3 – Define your API route handler + +const apiRouteHandler = async (req, res) => { + res.status(200); + res.send("Hello world!"); +}; + +// 4 – Choose middleware to invoke for this API route + +export default withMiddleware("addRequestId")(apiRouteHandler); \ No newline at end of file diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts new file mode 100644 index 0000000000..41dbb094d7 --- /dev/null +++ b/lib/helpers/verifyApiKey.ts @@ -0,0 +1,36 @@ +// https://github.com/htunnicliff/next-api-middleware +// import prisma from "@calcom/prisma"; + +// import { User } from "@calcom/prisma/client"; +// import type { NextApiRequest, NextApiResponse } from "next"; + +// type ResponseData = { +// data?: User[]; +// error?: unknown; +// }; +// const dateInPast = function (firstDate: Date, secondDate: Date) { +// if (firstDate.setHours(0, 0, 0, 0) <= secondDate.setHours(0, 0, 0, 0)) { +// return true; +// } + +// return false; +// }; +// const today = new Date(); + +// export default async function user(req: NextApiRequest, res: NextApiResponse) { +// const apiKey = req.query.apiKey as string; +// const apiInDb = await prisma.apiKey.findUnique({ where: { id: apiKey } }); +// if (!apiInDb) throw new Error('API key not found'); +// const { expiresAt } = apiInDb; +// // if (!apiInDb) res.status(400).json({ error: 'Your api key is not valid' }); +// if (expiresAt && dateInPast(expiresAt, today)) { +// try { +// const data = await prisma.user.findMany(); +// res.status(200).json({ data }); +// } catch (error) { +// // FIXME: Add zod for validation/error handling +// res.status(400).json({ error: error }); +// } +// } else res.status(400).json({ error: 'Your api key is not valid' }); + +// } diff --git a/package.json b/package.json index b91cd3b07f..e70d483ecd 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ }, "dependencies": { "next": "^12.1.0", + "next-api-middleware": "^1.0.1", "next-transpile-modules": "^9.0.0", "next-validations": "^0.1.11", "typescript": "^4.6.3", diff --git a/pages/api/booking-references/[id]/delete.ts b/pages/api/booking-references/[id]/delete.ts new file mode 100644 index 0000000000..13798382ba --- /dev/null +++ b/pages/api/booking-references/[id]/delete.ts @@ -0,0 +1,27 @@ +import prisma from "@calcom/prisma"; + +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + + +type ResponseData = { + message?: string; + error?: unknown; +}; + +export async function deleteBookingReference(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryIdParseInt.safeParse(query); + if (method === "DELETE" && safe.success && safe.data) { + const bookingReference = await prisma.bookingReference + .delete({ where: { id: safe.data.id } }) + // We only remove the bookingReference type from the database if there's an existing resource. + if (bookingReference) res.status(200).json({ message: `bookingReference with id: ${safe.data.id} deleted successfully` }); + // This catches the error thrown by prisma.bookingReference.delete() if the resource is not found. + else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only DELETE Method allowed" }); +} + +export default withValidQueryIdTransformParseInt(deleteBookingReference); diff --git a/pages/api/booking-references/[id]/edit.ts b/pages/api/booking-references/[id]/edit.ts new file mode 100644 index 0000000000..cdfe7a739b --- /dev/null +++ b/pages/api/booking-references/[id]/edit.ts @@ -0,0 +1,32 @@ +import prisma from "@calcom/prisma"; + +import { BookingReference } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaBookingReference, withValidBookingReference } from "@lib/validations/bookingReference"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: BookingReference; + message?: string; + error?: unknown; +}; + +export async function editBookingReference(req: NextApiRequest, res: NextApiResponse) { + const { query, body, method } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaBookingReference.safeParse(body); + + if (method === "PATCH" && safeQuery.success && safeBody.success) { + const data = await prisma.bookingReference.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + if (data) res.status(200).json({ data }); + else res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated` }) + + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only PATCH Method allowed for updating bookingReferences" }); +} + +export default withValidQueryIdTransformParseInt(withValidBookingReference(editBookingReference)); diff --git a/pages/api/booking-references/[id]/index.ts b/pages/api/booking-references/[id]/index.ts new file mode 100644 index 0000000000..ec973f5016 --- /dev/null +++ b/pages/api/booking-references/[id]/index.ts @@ -0,0 +1,27 @@ +import prisma from "@calcom/prisma"; + +import { BookingReference } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: BookingReference; + message?: string; + error?: unknown; +}; + +export async function bookingReference(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryIdParseInt.safeParse(query); + if (method === "GET" && safe.success) { + const data = await prisma.bookingReference.findUnique({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ data }); + if (!data) res.status(404).json({ message: "Event type not found" }); + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only GET Method allowed" }); +} + + +export default withValidQueryIdTransformParseInt(bookingReference); diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts new file mode 100644 index 0000000000..460d681ca7 --- /dev/null +++ b/pages/api/booking-references/index.ts @@ -0,0 +1,15 @@ +import prisma from "@calcom/prisma"; + +import { BookingReference } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +type ResponseData = { + data?: BookingReference[]; + error?: unknown; +}; + +export default async function bookingReference(req: NextApiRequest, res: NextApiResponse) { + const data = await prisma.bookingReference.findMany(); + if (data) res.status(200).json({ data }); + else res.status(400).json({ error: "No data found" }); +} diff --git a/pages/api/booking-references/new.ts b/pages/api/booking-references/new.ts new file mode 100644 index 0000000000..ba21befec8 --- /dev/null +++ b/pages/api/booking-references/new.ts @@ -0,0 +1,26 @@ +import prisma from "@calcom/prisma"; + +import { BookingReference } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaBookingReference, withValidBookingReference } from "@lib/validations/bookingReference"; + +type ResponseData = { + data?: BookingReference; + message?: string; + error?: string; +}; + +async function createBookingReference(req: NextApiRequest, res: NextApiResponse) { + const { body, method } = req; + const safe = schemaBookingReference.safeParse(body); + if (method === "POST" && safe.success) { + await prisma.bookingReference + .create({ data: safe.data }) + .then((data) => res.status(201).json({ data })) + .catch((error) => res.status(400).json({ message: "Could not create bookingReference type", error: error })); + // Reject any other HTTP method than POST + } else res.status(405).json({ error: "Only POST Method allowed" }); +} + +export default withValidBookingReference(createBookingReference); diff --git a/pages/api/credentials/[id]/delete.ts b/pages/api/credentials/[id]/delete.ts new file mode 100644 index 0000000000..a20e49518b --- /dev/null +++ b/pages/api/credentials/[id]/delete.ts @@ -0,0 +1,27 @@ +import prisma from "@calcom/prisma"; + +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + + +type ResponseData = { + message?: string; + error?: unknown; +}; + +export async function deleteCredential(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryIdParseInt.safeParse(query); + if (method === "DELETE" && safe.success && safe.data) { + const credential = await prisma.credential + .delete({ where: { id: safe.data.id } }) + // We only remove the credential type from the database if there's an existing resource. + if (credential) res.status(200).json({ message: `credential with id: ${safe.data.id} deleted successfully` }); + // This catches the error thrown by prisma.credential.delete() if the resource is not found. + else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only DELETE Method allowed" }); +} + +export default withValidQueryIdTransformParseInt(deleteCredential); diff --git a/pages/api/credentials/[id]/edit.ts b/pages/api/credentials/[id]/edit.ts new file mode 100644 index 0000000000..7ee777ba59 --- /dev/null +++ b/pages/api/credentials/[id]/edit.ts @@ -0,0 +1,32 @@ +import prisma from "@calcom/prisma"; + +import { Credential } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaCredential, withValidCredential } from "@lib/validations/credential"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: Credential; + message?: string; + error?: unknown; +}; + +export async function editCredential(req: NextApiRequest, res: NextApiResponse) { + const { query, body, method } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaCredential.safeParse(body); + + if (method === "PATCH" && safeQuery.success && safeBody.success) { + const data = await prisma.credential.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + if (data) res.status(200).json({ data }); + else res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only PATCH Method allowed for updating credentials" }); +} + +export default withValidQueryIdTransformParseInt(withValidCredential(editCredential)); diff --git a/pages/api/credentials/[id]/index.ts b/pages/api/credentials/[id]/index.ts new file mode 100644 index 0000000000..14ca851867 --- /dev/null +++ b/pages/api/credentials/[id]/index.ts @@ -0,0 +1,27 @@ +import prisma from "@calcom/prisma"; + +import { Credential } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: Credential; + message?: string; + error?: unknown; +}; + +export async function credential(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryIdParseInt.safeParse(query); + if (method === "GET" && safe.success) { + const data = await prisma.credential.findUnique({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ data }); + if (!data) res.status(404).json({ message: "Event type not found" }); + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only GET Method allowed" }); +} + + +export default withValidQueryIdTransformParseInt(credential); diff --git a/pages/api/credentials/index.ts b/pages/api/credentials/index.ts new file mode 100644 index 0000000000..cb484c95db --- /dev/null +++ b/pages/api/credentials/index.ts @@ -0,0 +1,15 @@ +import prisma from "@calcom/prisma"; + +import { Credential } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +type ResponseData = { + data?: Credential[]; + error?: unknown; +}; + +export default async function credential(req: NextApiRequest, res: NextApiResponse) { + const data = await prisma.credential.findMany(); + if (data) res.status(200).json({ data }); + else res.status(400).json({ error: "No data found" }); +} diff --git a/pages/api/credentials/new.ts b/pages/api/credentials/new.ts new file mode 100644 index 0000000000..ad025729d8 --- /dev/null +++ b/pages/api/credentials/new.ts @@ -0,0 +1,26 @@ +import prisma from "@calcom/prisma"; + +import { Credential } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaCredential, withValidCredential } from "@lib/validations/credential"; + +type ResponseData = { + data?: Credential; + message?: string; + error?: string; +}; + +async function createCredential(req: NextApiRequest, res: NextApiResponse) { + const { body, method } = req; + const safe = schemaCredential.safeParse(body); + if (method === "POST" && safe.success) { + await prisma.credential + .create({ data: safe.data }) + .then((data) => res.status(201).json({ data })) + .catch((error) => res.status(400).json({ message: "Could not create credential type", error: error })); + // Reject any other HTTP method than POST + } else res.status(405).json({ error: "Only POST Method allowed" }); +} + +export default withValidCredential(createCredential); diff --git a/pages/api/daily-event-references/[id]/delete.ts b/pages/api/daily-event-references/[id]/delete.ts new file mode 100644 index 0000000000..6b7a2a5541 --- /dev/null +++ b/pages/api/daily-event-references/[id]/delete.ts @@ -0,0 +1,27 @@ +import prisma from "@calcom/prisma"; + +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + + +type ResponseData = { + message?: string; + error?: unknown; +}; + +export async function deleteDailyEventReference(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryIdParseInt.safeParse(query); + if (method === "DELETE" && safe.success && safe.data) { + const dailyEventReference = await prisma.dailyEventReference + .delete({ where: { id: safe.data.id } }) + // We only remove the dailyEventReference type from the database if there's an existing resource. + if (dailyEventReference) res.status(200).json({ message: `dailyEventReference with id: ${safe.data.id} deleted successfully` }); + // This catches the error thrown by prisma.dailyEventReference.delete() if the resource is not found. + else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only DELETE Method allowed" }); +} + +export default withValidQueryIdTransformParseInt(deleteDailyEventReference); diff --git a/pages/api/daily-event-references/[id]/edit.ts b/pages/api/daily-event-references/[id]/edit.ts new file mode 100644 index 0000000000..eb731dde8a --- /dev/null +++ b/pages/api/daily-event-references/[id]/edit.ts @@ -0,0 +1,32 @@ +import prisma from "@calcom/prisma"; + +import { DailyEventReference } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaDailyEventReference, withValidDailyEventReference } from "@lib/validations/dailyEventReference"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: DailyEventReference; + message?: string; + error?: unknown; +}; + +export async function editDailyEventReference(req: NextApiRequest, res: NextApiResponse) { + const { query, body, method } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaDailyEventReference.safeParse(body); + + if (method === "PATCH" && safeQuery.success && safeBody.success) { + const data = await prisma.dailyEventReference.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + if (data) res.status(200).json({ data }); + else res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only PATCH Method allowed for updating dailyEventReferences" }); +} + +export default withValidQueryIdTransformParseInt(withValidDailyEventReference(editDailyEventReference)); diff --git a/pages/api/daily-event-references/[id]/index.ts b/pages/api/daily-event-references/[id]/index.ts new file mode 100644 index 0000000000..c9b243f707 --- /dev/null +++ b/pages/api/daily-event-references/[id]/index.ts @@ -0,0 +1,27 @@ +import prisma from "@calcom/prisma"; + +import { DailyEventReference } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: DailyEventReference; + message?: string; + error?: unknown; +}; + +export async function dailyEventReference(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryIdParseInt.safeParse(query); + if (method === "GET" && safe.success) { + const data = await prisma.dailyEventReference.findUnique({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ data }); + if (!data) res.status(404).json({ message: "Event type not found" }); + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only GET Method allowed" }); +} + + +export default withValidQueryIdTransformParseInt(dailyEventReference); diff --git a/pages/api/daily-event-references/index.ts b/pages/api/daily-event-references/index.ts new file mode 100644 index 0000000000..7d25bba8f1 --- /dev/null +++ b/pages/api/daily-event-references/index.ts @@ -0,0 +1,15 @@ +import prisma from "@calcom/prisma"; + +import { DailyEventReference } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +type ResponseData = { + data?: DailyEventReference[]; + error?: unknown; +}; + +export default async function dailyEventReference(req: NextApiRequest, res: NextApiResponse) { + const data = await prisma.dailyEventReference.findMany(); + if (data) res.status(200).json({ data }); + else res.status(400).json({ error: "No data found" }); +} diff --git a/pages/api/daily-event-references/new.ts b/pages/api/daily-event-references/new.ts new file mode 100644 index 0000000000..c508b37e08 --- /dev/null +++ b/pages/api/daily-event-references/new.ts @@ -0,0 +1,26 @@ +import prisma from "@calcom/prisma"; + +import { DailyEventReference } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaDailyEventReference, withValidDailyEventReference } from "@lib/validations/dailyEventReference"; + +type ResponseData = { + data?: DailyEventReference; + message?: string; + error?: string; +}; + +async function createDailyEventReference(req: NextApiRequest, res: NextApiResponse) { + const { body, method } = req; + const safe = schemaDailyEventReference.safeParse(body); + if (method === "POST" && safe.success) { + await prisma.dailyEventReference + .create({ data: safe.data }) + .then((data) => res.status(201).json({ data })) + .catch((error) => res.status(400).json({ message: "Could not create dailyEventReference type", error: error })); + // Reject any other HTTP method than POST + } else res.status(405).json({ error: "Only POST Method allowed" }); +} + +export default withValidDailyEventReference(createDailyEventReference); diff --git a/pages/api/destination-calendars/[id]/delete.ts b/pages/api/destination-calendars/[id]/delete.ts new file mode 100644 index 0000000000..246d5a58eb --- /dev/null +++ b/pages/api/destination-calendars/[id]/delete.ts @@ -0,0 +1,27 @@ +import prisma from "@calcom/prisma"; + +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + + +type ResponseData = { + message?: string; + error?: unknown; +}; + +export async function deleteDestinationCalendar(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryIdParseInt.safeParse(query); + if (method === "DELETE" && safe.success && safe.data) { + const destinationCalendar = await prisma.destinationCalendar + .delete({ where: { id: safe.data.id } }) + // We only remove the destinationCalendar type from the database if there's an existing resource. + if (destinationCalendar) res.status(200).json({ message: `destinationCalendar with id: ${safe.data.id} deleted successfully` }); + // This catches the error thrown by prisma.destinationCalendar.delete() if the resource is not found. + else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only DELETE Method allowed" }); +} + +export default withValidQueryIdTransformParseInt(deleteDestinationCalendar); diff --git a/pages/api/destination-calendars/[id]/edit.ts b/pages/api/destination-calendars/[id]/edit.ts new file mode 100644 index 0000000000..5cc11fa10d --- /dev/null +++ b/pages/api/destination-calendars/[id]/edit.ts @@ -0,0 +1,32 @@ +import prisma from "@calcom/prisma"; + +import { DestinationCalendar } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaDestinationCalendar, withValidDestinationCalendar } from "@lib/validations/destinationCalendar"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: DestinationCalendar; + message?: string; + error?: unknown; +}; + +export async function editDestinationCalendar(req: NextApiRequest, res: NextApiResponse) { + const { query, body, method } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaDestinationCalendar.safeParse(body); + + if (method === "PATCH" && safeQuery.success && safeBody.success) { + const data = await prisma.destinationCalendar.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + if (data) res.status(200).json({ data }); + else res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only PATCH Method allowed for updating destinationCalendars" }); +} + +export default withValidQueryIdTransformParseInt(withValidDestinationCalendar(editDestinationCalendar)); diff --git a/pages/api/destination-calendars/[id]/index.ts b/pages/api/destination-calendars/[id]/index.ts new file mode 100644 index 0000000000..95a1409372 --- /dev/null +++ b/pages/api/destination-calendars/[id]/index.ts @@ -0,0 +1,27 @@ +import prisma from "@calcom/prisma"; + +import { DestinationCalendar } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: DestinationCalendar; + message?: string; + error?: unknown; +}; + +export async function destinationCalendar(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryIdParseInt.safeParse(query); + if (method === "GET" && safe.success) { + const data = await prisma.destinationCalendar.findUnique({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ data }); + if (!data) res.status(404).json({ message: "Event type not found" }); + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only GET Method allowed" }); +} + + +export default withValidQueryIdTransformParseInt(destinationCalendar); diff --git a/pages/api/destination-calendars/index.ts b/pages/api/destination-calendars/index.ts new file mode 100644 index 0000000000..3877dbc08a --- /dev/null +++ b/pages/api/destination-calendars/index.ts @@ -0,0 +1,15 @@ +import prisma from "@calcom/prisma"; + +import { DestinationCalendar } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +type ResponseData = { + data?: DestinationCalendar[]; + error?: unknown; +}; + +export default async function destinationCalendar(req: NextApiRequest, res: NextApiResponse) { + const data = await prisma.destinationCalendar.findMany(); + if (data) res.status(200).json({ data }); + else res.status(400).json({ error: "No data found" }); +} diff --git a/pages/api/destination-calendars/new.ts b/pages/api/destination-calendars/new.ts new file mode 100644 index 0000000000..514217401c --- /dev/null +++ b/pages/api/destination-calendars/new.ts @@ -0,0 +1,26 @@ +import prisma from "@calcom/prisma"; + +import { DestinationCalendar } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaDestinationCalendar, withValidDestinationCalendar } from "@lib/validations/destinationCalendar"; + +type ResponseData = { + data?: DestinationCalendar; + message?: string; + error?: string; +}; + +async function createDestinationCalendar(req: NextApiRequest, res: NextApiResponse) { + const { body, method } = req; + const safe = schemaDestinationCalendar.safeParse(body); + if (method === "POST" && safe.success) { + await prisma.destinationCalendar + .create({ data: safe.data }) + .then((data) => res.status(201).json({ data })) + .catch((error) => res.status(400).json({ message: "Could not create destinationCalendar type", error: error })); + // Reject any other HTTP method than POST + } else res.status(405).json({ error: "Only POST Method allowed" }); +} + +export default withValidDestinationCalendar(createDestinationCalendar); diff --git a/pages/api/event-type-custom-inputs/[id]/delete.ts b/pages/api/event-type-custom-inputs/[id]/delete.ts new file mode 100644 index 0000000000..d4e8431f51 --- /dev/null +++ b/pages/api/event-type-custom-inputs/[id]/delete.ts @@ -0,0 +1,27 @@ +import prisma from "@calcom/prisma"; + +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + + +type ResponseData = { + message?: string; + error?: unknown; +}; + +export async function deleteEventTypeCustomInput(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryIdParseInt.safeParse(query); + if (method === "DELETE" && safe.success && safe.data) { + const eventTypeCustomInput = await prisma.eventTypeCustomInput + .delete({ where: { id: safe.data.id } }) + // We only remove the eventTypeCustomInput type from the database if there's an existing resource. + if (eventTypeCustomInput) res.status(200).json({ message: `eventTypeCustomInput with id: ${safe.data.id} deleted successfully` }); + // This catches the error thrown by prisma.eventTypeCustomInput.delete() if the resource is not found. + else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only DELETE Method allowed" }); +} + +export default withValidQueryIdTransformParseInt(deleteEventTypeCustomInput); diff --git a/pages/api/event-type-custom-inputs/[id]/edit.ts b/pages/api/event-type-custom-inputs/[id]/edit.ts new file mode 100644 index 0000000000..fcb650c906 --- /dev/null +++ b/pages/api/event-type-custom-inputs/[id]/edit.ts @@ -0,0 +1,32 @@ +import prisma from "@calcom/prisma"; + +import { EventTypeCustomInput } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaEventTypeCustomInput, withValidEventTypeCustomInput } from "@lib/validations/eventTypeCustomInput"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: EventTypeCustomInput; + message?: string; + error?: unknown; +}; + +export async function editEventTypeCustomInput(req: NextApiRequest, res: NextApiResponse) { + const { query, body, method } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaEventTypeCustomInput.safeParse(body); + + if (method === "PATCH" && safeQuery.success && safeBody.success) { + const data = await prisma.eventTypeCustomInput.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + if (data) res.status(200).json({ data }); + else res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only PATCH Method allowed for updating eventTypeCustomInputs" }); +} + +export default withValidQueryIdTransformParseInt(withValidEventTypeCustomInput(editEventTypeCustomInput)); diff --git a/pages/api/event-type-custom-inputs/[id]/index.ts b/pages/api/event-type-custom-inputs/[id]/index.ts new file mode 100644 index 0000000000..3b7a926dcd --- /dev/null +++ b/pages/api/event-type-custom-inputs/[id]/index.ts @@ -0,0 +1,27 @@ +import prisma from "@calcom/prisma"; + +import { EventTypeCustomInput } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: EventTypeCustomInput; + message?: string; + error?: unknown; +}; + +export async function eventTypeCustomInput(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryIdParseInt.safeParse(query); + if (method === "GET" && safe.success) { + const data = await prisma.eventTypeCustomInput.findUnique({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ data }); + if (!data) res.status(404).json({ message: "Event type not found" }); + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only GET Method allowed" }); +} + + +export default withValidQueryIdTransformParseInt(eventTypeCustomInput); diff --git a/pages/api/event-type-custom-inputs/index.ts b/pages/api/event-type-custom-inputs/index.ts new file mode 100644 index 0000000000..733539064e --- /dev/null +++ b/pages/api/event-type-custom-inputs/index.ts @@ -0,0 +1,15 @@ +import prisma from "@calcom/prisma"; + +import { EventTypeCustomInput } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +type ResponseData = { + data?: EventTypeCustomInput[]; + error?: unknown; +}; + +export default async function eventTypeCustomInput(req: NextApiRequest, res: NextApiResponse) { + const data = await prisma.eventTypeCustomInput.findMany(); + if (data) res.status(200).json({ data }); + else res.status(400).json({ error: "No data found" }); +} diff --git a/pages/api/event-type-custom-inputs/new.ts b/pages/api/event-type-custom-inputs/new.ts new file mode 100644 index 0000000000..abdb410070 --- /dev/null +++ b/pages/api/event-type-custom-inputs/new.ts @@ -0,0 +1,26 @@ +import prisma from "@calcom/prisma"; + +import { EventTypeCustomInput } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaEventTypeCustomInput, withValidEventTypeCustomInput } from "@lib/validations/eventTypeCustomInput"; + +type ResponseData = { + data?: EventTypeCustomInput; + message?: string; + error?: string; +}; + +async function createEventTypeCustomInput(req: NextApiRequest, res: NextApiResponse) { + const { body, method } = req; + const safe = schemaEventTypeCustomInput.safeParse(body); + if (method === "POST" && safe.success) { + await prisma.eventTypeCustomInput + .create({ data: safe.data }) + .then((data) => res.status(201).json({ data })) + .catch((error) => res.status(400).json({ message: "Could not create eventTypeCustomInput type", error: error })); + // Reject any other HTTP method than POST + } else res.status(405).json({ error: "Only POST Method allowed" }); +} + +export default withValidEventTypeCustomInput(createEventTypeCustomInput); diff --git a/pages/api/memberships/[id]/delete.ts b/pages/api/memberships/[id]/delete.ts new file mode 100644 index 0000000000..54c4fc9659 --- /dev/null +++ b/pages/api/memberships/[id]/delete.ts @@ -0,0 +1,27 @@ +import prisma from "@calcom/prisma"; + +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + + +type ResponseData = { + message?: string; + error?: unknown; +}; + +export async function deleteMembership(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryIdParseInt.safeParse(query); + if (method === "DELETE" && safe.success && safe.data) { + const membership = await prisma.membership + .delete({ where: { id: safe.data.id } }) + // We only remove the membership type from the database if there's an existing resource. + if (membership) res.status(200).json({ message: `membership with id: ${safe.data.id} deleted successfully` }); + // This catches the error thrown by prisma.membership.delete() if the resource is not found. + else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only DELETE Method allowed" }); +} + +export default withValidQueryIdTransformParseInt(deleteMembership); diff --git a/pages/api/memberships/[id]/edit.ts b/pages/api/memberships/[id]/edit.ts new file mode 100644 index 0000000000..63cdba3c0a --- /dev/null +++ b/pages/api/memberships/[id]/edit.ts @@ -0,0 +1,32 @@ +import prisma from "@calcom/prisma"; + +import { Membership } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaMembership, withValidMembership } from "@lib/validations/membership"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: Membership; + message?: string; + error?: unknown; +}; + +export async function editMembership(req: NextApiRequest, res: NextApiResponse) { + const { query, body, method } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaMembership.safeParse(body); + + if (method === "PATCH" && safeQuery.success && safeBody.success) { + const data = await prisma.membership.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + if (data) res.status(200).json({ data }); + else res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only PATCH Method allowed for updating memberships" }); +} + +export default withValidQueryIdTransformParseInt(withValidMembership(editMembership)); diff --git a/pages/api/memberships/[id]/index.ts b/pages/api/memberships/[id]/index.ts new file mode 100644 index 0000000000..7f56aa3889 --- /dev/null +++ b/pages/api/memberships/[id]/index.ts @@ -0,0 +1,27 @@ +import prisma from "@calcom/prisma"; + +import { Membership } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: Membership; + message?: string; + error?: unknown; +}; + +export async function membership(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryIdParseInt.safeParse(query); + if (method === "GET" && safe.success) { + const data = await prisma.membership.findUnique({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ data }); + if (!data) res.status(404).json({ message: "Event type not found" }); + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only GET Method allowed" }); +} + + +export default withValidQueryIdTransformParseInt(membership); diff --git a/pages/api/memberships/index.ts b/pages/api/memberships/index.ts new file mode 100644 index 0000000000..c993dd2134 --- /dev/null +++ b/pages/api/memberships/index.ts @@ -0,0 +1,15 @@ +import prisma from "@calcom/prisma"; + +import { Membership } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +type ResponseData = { + data?: Membership[]; + error?: unknown; +}; + +export default async function membership(req: NextApiRequest, res: NextApiResponse) { + const data = await prisma.membership.findMany(); + if (data) res.status(200).json({ data }); + else res.status(400).json({ error: "No data found" }); +} diff --git a/pages/api/memberships/new.ts b/pages/api/memberships/new.ts new file mode 100644 index 0000000000..c19365f3a0 --- /dev/null +++ b/pages/api/memberships/new.ts @@ -0,0 +1,26 @@ +import prisma from "@calcom/prisma"; + +import { Membership } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaMembership, withValidMembership } from "@lib/validations/membership"; + +type ResponseData = { + data?: Membership; + message?: string; + error?: string; +}; + +async function createMembership(req: NextApiRequest, res: NextApiResponse) { + const { body, method } = req; + const safe = schemaMembership.safeParse(body); + if (method === "POST" && safe.success) { + await prisma.membership + .create({ data: safe.data }) + .then((data) => res.status(201).json({ data })) + .catch((error) => res.status(400).json({ message: "Could not create membership type", error: error })); + // Reject any other HTTP method than POST + } else res.status(405).json({ error: "Only POST Method allowed" }); +} + +export default withValidMembership(createMembership); diff --git a/pages/api/schedules/[id]/delete.ts b/pages/api/schedules/[id]/delete.ts new file mode 100644 index 0000000000..0dcaf7910a --- /dev/null +++ b/pages/api/schedules/[id]/delete.ts @@ -0,0 +1,27 @@ +import prisma from "@calcom/prisma"; + +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + + +type ResponseData = { + message?: string; + error?: unknown; +}; + +export async function deleteSchedule(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryIdParseInt.safeParse(query); + if (method === "DELETE" && safe.success && safe.data) { + const schedule = await prisma.schedule + .delete({ where: { id: safe.data.id } }) + // We only remove the schedule type from the database if there's an existing resource. + if (schedule) res.status(200).json({ message: `schedule with id: ${safe.data.id} deleted successfully` }); + // This catches the error thrown by prisma.schedule.delete() if the resource is not found. + else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only DELETE Method allowed" }); +} + +export default withValidQueryIdTransformParseInt(deleteSchedule); diff --git a/pages/api/schedules/[id]/edit.ts b/pages/api/schedules/[id]/edit.ts new file mode 100644 index 0000000000..5b207636cc --- /dev/null +++ b/pages/api/schedules/[id]/edit.ts @@ -0,0 +1,32 @@ +import prisma from "@calcom/prisma"; + +import { Schedule } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaSchedule, withValidSchedule } from "@lib/validations/schedule"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: Schedule; + message?: string; + error?: unknown; +}; + +export async function editSchedule(req: NextApiRequest, res: NextApiResponse) { + const { query, body, method } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaSchedule.safeParse(body); + + if (method === "PATCH" && safeQuery.success && safeBody.success) { + const data = await prisma.schedule.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + if (data) res.status(200).json({ data }); + else res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only PATCH Method allowed for updating schedules" }); +} + +export default withValidQueryIdTransformParseInt(withValidSchedule(editSchedule)); diff --git a/pages/api/schedules/[id]/index.ts b/pages/api/schedules/[id]/index.ts new file mode 100644 index 0000000000..f6d3621a80 --- /dev/null +++ b/pages/api/schedules/[id]/index.ts @@ -0,0 +1,27 @@ +import prisma from "@calcom/prisma"; + +import { Schedule } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: Schedule; + message?: string; + error?: unknown; +}; + +export async function schedule(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryIdParseInt.safeParse(query); + if (method === "GET" && safe.success) { + const data = await prisma.schedule.findUnique({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ data }); + if (!data) res.status(404).json({ message: "Event type not found" }); + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only GET Method allowed" }); +} + + +export default withValidQueryIdTransformParseInt(schedule); diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts new file mode 100644 index 0000000000..3892a461b5 --- /dev/null +++ b/pages/api/schedules/index.ts @@ -0,0 +1,15 @@ +import prisma from "@calcom/prisma"; + +import { Schedule } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +type ResponseData = { + data?: Schedule[]; + error?: unknown; +}; + +export default async function schedule(req: NextApiRequest, res: NextApiResponse) { + const data = await prisma.schedule.findMany(); + if (data) res.status(200).json({ data }); + else res.status(400).json({ error: "No data found" }); +} diff --git a/pages/api/schedules/new.ts b/pages/api/schedules/new.ts new file mode 100644 index 0000000000..ad3e1f90bf --- /dev/null +++ b/pages/api/schedules/new.ts @@ -0,0 +1,26 @@ +import prisma from "@calcom/prisma"; + +import { Schedule } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaSchedule, withValidSchedule } from "@lib/validations/schedule"; + +type ResponseData = { + data?: Schedule; + message?: string; + error?: string; +}; + +async function createSchedule(req: NextApiRequest, res: NextApiResponse) { + const { body, method } = req; + const safe = schemaSchedule.safeParse(body); + if (method === "POST" && safe.success) { + await prisma.schedule + .create({ data: safe.data }) + .then((data) => res.status(201).json({ data })) + .catch((error) => res.status(400).json({ message: "Could not create schedule type", error: error })); + // Reject any other HTTP method than POST + } else res.status(405).json({ error: "Only POST Method allowed" }); +} + +export default withValidSchedule(createSchedule); diff --git a/pages/api/selected-calendars/[id]/delete.ts b/pages/api/selected-calendars/[id]/delete.ts new file mode 100644 index 0000000000..06a0c5a156 --- /dev/null +++ b/pages/api/selected-calendars/[id]/delete.ts @@ -0,0 +1,27 @@ +import prisma from "@calcom/prisma"; + +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + + +type ResponseData = { + message?: string; + error?: unknown; +}; + +export async function deleteSelectedCalendar(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryIdParseInt.safeParse(query); + if (method === "DELETE" && safe.success && safe.data) { + const selectedCalendar = await prisma.selectedCalendar + .delete({ where: { id: safe.data.id } }) + // We only remove the selectedCalendar type from the database if there's an existing resource. + if (selectedCalendar) res.status(200).json({ message: `selectedCalendar with id: ${safe.data.id} deleted successfully` }); + // This catches the error thrown by prisma.selectedCalendar.delete() if the resource is not found. + else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only DELETE Method allowed" }); +} + +export default withValidQueryIdTransformParseInt(deleteSelectedCalendar); diff --git a/pages/api/selected-calendars/[id]/edit.ts b/pages/api/selected-calendars/[id]/edit.ts new file mode 100644 index 0000000000..c53dc4222e --- /dev/null +++ b/pages/api/selected-calendars/[id]/edit.ts @@ -0,0 +1,32 @@ +import prisma from "@calcom/prisma"; + +import { SelectedCalendar } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaSelectedCalendar, withValidSelectedCalendar } from "@lib/validations/selectedCalendar"; +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: SelectedCalendar; + message?: string; + error?: unknown; +}; + +export async function editSelectedCalendar(req: NextApiRequest, res: NextApiResponse) { + const { query, body, method } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaSelectedCalendar.safeParse(body); + + if (method === "PATCH" && safeQuery.success && safeBody.success) { + const data = await prisma.selectedCalendar.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + if (data) res.status(200).json({ data }); + else res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only PATCH Method allowed for updating selectedCalendars" }); +} + +export default withValidQueryIdTransformParseInt(withValidSelectedCalendar(editSelectedCalendar)); diff --git a/pages/api/selected-calendars/[id]/index.ts b/pages/api/selected-calendars/[id]/index.ts new file mode 100644 index 0000000000..d89fb31398 --- /dev/null +++ b/pages/api/selected-calendars/[id]/index.ts @@ -0,0 +1,27 @@ +import prisma from "@calcom/prisma"; + +import { SelectedCalendar } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +type ResponseData = { + data?: SelectedCalendar; + message?: string; + error?: unknown; +}; + +export async function selectedCalendar(req: NextApiRequest, res: NextApiResponse) { + const { query, method } = req; + const safe = await schemaQueryIdParseInt.safeParse(query); + if (method === "GET" && safe.success) { + const data = await prisma.selectedCalendar.findUnique({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ data }); + if (!data) res.status(404).json({ message: "Event type not found" }); + // Reject any other HTTP method than POST + } else res.status(405).json({ message: "Only GET Method allowed" }); +} + + +export default withValidQueryIdTransformParseInt(selectedCalendar); diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts new file mode 100644 index 0000000000..d6a29e3dd3 --- /dev/null +++ b/pages/api/selected-calendars/index.ts @@ -0,0 +1,15 @@ +import prisma from "@calcom/prisma"; + +import { SelectedCalendar } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +type ResponseData = { + data?: SelectedCalendar[]; + error?: unknown; +}; + +export default async function selectedCalendar(req: NextApiRequest, res: NextApiResponse) { + const data = await prisma.selectedCalendar.findMany(); + if (data) res.status(200).json({ data }); + else res.status(400).json({ error: "No data found" }); +} diff --git a/pages/api/selected-calendars/new.ts b/pages/api/selected-calendars/new.ts new file mode 100644 index 0000000000..649e276a5e --- /dev/null +++ b/pages/api/selected-calendars/new.ts @@ -0,0 +1,26 @@ +import prisma from "@calcom/prisma"; + +import { SelectedCalendar } from "@calcom/prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { schemaSelectedCalendar, withValidSelectedCalendar } from "@lib/validations/selectedCalendar"; + +type ResponseData = { + data?: SelectedCalendar; + message?: string; + error?: string; +}; + +async function createSelectedCalendar(req: NextApiRequest, res: NextApiResponse) { + const { body, method } = req; + const safe = schemaSelectedCalendar.safeParse(body); + if (method === "POST" && safe.success) { + await prisma.selectedCalendar + .create({ data: safe.data }) + .then((data) => res.status(201).json({ data })) + .catch((error) => res.status(400).json({ message: "Could not create selectedCalendar type", error: error })); + // Reject any other HTTP method than POST + } else res.status(405).json({ error: "Only POST Method allowed" }); +} + +export default withValidSelectedCalendar(createSelectedCalendar); diff --git a/pages/api/users/[id]/edit.ts b/pages/api/users/[id]/edit.ts index 1e5780fc35..cba9230543 100644 --- a/pages/api/users/[id]/edit.ts +++ b/pages/api/users/[id]/edit.ts @@ -17,21 +17,16 @@ export async function editUser(req: NextApiRequest, res: NextApiResponse { - res.status(200).json({ data: user }); - }).catch(error => { - res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) - }); - } - } else { + }) + if (data) res.status(200).json({ data }); + else res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + // Reject any other HTTP method than POST - res.status(405).json({ message: "Only PATCH Method allowed for updating users" }); - } + } else res.status(405).json({ message: "Only PATCH Method allowed for updating users" }); } export default withValidQueryIdTransformParseInt(withValidUser(editUser)); diff --git a/pages/api/users/[id]/index.ts b/pages/api/users/[id]/index.ts index 8852ad6e6f..61be86fe7c 100644 --- a/pages/api/users/[id]/index.ts +++ b/pages/api/users/[id]/index.ts @@ -15,14 +15,12 @@ export async function user(req: NextApiRequest, res: NextApiResponse) { - try { - const users = await prisma.user.findMany(); - res.status(200).json({ data: { ...users } }); - } catch (error) { - // FIXME: Add zod for validation/error handling - res.status(400).json({ error: error }); - } + const data = await prisma.user.findMany(); + if (data) res.status(200).json({ data }); + else res.status(400).json({ error: "No data found" }); } diff --git a/pages/api/users/new.ts b/pages/api/users/new.ts index ae298fdfb3..7f319e62d9 100644 --- a/pages/api/users/new.ts +++ b/pages/api/users/new.ts @@ -17,7 +17,7 @@ async function createUser(req: NextApiRequest, res: NextApiResponse res.status(201).json({ data: user })) + .then((data) => res.status(201).json({ data })) .catch((error) => res.status(400).json({ message: "Could not create user type", error: error })); // Reject any other HTTP method than POST } else res.status(405).json({ error: "Only POST Method allowed" }); From ec8fe3693006405d156448cfdd472d03c2b797f7 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 29 Mar 2022 02:25:24 +0200 Subject: [PATCH 040/658] feat: successfully protected all endpoints with next-api-middleware for verifyApiKey --- lib/helpers/addRequestid.ts | 9 +++ lib/helpers/captureError.ts | 47 -------------- lib/helpers/captureErrors.ts | 16 +++++ lib/helpers/verifyApiKey.ts | 52 ++++++---------- lib/helpers/withMiddleware.ts | 15 +++++ package.json | 1 + pages/api/users/index.ts | 4 +- yarn-error.log | 112 +++++++++++++++++++++++++++++++--- 8 files changed, 167 insertions(+), 89 deletions(-) create mode 100644 lib/helpers/addRequestid.ts delete mode 100644 lib/helpers/captureError.ts create mode 100644 lib/helpers/captureErrors.ts create mode 100644 lib/helpers/withMiddleware.ts diff --git a/lib/helpers/addRequestid.ts b/lib/helpers/addRequestid.ts new file mode 100644 index 0000000000..2096927a1e --- /dev/null +++ b/lib/helpers/addRequestid.ts @@ -0,0 +1,9 @@ +import { NextMiddleware } from "next-api-middleware"; +import { nanoid } from "nanoid"; + +export const addRequestId: NextMiddleware = async (_req, res, next) => { + // Apply header + res.setHeader("X-Response-ID", nanoid()); + // Let remaining middleware and API route execute + await next(); +}; \ No newline at end of file diff --git a/lib/helpers/captureError.ts b/lib/helpers/captureError.ts deleted file mode 100644 index 8835a3cb91..0000000000 --- a/lib/helpers/captureError.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { label, NextMiddleware } from "next-api-middleware"; -import * as Sentry from "@sentry/nextjs"; -import nanoid from "nanoid"; - -// 1 – Create middleware functions - -const captureErrors: NextMiddleware = async (req, res, next) => { - try { - // Catch any errors that are thrown in remaining - // middleware and the API route handler - await next(); - } catch (err) { - const eventId = Sentry.captureException(err); - - res.status(500); - res.json({ error: err }); - } -}; - -const addRequestId: NextMiddleware = async (req, res, next) => { - // Let remaining middleware and API route execute - await next(); - - // Apply header - res.setHeader("X-Response-ID", nanoid()); -}; - -// 2 – Use `label` to assemble all middleware - -const withMiddleware = label( - { - addRequestId, - sentry: captureErrors, // <-- Optionally alias middleware - }, - ["sentry"] // <-- Provide a list of middleware to call automatically -); - -// 3 – Define your API route handler - -const apiRouteHandler = async (req, res) => { - res.status(200); - res.send("Hello world!"); -}; - -// 4 – Choose middleware to invoke for this API route - -export default withMiddleware("addRequestId")(apiRouteHandler); \ No newline at end of file diff --git a/lib/helpers/captureErrors.ts b/lib/helpers/captureErrors.ts new file mode 100644 index 0000000000..b78174f36a --- /dev/null +++ b/lib/helpers/captureErrors.ts @@ -0,0 +1,16 @@ +import { NextMiddleware } from "next-api-middleware"; +import * as Sentry from "@sentry/nextjs"; + +export const captureErrors: NextMiddleware = async (_req, res, next) => { + try { + // Catch any errors that are thrown in remaining + // middleware and the API route handler + await next(); + } catch (err) { + const eventId = Sentry.captureException(err); + console.log(eventId) + res.status(500); + res.json({ error: err }); + } +}; + diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 41dbb094d7..ffc602dcde 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -1,36 +1,20 @@ -// https://github.com/htunnicliff/next-api-middleware -// import prisma from "@calcom/prisma"; +import { NextMiddleware } from "next-api-middleware"; +// import { nanoid } from "nanoid"; +import prisma from "@calcom/prisma"; -// import { User } from "@calcom/prisma/client"; -// import type { NextApiRequest, NextApiResponse } from "next"; +const dateInPast = function (firstDate: Date, secondDate: Date) { + if (firstDate.setHours(0, 0, 0, 0) <= secondDate.setHours(0, 0, 0, 0)) { + return true; + } +} +const today = new Date(); -// type ResponseData = { -// data?: User[]; -// error?: unknown; -// }; -// const dateInPast = function (firstDate: Date, secondDate: Date) { -// if (firstDate.setHours(0, 0, 0, 0) <= secondDate.setHours(0, 0, 0, 0)) { -// return true; -// } - -// return false; -// }; -// const today = new Date(); - -// export default async function user(req: NextApiRequest, res: NextApiResponse) { -// const apiKey = req.query.apiKey as string; -// const apiInDb = await prisma.apiKey.findUnique({ where: { id: apiKey } }); -// if (!apiInDb) throw new Error('API key not found'); -// const { expiresAt } = apiInDb; -// // if (!apiInDb) res.status(400).json({ error: 'Your api key is not valid' }); -// if (expiresAt && dateInPast(expiresAt, today)) { -// try { -// const data = await prisma.user.findMany(); -// res.status(200).json({ data }); -// } catch (error) { -// // FIXME: Add zod for validation/error handling -// res.status(400).json({ error: error }); -// } -// } else res.status(400).json({ error: 'Your api key is not valid' }); - -// } +export const verifyApiKey: NextMiddleware = async (req, res, next) => { + const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.apiKey as string } }); + if (!apiKey) { + res.status(400).json({ error: 'Your api key is not valid' }); + throw new Error('No api key found'); + } + if (apiKey.expiresAt && dateInPast(apiKey.expiresAt, today)) await next(); + else res.status(400).json({ error: 'Your api key is not valid' }); +}; diff --git a/lib/helpers/withMiddleware.ts b/lib/helpers/withMiddleware.ts new file mode 100644 index 0000000000..99f3958af7 --- /dev/null +++ b/lib/helpers/withMiddleware.ts @@ -0,0 +1,15 @@ +import { label } from "next-api-middleware"; +import { addRequestId } from "./addRequestid"; +import { captureErrors } from "./captureErrors"; +import { verifyApiKey } from "./verifyApiKey"; + +const withMiddleware = label( + { + addRequestId, + verifyApiKey, + sentry: captureErrors, // <-- Optionally alias middleware + }, + ["sentry","verifyApiKey"] // <-- Provide a list of middleware to call automatically +); + +export default withMiddleware; \ No newline at end of file diff --git a/package.json b/package.json index e70d483ecd..feaee290bb 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "node-mocks-http": "^1.11.0" }, "dependencies": { + "@sentry/nextjs": "^6.19.2", "next": "^12.1.0", "next-api-middleware": "^1.0.1", "next-transpile-modules": "^9.0.0", diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 8f83378ead..f431caa6c8 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -1,6 +1,7 @@ import prisma from "@calcom/prisma"; import { User } from "@calcom/prisma/client"; +import withMiddleware from "@lib/helpers/withMiddleware"; import type { NextApiRequest, NextApiResponse } from "next"; type ResponseData = { @@ -8,8 +9,9 @@ type ResponseData = { error?: unknown; }; -export default async function user(req: NextApiRequest, res: NextApiResponse) { +async function user(req: NextApiRequest, res: NextApiResponse) { const data = await prisma.user.findMany(); if (data) res.status(200).json({ data }); else res.status(400).json({ error: "No data found" }); } +export default withMiddleware("addRequestId")(user); \ No newline at end of file diff --git a/yarn-error.log b/yarn-error.log index e56325651f..3e1a5107cc 100644 --- a/yarn-error.log +++ b/yarn-error.log @@ -1,8 +1,8 @@ Arguments: - /Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/bin/node /Users/ag/Library/Caches/fnm_multishells/3034_1648146693474/bin/yarn add --dev -W @typescript-eslint + /Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/bin/node /Users/ag/Library/Caches/fnm_multishells/13639_1648391401808/bin/yarn add -W @types/next-api-middleware PATH: - /Users/ag/Library/pnpm:/Users/ag/Library/Caches/fnm_multishells/3034_1648146693474/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/ag/.local/bin:/Users/ag/.fig/bin:/Users/ag/.local/bin:/Users/ag/.local/bin:/Users/ag/.yarn/bin + /Users/ag/Library/pnpm:/Users/ag/Library/Caches/fnm_multishells/13639_1648391401808/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/ag/.local/bin:/Users/ag/.fig/bin:/Users/ag/.local/bin:/Users/ag/.local/bin:/Users/ag/.yarn/bin Yarn version: 1.22.17 @@ -14,8 +14,8 @@ Platform: darwin x64 Trace: - Error: https://registry.yarnpkg.com/@typescript-eslint: Request "https://registry.yarnpkg.com/@typescript-eslint" returned a 405 - at Request.params.callback [as _callback] (/Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/lib/node_modules/yarn/lib/cli.js:67038:18) + Error: https://registry.yarnpkg.com/@types%2fnext-api-middleware: Not found + at Request.params.callback [as _callback] (/Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/lib/node_modules/yarn/lib/cli.js:67029:18) at Request.self.callback (/Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/lib/node_modules/yarn/lib/cli.js:140883:22) at Request.emit (events.js:400:28) at Request. (/Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/lib/node_modules/yarn/lib/cli.js:141855:10) @@ -53,15 +53,18 @@ npm manifest: "@babel/preset-typescript": "^7.16.7", "@calcom/prisma": "*", "@calcom/tsconfig": "*", + "@typescript-eslint/eslint-plugin": "^5.16.0", "babel-jest": "^27.5.1", "husky": "^7.0.4", "jest": "^27.5.1", - "node-mocks-http": "^1.11.0", - "typescript": "^4.6.3" + "node-mocks-http": "^1.11.0" }, "dependencies": { "next": "^12.1.0", + "next-api-middleware": "^1.0.1", + "next-transpile-modules": "^9.0.0", "next-validations": "^0.1.11", + "typescript": "^4.6.3", "zod": "^3.14.2" } } @@ -3614,6 +3617,11 @@ Lockfile: jest-matcher-utils "^27.0.0" pretty-format "^27.0.0" + "@types/json-schema@^7.0.9": + version "7.0.10" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.10.tgz#9b05b7896166cd00e9cbd59864853abf65d9ac23" + integrity sha512-BLO9bBq59vW3fxCpD4o0N4U+DXsvwvIcl+jofw0frQo/GrBFC+/jRZj1E7kgp6dvTyNmA4y6JCV5Id/r3mNP5A== + "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" @@ -3886,6 +3894,21 @@ Lockfile: resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.3.tgz#781d360c282436494b32fe7d9f7f8e64b3118aa3" integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw== + "@typescript-eslint/eslint-plugin@^5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.16.0.tgz#78f246dd8d1b528fc5bfca99a8a64d4023a3d86d" + integrity sha512-SJoba1edXvQRMmNI505Uo4XmGbxCK9ARQpkvOd00anxzri9RNQk0DDCxD+LIl+jYhkzOJiOMMKYEHnHEODjdCw== + dependencies: + "@typescript-eslint/scope-manager" "5.16.0" + "@typescript-eslint/type-utils" "5.16.0" + "@typescript-eslint/utils" "5.16.0" + debug "^4.3.2" + functional-red-black-tree "^1.0.1" + ignore "^5.1.8" + regexpp "^3.2.0" + semver "^7.3.5" + tsutils "^3.21.0" + "@typescript-eslint/parser@^5.0.0": version "5.14.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.14.0.tgz#7c79f898aa3cff0ceee6f1d34eeed0f034fb9ef3" @@ -3904,11 +3927,33 @@ Lockfile: "@typescript-eslint/types" "5.14.0" "@typescript-eslint/visitor-keys" "5.14.0" + "@typescript-eslint/scope-manager@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.16.0.tgz#7e7909d64bd0c4d8aef629cdc764b9d3e1d3a69a" + integrity sha512-P+Yab2Hovg8NekLIR/mOElCDPyGgFZKhGoZA901Yax6WR6HVeGLbsqJkZ+Cvk5nts/dAlFKm8PfL43UZnWdpIQ== + dependencies: + "@typescript-eslint/types" "5.16.0" + "@typescript-eslint/visitor-keys" "5.16.0" + + "@typescript-eslint/type-utils@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.16.0.tgz#b482bdde1d7d7c0c7080f7f2f67ea9580b9e0692" + integrity sha512-SKygICv54CCRl1Vq5ewwQUJV/8padIWvPgCxlWPGO/OgQLCijY9G7lDu6H+mqfQtbzDNlVjzVWQmeqbLMBLEwQ== + dependencies: + "@typescript-eslint/utils" "5.16.0" + debug "^4.3.2" + tsutils "^3.21.0" + "@typescript-eslint/types@5.14.0": version "5.14.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.14.0.tgz#96317cf116cea4befabc0defef371a1013f8ab11" integrity sha512-BR6Y9eE9360LNnW3eEUqAg6HxS9Q35kSIs4rp4vNHRdfg0s+/PgHgskvu5DFTM7G5VKAVjuyaN476LCPrdA7Mw== + "@typescript-eslint/types@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.16.0.tgz#5827b011982950ed350f075eaecb7f47d3c643ee" + integrity sha512-oUorOwLj/3/3p/HFwrp6m/J2VfbLC8gjW5X3awpQJ/bSG+YRGFS4dpsvtQ8T2VNveV+LflQHjlLvB6v0R87z4g== + "@typescript-eslint/typescript-estree@5.14.0": version "5.14.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.14.0.tgz#78b7f7385d5b6f2748aacea5c9b7f6ae62058314" @@ -3922,6 +3967,31 @@ Lockfile: semver "^7.3.5" tsutils "^3.21.0" + "@typescript-eslint/typescript-estree@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.16.0.tgz#32259459ec62f5feddca66adc695342f30101f61" + integrity sha512-SE4VfbLWUZl9MR+ngLSARptUv2E8brY0luCdgmUevU6arZRY/KxYoLI/3V/yxaURR8tLRN7bmZtJdgmzLHI6pQ== + dependencies: + "@typescript-eslint/types" "5.16.0" + "@typescript-eslint/visitor-keys" "5.16.0" + debug "^4.3.2" + globby "^11.0.4" + is-glob "^4.0.3" + semver "^7.3.5" + tsutils "^3.21.0" + + "@typescript-eslint/utils@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.16.0.tgz#42218b459d6d66418a4eb199a382bdc261650679" + integrity sha512-iYej2ER6AwmejLWMWzJIHy3nPJeGDuCqf8Jnb+jAQVoPpmWzwQOfa9hWVB8GIQE5gsCv/rfN4T+AYb/V06WseQ== + dependencies: + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.16.0" + "@typescript-eslint/types" "5.16.0" + "@typescript-eslint/typescript-estree" "5.16.0" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + "@typescript-eslint/visitor-keys@5.14.0": version "5.14.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.14.0.tgz#1927005b3434ccd0d3ae1b2ecf60e65943c36986" @@ -3930,6 +4000,14 @@ Lockfile: "@typescript-eslint/types" "5.14.0" eslint-visitor-keys "^3.0.0" + "@typescript-eslint/visitor-keys@5.16.0": + version "5.16.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.16.0.tgz#f27dc3b943e6317264c7492e390c6844cd4efbbb" + integrity sha512-jqxO8msp5vZDhikTwq9ubyMHqZ67UIvawohr4qF3KhlpL7gzSjOd+8471H3nh5LyABkaI85laEKKU8SnGUK5/g== + dependencies: + "@typescript-eslint/types" "5.16.0" + eslint-visitor-keys "^3.0.0" + "@vercel/edge-functions-ui@^0.2.1": version "0.2.1" resolved "https://registry.yarnpkg.com/@vercel/edge-functions-ui/-/edge-functions-ui-0.2.1.tgz#8af0a5d8d4d544364fa79c4d075564e3a5bd972e" @@ -6383,6 +6461,14 @@ Lockfile: semver "^6.3.0" string.prototype.matchall "^4.0.6" + eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + eslint-scope@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" @@ -6477,6 +6563,11 @@ Lockfile: dependencies: estraverse "^5.2.0" + estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" @@ -7990,7 +8081,7 @@ Lockfile: resolved "https://registry.yarnpkg.com/iframe-resizer/-/iframe-resizer-4.3.2.tgz#42dd88345d18b9e377b6044dddb98c664ab0ce6b" integrity sha512-gOWo2hmdPjMQsQ+zTKbses08mDfDEMh4NneGQNP4qwePYujY1lguqP6gnbeJkf154gojWlBhIltlgnMfYjGHWA== - ignore@^5.2.0: + ignore@^5.1.8, ignore@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== @@ -11053,6 +11144,13 @@ Lockfile: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + next-api-middleware@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/next-api-middleware/-/next-api-middleware-1.0.1.tgz#8dd76abeace9e10c6be29c9c9486a84cb649cc12" + integrity sha512-t8UbZ9UUPFB7nklrHdAusn7MfoVSHtnWlRV1R0hirvLRHPDnzidTnw1Mu99Kqvc1bVC0rQSUX5kf0j/4nmEtfA== + dependencies: + debug "^4.3.2" + next-auth@^4.0.6: version "4.3.0" resolved "https://registry.yarnpkg.com/next-auth/-/next-auth-4.3.0.tgz#93274254f9e6263c3c3edf7169a92fb13a700619" From 75e635cb3715ebdc2e1fcb5ef21ab8ed770efae1 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 29 Mar 2022 02:47:48 +0200 Subject: [PATCH 041/658] chore: remove yarn-error from repo, add to .gitignore --- .gitignore | 3 + yarn-error.log | 15975 ----------------------------------------------- 2 files changed, 3 insertions(+), 15975 deletions(-) delete mode 100644 yarn-error.log diff --git a/.gitignore b/.gitignore index b04bde734a..b93b0f6248 100644 --- a/.gitignore +++ b/.gitignore @@ -70,3 +70,6 @@ dist # Linting lint-results + +# Yarn +yarn-error.log \ No newline at end of file diff --git a/yarn-error.log b/yarn-error.log deleted file mode 100644 index 3e1a5107cc..0000000000 --- a/yarn-error.log +++ /dev/null @@ -1,15975 +0,0 @@ -Arguments: - /Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/bin/node /Users/ag/Library/Caches/fnm_multishells/13639_1648391401808/bin/yarn add -W @types/next-api-middleware - -PATH: - /Users/ag/Library/pnpm:/Users/ag/Library/Caches/fnm_multishells/13639_1648391401808/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Users/ag/.local/bin:/Users/ag/.fig/bin:/Users/ag/.local/bin:/Users/ag/.local/bin:/Users/ag/.yarn/bin - -Yarn version: - 1.22.17 - -Node version: - 14.17.6 - -Platform: - darwin x64 - -Trace: - Error: https://registry.yarnpkg.com/@types%2fnext-api-middleware: Not found - at Request.params.callback [as _callback] (/Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/lib/node_modules/yarn/lib/cli.js:67029:18) - at Request.self.callback (/Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/lib/node_modules/yarn/lib/cli.js:140883:22) - at Request.emit (events.js:400:28) - at Request. (/Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/lib/node_modules/yarn/lib/cli.js:141855:10) - at Request.emit (events.js:400:28) - at IncomingMessage. (/Users/ag/Library/Application Support/fnm/node-versions/v14.17.6/installation/lib/node_modules/yarn/lib/cli.js:141777:12) - at Object.onceWrapper (events.js:519:28) - at IncomingMessage.emit (events.js:412:35) - at endReadableNT (internal/streams/readable.js:1317:12) - at processTicksAndRejections (internal/process/task_queues.js:82:21) - -npm manifest: - { - "name": "@calcom/api", - "version": "1.0.0", - "description": "Public API for Cal.com", - "main": "index.ts", - "repository": "git@github.com:calcom/api.git", - "author": "Cal.com Inc.", - "private": true, - "scripts": { - "dev": "PORT=3002 next", - "start": "next start", - "build": "next build", - "lint": "next lint", - "lint-fix": "next lint --fix", - "test": "jest --detectOpenHandles", - "type-check": "tsc --pretty --noEmit", - "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist", - "prepare": "husky install", - "pre-commit": "next lint" - }, - "devDependencies": { - "@babel/core": "^7.17.8", - "@babel/preset-env": "^7.16.11", - "@babel/preset-typescript": "^7.16.7", - "@calcom/prisma": "*", - "@calcom/tsconfig": "*", - "@typescript-eslint/eslint-plugin": "^5.16.0", - "babel-jest": "^27.5.1", - "husky": "^7.0.4", - "jest": "^27.5.1", - "node-mocks-http": "^1.11.0" - }, - "dependencies": { - "next": "^12.1.0", - "next-api-middleware": "^1.0.1", - "next-transpile-modules": "^9.0.0", - "next-validations": "^0.1.11", - "typescript": "^4.6.3", - "zod": "^3.14.2" - } - } - -yarn manifest: - No manifest - -Lockfile: - # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. - # yarn lockfile v1 - - - "@ampproject/remapping@^2.1.0": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.1.2.tgz#4edca94973ded9630d20101cd8559cedb8d8bd34" - integrity sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg== - dependencies: - "@jridgewell/trace-mapping" "^0.3.0" - - "@babel/code-frame@7.16.7", "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.7.tgz#44416b6bd7624b998f5b1af5d470856c40138789" - integrity sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg== - dependencies: - "@babel/highlight" "^7.16.7" - - "@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.8", "@babel/compat-data@^7.17.0", "@babel/compat-data@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.7.tgz#078d8b833fbbcc95286613be8c716cef2b519fa2" - integrity sha512-p8pdE6j0a29TNGebNm7NzYZWB3xVZJBZ7XGs42uAKzQo8VQ3F0By/cQCtUEABwIqw5zo6WA4NbmxsfzADzMKnQ== - - "@babel/core@7.13.10": - version "7.13.10" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.13.10.tgz#07de050bbd8193fcd8a3c27918c0890613a94559" - integrity sha512-bfIYcT0BdKeAZrovpMqX2Mx5NrgAckGbwT982AkdS5GNfn3KMGiprlBAtmBcFZRUmpaufS6WZFP8trvx8ptFDw== - dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.13.9" - "@babel/helper-compilation-targets" "^7.13.10" - "@babel/helper-module-transforms" "^7.13.0" - "@babel/helpers" "^7.13.10" - "@babel/parser" "^7.13.10" - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.13.0" - "@babel/types" "^7.13.0" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.1.2" - lodash "^4.17.19" - semver "^6.3.0" - source-map "^0.5.0" - - "@babel/core@7.16.12": - version "7.16.12" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.12.tgz#5edc53c1b71e54881315923ae2aedea2522bb784" - integrity sha512-dK5PtG1uiN2ikk++5OzSYsitZKny4wOCD0nrO4TqnW4BVBTQ2NGS3NgilvT/TEyxTST7LNyWV/T4tXDoD3fOgg== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.16.8" - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-module-transforms" "^7.16.7" - "@babel/helpers" "^7.16.7" - "@babel/parser" "^7.16.12" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.16.10" - "@babel/types" "^7.16.8" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.1.2" - semver "^6.3.0" - source-map "^0.5.0" - - "@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.7.5": - version "7.17.5" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.5.tgz#6cd2e836058c28f06a4ca8ee7ed955bbf37c8225" - integrity sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA== - dependencies: - "@ampproject/remapping" "^2.1.0" - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.3" - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-module-transforms" "^7.16.7" - "@babel/helpers" "^7.17.2" - "@babel/parser" "^7.17.3" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.3" - "@babel/types" "^7.17.0" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.1.2" - semver "^6.3.0" - - "@babel/core@^7.17.8", "@babel/core@^7.7.2", "@babel/core@^7.8.0": - version "7.17.8" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.17.8.tgz#3dac27c190ebc3a4381110d46c80e77efe172e1a" - integrity sha512-OdQDV/7cRBtJHLSOBqqbYNkOcydOgnX59TZx4puf41fzcVtN3e/4yqY8lMQsK+5X2lJtAdmA+6OHqsj1hBJ4IQ== - dependencies: - "@ampproject/remapping" "^2.1.0" - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.7" - "@babel/helper-compilation-targets" "^7.17.7" - "@babel/helper-module-transforms" "^7.17.7" - "@babel/helpers" "^7.17.8" - "@babel/parser" "^7.17.8" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.3" - "@babel/types" "^7.17.0" - convert-source-map "^1.7.0" - debug "^4.1.0" - gensync "^1.0.0-beta.2" - json5 "^2.1.2" - semver "^6.3.0" - - "@babel/generator@7.13.9": - version "7.13.9" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.13.9.tgz#3a7aa96f9efb8e2be42d38d80e2ceb4c64d8de39" - integrity sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw== - dependencies: - "@babel/types" "^7.13.0" - jsesc "^2.5.1" - source-map "^0.5.0" - - "@babel/generator@^7.13.0", "@babel/generator@^7.13.9", "@babel/generator@^7.16.8", "@babel/generator@^7.17.3": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.3.tgz#a2c30b0c4f89858cb87050c3ffdfd36bdf443200" - integrity sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg== - dependencies: - "@babel/types" "^7.17.0" - jsesc "^2.5.1" - source-map "^0.5.0" - - "@babel/generator@^7.17.7", "@babel/generator@^7.7.2": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.17.7.tgz#8da2599beb4a86194a3b24df6c085931d9ee45ad" - integrity sha512-oLcVCTeIFadUoArDTwpluncplrYBmTCCZZgXCbgNGvOBBiSDDK3eWO4b/+eOTli5tKv1lg+a5/NAXg+nTcei1w== - dependencies: - "@babel/types" "^7.17.0" - jsesc "^2.5.1" - source-map "^0.5.0" - - "@babel/helper-annotate-as-pure@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz#bb2339a7534a9c128e3102024c60760a3a7f3862" - integrity sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw== - dependencies: - "@babel/types" "^7.16.7" - - "@babel/helper-builder-binary-assignment-operator-visitor@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz#38d138561ea207f0f69eb1626a418e4f7e6a580b" - integrity sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA== - dependencies: - "@babel/helper-explode-assignable-expression" "^7.16.7" - "@babel/types" "^7.16.7" - - "@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.13.10", "@babel/helper-compilation-targets@^7.16.7", "@babel/helper-compilation-targets@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.7.tgz#a3c2924f5e5f0379b356d4cfb313d1414dc30e46" - integrity sha512-UFzlz2jjd8kroj0hmCFV5zr+tQPi1dpC2cRsDV/3IEW8bJfCPrPpmcSN6ZS8RqIq4LXcmpipCQFPddyFA5Yc7w== - dependencies: - "@babel/compat-data" "^7.17.7" - "@babel/helper-validator-option" "^7.16.7" - browserslist "^4.17.5" - semver "^6.3.0" - - "@babel/helper-create-class-features-plugin@^7.16.10", "@babel/helper-create-class-features-plugin@^7.16.7", "@babel/helper-create-class-features-plugin@^7.17.6": - version "7.17.6" - resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.6.tgz#3778c1ed09a7f3e65e6d6e0f6fbfcc53809d92c9" - integrity sha512-SogLLSxXm2OkBbSsHZMM4tUi8fUzjs63AT/d0YQIzr6GSd8Hxsbk2KYDX0k0DweAzGMj/YWeiCsorIdtdcW8Eg== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.16.7" - "@babel/helper-member-expression-to-functions" "^7.16.7" - "@babel/helper-optimise-call-expression" "^7.16.7" - "@babel/helper-replace-supers" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" - - "@babel/helper-create-regexp-features-plugin@^7.16.7": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.0.tgz#1dcc7d40ba0c6b6b25618997c5dbfd310f186fe1" - integrity sha512-awO2So99wG6KnlE+TPs6rn83gCz5WlEePJDTnLEqbchMVrBeAujURVphRdigsk094VhvZehFoNOihSlcBjwsXA== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - regexpu-core "^5.0.1" - - "@babel/helper-define-polyfill-provider@^0.3.1": - version "0.3.1" - resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz#52411b445bdb2e676869e5a74960d2d3826d2665" - integrity sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA== - dependencies: - "@babel/helper-compilation-targets" "^7.13.0" - "@babel/helper-module-imports" "^7.12.13" - "@babel/helper-plugin-utils" "^7.13.0" - "@babel/traverse" "^7.13.0" - debug "^4.1.1" - lodash.debounce "^4.0.8" - resolve "^1.14.2" - semver "^6.1.2" - - "@babel/helper-environment-visitor@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz#ff484094a839bde9d89cd63cba017d7aae80ecd7" - integrity sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag== - dependencies: - "@babel/types" "^7.16.7" - - "@babel/helper-explode-assignable-expression@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz#12a6d8522fdd834f194e868af6354e8650242b7a" - integrity sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ== - dependencies: - "@babel/types" "^7.16.7" - - "@babel/helper-function-name@^7.12.13", "@babel/helper-function-name@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz#f1ec51551fb1c8956bc8dd95f38523b6cf375f8f" - integrity sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA== - dependencies: - "@babel/helper-get-function-arity" "^7.16.7" - "@babel/template" "^7.16.7" - "@babel/types" "^7.16.7" - - "@babel/helper-get-function-arity@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz#ea08ac753117a669f1508ba06ebcc49156387419" - integrity sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw== - dependencies: - "@babel/types" "^7.16.7" - - "@babel/helper-hoist-variables@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz#86bcb19a77a509c7b77d0e22323ef588fa58c246" - integrity sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg== - dependencies: - "@babel/types" "^7.16.7" - - "@babel/helper-member-expression-to-functions@^7.16.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz#a34013b57d8542a8c4ff8ba3f747c02452a4d8c4" - integrity sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw== - dependencies: - "@babel/types" "^7.17.0" - - "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz#25612a8091a999704461c8a222d0efec5d091437" - integrity sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg== - dependencies: - "@babel/types" "^7.16.7" - - "@babel/helper-module-transforms@^7.13.0", "@babel/helper-module-transforms@^7.16.7": - version "7.17.6" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.6.tgz#3c3b03cc6617e33d68ef5a27a67419ac5199ccd0" - integrity sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA== - dependencies: - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-simple-access" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/helper-validator-identifier" "^7.16.7" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.3" - "@babel/types" "^7.17.0" - - "@babel/helper-module-transforms@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.17.7.tgz#3943c7f777139e7954a5355c815263741a9c1cbd" - integrity sha512-VmZD99F3gNTYB7fJRDTi+u6l/zxY0BE6OIxPSU7a50s6ZUQkHwSDmV92FfM+oCG0pZRVojGYhkR8I0OGeCVREw== - dependencies: - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-simple-access" "^7.17.7" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/helper-validator-identifier" "^7.16.7" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.3" - "@babel/types" "^7.17.0" - - "@babel/helper-optimise-call-expression@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz#a34e3560605abbd31a18546bd2aad3e6d9a174f2" - integrity sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w== - dependencies: - "@babel/types" "^7.16.7" - - "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz#aa3a8ab4c3cceff8e65eb9e73d87dc4ff320b2f5" - integrity sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA== - - "@babel/helper-remap-async-to-generator@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz#29ffaade68a367e2ed09c90901986918d25e57e3" - integrity sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-wrap-function" "^7.16.8" - "@babel/types" "^7.16.8" - - "@babel/helper-replace-supers@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz#e9f5f5f32ac90429c1a4bdec0f231ef0c2838ab1" - integrity sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw== - dependencies: - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-member-expression-to-functions" "^7.16.7" - "@babel/helper-optimise-call-expression" "^7.16.7" - "@babel/traverse" "^7.16.7" - "@babel/types" "^7.16.7" - - "@babel/helper-simple-access@^7.16.7", "@babel/helper-simple-access@^7.17.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz#aaa473de92b7987c6dfa7ce9a7d9674724823367" - integrity sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA== - dependencies: - "@babel/types" "^7.17.0" - - "@babel/helper-skip-transparent-expression-wrappers@^7.16.0": - version "7.16.0" - resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz#0ee3388070147c3ae051e487eca3ebb0e2e8bb09" - integrity sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw== - dependencies: - "@babel/types" "^7.16.0" - - "@babel/helper-split-export-declaration@^7.12.13", "@babel/helper-split-export-declaration@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz#0b648c0c42da9d3920d85ad585f2778620b8726b" - integrity sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw== - dependencies: - "@babel/types" "^7.16.7" - - "@babel/helper-validator-identifier@^7.12.11", "@babel/helper-validator-identifier@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz#e8c602438c4a8195751243da9031d1607d247cad" - integrity sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw== - - "@babel/helper-validator-option@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz#b203ce62ce5fe153899b617c08957de860de4d23" - integrity sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ== - - "@babel/helper-wrap-function@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz#58afda087c4cd235de92f7ceedebca2c41274200" - integrity sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw== - dependencies: - "@babel/helper-function-name" "^7.16.7" - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.16.8" - "@babel/types" "^7.16.8" - - "@babel/helpers@^7.13.10", "@babel/helpers@^7.16.7", "@babel/helpers@^7.17.2": - version "7.17.2" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.2.tgz#23f0a0746c8e287773ccd27c14be428891f63417" - integrity sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ== - dependencies: - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.0" - "@babel/types" "^7.17.0" - - "@babel/helpers@^7.17.8": - version "7.17.8" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.17.8.tgz#288450be8c6ac7e4e44df37bcc53d345e07bc106" - integrity sha512-QcL86FGxpfSJwGtAvv4iG93UL6bmqBdmoVY0CMCU2g+oD2ezQse3PT5Pa+jiD6LJndBQi0EDlpzOWNlLuhz5gw== - dependencies: - "@babel/template" "^7.16.7" - "@babel/traverse" "^7.17.3" - "@babel/types" "^7.17.0" - - "@babel/highlight@^7.16.7": - version "7.16.10" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.10.tgz#744f2eb81579d6eea753c227b0f570ad785aba88" - integrity sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw== - dependencies: - "@babel/helper-validator-identifier" "^7.16.7" - chalk "^2.0.0" - js-tokens "^4.0.0" - - "@babel/parser@7.14.6": - version "7.14.6" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.6.tgz#d85cc68ca3cac84eae384c06f032921f5227f4b2" - integrity sha512-oG0ej7efjEXxb4UgE+klVx+3j4MVo+A2vCzm7OUN4CLo6WhQ+vSOD2yJ8m7B+DghObxtLxt3EfgMWpq+AsWehQ== - - "@babel/parser@^7.1.0", "@babel/parser@^7.13.0", "@babel/parser@^7.13.10", "@babel/parser@^7.14.7", "@babel/parser@^7.16.12", "@babel/parser@^7.16.7", "@babel/parser@^7.17.3": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.3.tgz#b07702b982990bf6fdc1da5049a23fece4c5c3d0" - integrity sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA== - - "@babel/parser@^7.17.8": - version "7.17.8" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.17.8.tgz#2817fb9d885dd8132ea0f8eb615a6388cca1c240" - integrity sha512-BoHhDJrJXqcg+ZL16Xv39H9n+AqJ4pcDrQBGZN+wHxIysrLZ3/ECwCBUch/1zUNhnsXULcONU3Ei5Hmkfk6kiQ== - - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz#4eda6d6c2a0aa79c70fa7b6da67763dfe2141050" - integrity sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz#cc001234dfc139ac45f6bcf801866198c8c72ff9" - integrity sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" - "@babel/plugin-proposal-optional-chaining" "^7.16.7" - - "@babel/plugin-proposal-async-generator-functions@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.8.tgz#3bdd1ebbe620804ea9416706cd67d60787504bc8" - integrity sha512-71YHIvMuiuqWJQkebWJtdhQTfd4Q4mF76q2IX37uZPkG9+olBxsX+rH1vkhFto4UeJZ9dPY2s+mDvhDm1u2BGQ== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-remap-async-to-generator" "^7.16.8" - "@babel/plugin-syntax-async-generators" "^7.8.4" - - "@babel/plugin-proposal-class-properties@7.16.7", "@babel/plugin-proposal-class-properties@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz#925cad7b3b1a2fcea7e59ecc8eb5954f961f91b0" - integrity sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-proposal-class-static-block@^7.16.7": - version "7.17.6" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.6.tgz#164e8fd25f0d80fa48c5a4d1438a6629325ad83c" - integrity sha512-X/tididvL2zbs7jZCeeRJ8167U/+Ac135AM6jCAx6gYXDUviZV5Ku9UDvWS2NCuWlFjIRXklYhwo6HhAC7ETnA== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.17.6" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - - "@babel/plugin-proposal-dynamic-import@7.16.7", "@babel/plugin-proposal-dynamic-import@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz#c19c897eaa46b27634a00fee9fb7d829158704b2" - integrity sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - - "@babel/plugin-proposal-export-namespace-from@7.16.7", "@babel/plugin-proposal-export-namespace-from@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz#09de09df18445a5786a305681423ae63507a6163" - integrity sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - - "@babel/plugin-proposal-json-strings@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz#9732cb1d17d9a2626a08c5be25186c195b6fa6e8" - integrity sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-json-strings" "^7.8.3" - - "@babel/plugin-proposal-logical-assignment-operators@7.16.7", "@babel/plugin-proposal-logical-assignment-operators@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz#be23c0ba74deec1922e639832904be0bea73cdea" - integrity sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - - "@babel/plugin-proposal-nullish-coalescing-operator@7.16.7", "@babel/plugin-proposal-nullish-coalescing-operator@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz#141fc20b6857e59459d430c850a0011e36561d99" - integrity sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - - "@babel/plugin-proposal-numeric-separator@7.16.7", "@babel/plugin-proposal-numeric-separator@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz#d6b69f4af63fb38b6ca2558442a7fb191236eba9" - integrity sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - - "@babel/plugin-proposal-object-rest-spread@^7.16.7": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.3.tgz#d9eb649a54628a51701aef7e0ea3d17e2b9dd390" - integrity sha512-yuL5iQA/TbZn+RGAfxQXfi7CNLmKi1f8zInn4IgobuCWcAb7i+zj4TYzQ9l8cEzVyJ89PDGuqxK1xZpUDISesw== - dependencies: - "@babel/compat-data" "^7.17.0" - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.16.7" - - "@babel/plugin-proposal-optional-catch-binding@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz#c623a430674ffc4ab732fd0a0ae7722b67cb74cf" - integrity sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - - "@babel/plugin-proposal-optional-chaining@7.16.7", "@babel/plugin-proposal-optional-chaining@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz#7cd629564724816c0e8a969535551f943c64c39a" - integrity sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - - "@babel/plugin-proposal-private-methods@7.16.11", "@babel/plugin-proposal-private-methods@^7.16.11": - version "7.16.11" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.11.tgz#e8df108288555ff259f4527dbe84813aac3a1c50" - integrity sha512-F/2uAkPlXDr8+BHpZvo19w3hLFKge+k75XUprE6jaqKxjGkSYcK+4c+bup5PdW/7W/Rpjwql7FTVEDW+fRAQsw== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.10" - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-proposal-private-property-in-object@7.16.7", "@babel/plugin-proposal-private-property-in-object@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz#b0b8cef543c2c3d57e59e2c611994861d46a3fce" - integrity sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-create-class-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - - "@babel/plugin-proposal-unicode-property-regex@^7.16.7", "@babel/plugin-proposal-unicode-property-regex@^7.4.4": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz#635d18eb10c6214210ffc5ff4932552de08188a2" - integrity sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-syntax-async-generators@7.8.4", "@babel/plugin-syntax-async-generators@^7.8.4": - version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" - integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - - "@babel/plugin-syntax-bigint@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" - integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - - "@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" - integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - - "@babel/plugin-syntax-class-static-block@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" - integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - - "@babel/plugin-syntax-dynamic-import@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" - integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - - "@babel/plugin-syntax-export-namespace-from@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz#028964a9ba80dbc094c915c487ad7c4e7a66465a" - integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== - 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", "@babel/plugin-syntax-json-strings@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" - integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - - "@babel/plugin-syntax-jsx@^7.12.13", "@babel/plugin-syntax-jsx@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.16.7.tgz#50b6571d13f764266a113d77c82b4a6508bbe665" - integrity sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@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.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" - integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - - "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" - integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - - "@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" - integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - - "@babel/plugin-syntax-object-rest-spread@7.8.3", "@babel/plugin-syntax-object-rest-spread@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" - integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - - "@babel/plugin-syntax-optional-catch-binding@7.8.3", "@babel/plugin-syntax-optional-catch-binding@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" - integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - - "@babel/plugin-syntax-optional-chaining@^7.8.3": - version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" - integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== - dependencies: - "@babel/helper-plugin-utils" "^7.8.0" - - "@babel/plugin-syntax-private-property-in-object@^7.14.5": - version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" - integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== - dependencies: - "@babel/helper-plugin-utils" "^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.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" - integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - - "@babel/plugin-syntax-typescript@^7.16.7", "@babel/plugin-syntax-typescript@^7.7.2": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz#39c9b55ee153151990fb038651d58d3fd03f98f8" - integrity sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-arrow-functions@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz#44125e653d94b98db76369de9c396dc14bef4154" - integrity sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-async-to-generator@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.8.tgz#b83dff4b970cf41f1b819f8b49cc0cfbaa53a808" - integrity sha512-MtmUmTJQHCnyJVrScNzNlofQJ3dLFuobYn3mwOTKHnSCMtbNsqvF71GQmJfFjdrXSsAA7iysFmYWw4bXZ20hOg== - dependencies: - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-remap-async-to-generator" "^7.16.8" - - "@babel/plugin-transform-block-scoped-functions@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz#4d0d57d9632ef6062cdf354bb717102ee042a620" - integrity sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-block-scoping@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz#f50664ab99ddeaee5bc681b8f3a6ea9d72ab4f87" - integrity sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-classes@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz#8f4b9562850cd973de3b498f1218796eb181ce00" - integrity sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.16.7" - "@babel/helper-optimise-call-expression" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-replace-supers" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" - globals "^11.1.0" - - "@babel/plugin-transform-computed-properties@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz#66dee12e46f61d2aae7a73710f591eb3df616470" - integrity sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-destructuring@^7.16.7": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.7.tgz#49dc2675a7afa9a5e4c6bdee636061136c3408d1" - integrity sha512-XVh0r5yq9sLR4vZ6eVZe8FKfIcSgaTBxVBRSYokRj2qksf6QerYnTxz9/GTuKTH/n/HwLP7t6gtlybHetJ/6hQ== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-dotall-regex@^7.16.7", "@babel/plugin-transform-dotall-regex@^7.4.4": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz#6b2d67686fab15fb6a7fd4bd895d5982cfc81241" - integrity sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-duplicate-keys@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz#2207e9ca8f82a0d36a5a67b6536e7ef8b08823c9" - integrity sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-exponentiation-operator@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz#efa9862ef97e9e9e5f653f6ddc7b665e8536fe9b" - integrity sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA== - dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-for-of@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz#649d639d4617dff502a9a158c479b3b556728d8c" - integrity sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-function-name@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz#5ab34375c64d61d083d7d2f05c38d90b97ec65cf" - integrity sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA== - dependencies: - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-function-name" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-literals@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz#254c9618c5ff749e87cb0c0cef1a0a050c0bdab1" - integrity sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-member-expression-literals@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz#6e5dcf906ef8a098e630149d14c867dd28f92384" - integrity sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-modules-amd@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz#b28d323016a7daaae8609781d1f8c9da42b13186" - integrity sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g== - dependencies: - "@babel/helper-module-transforms" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - babel-plugin-dynamic-import-node "^2.3.3" - - "@babel/plugin-transform-modules-commonjs@7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.8.tgz#cdee19aae887b16b9d331009aa9a219af7c86afe" - integrity sha512-oflKPvsLT2+uKQopesJt3ApiaIS2HW+hzHFcwRNtyDGieAeC/dIHZX8buJQ2J2X1rxGPy4eRcUijm3qcSPjYcA== - dependencies: - "@babel/helper-module-transforms" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-simple-access" "^7.16.7" - babel-plugin-dynamic-import-node "^2.3.3" - - "@babel/plugin-transform-modules-commonjs@^7.16.8": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.7.tgz#d86b217c8e45bb5f2dbc11eefc8eab62cf980d19" - integrity sha512-ITPmR2V7MqioMJyrxUo2onHNC3e+MvfFiFIR0RP21d3PtlVb6sfzoxNKiphSZUOM9hEIdzCcZe83ieX3yoqjUA== - dependencies: - "@babel/helper-module-transforms" "^7.17.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-simple-access" "^7.17.7" - babel-plugin-dynamic-import-node "^2.3.3" - - "@babel/plugin-transform-modules-systemjs@^7.16.7": - version "7.17.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.8.tgz#81fd834024fae14ea78fbe34168b042f38703859" - integrity sha512-39reIkMTUVagzgA5x88zDYXPCMT6lcaRKs1+S9K6NKBPErbgO/w/kP8GlNQTC87b412ZTlmNgr3k2JrWgHH+Bw== - dependencies: - "@babel/helper-hoist-variables" "^7.16.7" - "@babel/helper-module-transforms" "^7.17.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-validator-identifier" "^7.16.7" - babel-plugin-dynamic-import-node "^2.3.3" - - "@babel/plugin-transform-modules-umd@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz#23dad479fa585283dbd22215bff12719171e7618" - integrity sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ== - dependencies: - "@babel/helper-module-transforms" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-named-capturing-groups-regex@^7.16.8": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.8.tgz#7f860e0e40d844a02c9dcf9d84965e7dfd666252" - integrity sha512-j3Jw+n5PvpmhRR+mrgIh04puSANCk/T/UA3m3P1MjJkhlK906+ApHhDIqBQDdOgL/r1UYpz4GNclTXxyZrYGSw== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.7" - - "@babel/plugin-transform-new-target@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz#9967d89a5c243818e0800fdad89db22c5f514244" - integrity sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-object-super@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz#ac359cf8d32cf4354d27a46867999490b6c32a94" - integrity sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-replace-supers" "^7.16.7" - - "@babel/plugin-transform-parameters@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz#a1721f55b99b736511cb7e0152f61f17688f331f" - integrity sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-property-literals@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz#2dadac85155436f22c696c4827730e0fe1057a55" - integrity sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-react-jsx@7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.16.7.tgz#86a6a220552afd0e4e1f0388a68a372be7add0d4" - integrity sha512-8D16ye66fxiE8m890w0BpPpngG9o9OVBBy0gH2E+2AR7qMR2ZpTYJEqLxAsoroenMId0p/wMW+Blc0meDgu0Ag== - dependencies: - "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-module-imports" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-jsx" "^7.16.7" - "@babel/types" "^7.16.7" - - "@babel/plugin-transform-regenerator@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz#9e7576dc476cb89ccc5096fff7af659243b4adeb" - integrity sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q== - dependencies: - regenerator-transform "^0.14.2" - - "@babel/plugin-transform-reserved-words@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz#1d798e078f7c5958eec952059c460b220a63f586" - integrity sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-shorthand-properties@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz#e8549ae4afcf8382f711794c0c7b6b934c5fbd2a" - integrity sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-spread@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz#a303e2122f9f12e0105daeedd0f30fb197d8ff44" - integrity sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0" - - "@babel/plugin-transform-sticky-regex@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz#c84741d4f4a38072b9a1e2e3fd56d359552e8660" - integrity sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-template-literals@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz#f3d1c45d28967c8e80f53666fc9c3e50618217ab" - integrity sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-typeof-symbol@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz#9cdbe622582c21368bd482b660ba87d5545d4f7e" - integrity sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-typescript@^7.16.7": - version "7.16.8" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.16.8.tgz#591ce9b6b83504903fa9dd3652c357c2ba7a1ee0" - integrity sha512-bHdQ9k7YpBDO2d0NVfkj51DpQcvwIzIusJ7mEUaMlbZq3Kt/U47j24inXZHQ5MDiYpCs+oZiwnXyKedE8+q7AQ== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/plugin-syntax-typescript" "^7.16.7" - - "@babel/plugin-transform-unicode-escapes@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz#da8717de7b3287a2c6d659750c964f302b31ece3" - integrity sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/plugin-transform-unicode-regex@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz#0f7aa4a501198976e25e82702574c34cfebe9ef2" - integrity sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q== - dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - - "@babel/preset-env@^7.16.11": - version "7.16.11" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.16.11.tgz#5dd88fd885fae36f88fd7c8342475c9f0abe2982" - integrity sha512-qcmWG8R7ZW6WBRPZK//y+E3Cli151B20W1Rv7ln27vuPaXU/8TKms6jFdiJtF7UDTxcrb7mZd88tAeK9LjdT8g== - dependencies: - "@babel/compat-data" "^7.16.8" - "@babel/helper-compilation-targets" "^7.16.7" - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-validator-option" "^7.16.7" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.16.7" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.16.7" - "@babel/plugin-proposal-async-generator-functions" "^7.16.8" - "@babel/plugin-proposal-class-properties" "^7.16.7" - "@babel/plugin-proposal-class-static-block" "^7.16.7" - "@babel/plugin-proposal-dynamic-import" "^7.16.7" - "@babel/plugin-proposal-export-namespace-from" "^7.16.7" - "@babel/plugin-proposal-json-strings" "^7.16.7" - "@babel/plugin-proposal-logical-assignment-operators" "^7.16.7" - "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.7" - "@babel/plugin-proposal-numeric-separator" "^7.16.7" - "@babel/plugin-proposal-object-rest-spread" "^7.16.7" - "@babel/plugin-proposal-optional-catch-binding" "^7.16.7" - "@babel/plugin-proposal-optional-chaining" "^7.16.7" - "@babel/plugin-proposal-private-methods" "^7.16.11" - "@babel/plugin-proposal-private-property-in-object" "^7.16.7" - "@babel/plugin-proposal-unicode-property-regex" "^7.16.7" - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-class-properties" "^7.12.13" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - "@babel/plugin-syntax-top-level-await" "^7.14.5" - "@babel/plugin-transform-arrow-functions" "^7.16.7" - "@babel/plugin-transform-async-to-generator" "^7.16.8" - "@babel/plugin-transform-block-scoped-functions" "^7.16.7" - "@babel/plugin-transform-block-scoping" "^7.16.7" - "@babel/plugin-transform-classes" "^7.16.7" - "@babel/plugin-transform-computed-properties" "^7.16.7" - "@babel/plugin-transform-destructuring" "^7.16.7" - "@babel/plugin-transform-dotall-regex" "^7.16.7" - "@babel/plugin-transform-duplicate-keys" "^7.16.7" - "@babel/plugin-transform-exponentiation-operator" "^7.16.7" - "@babel/plugin-transform-for-of" "^7.16.7" - "@babel/plugin-transform-function-name" "^7.16.7" - "@babel/plugin-transform-literals" "^7.16.7" - "@babel/plugin-transform-member-expression-literals" "^7.16.7" - "@babel/plugin-transform-modules-amd" "^7.16.7" - "@babel/plugin-transform-modules-commonjs" "^7.16.8" - "@babel/plugin-transform-modules-systemjs" "^7.16.7" - "@babel/plugin-transform-modules-umd" "^7.16.7" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.16.8" - "@babel/plugin-transform-new-target" "^7.16.7" - "@babel/plugin-transform-object-super" "^7.16.7" - "@babel/plugin-transform-parameters" "^7.16.7" - "@babel/plugin-transform-property-literals" "^7.16.7" - "@babel/plugin-transform-regenerator" "^7.16.7" - "@babel/plugin-transform-reserved-words" "^7.16.7" - "@babel/plugin-transform-shorthand-properties" "^7.16.7" - "@babel/plugin-transform-spread" "^7.16.7" - "@babel/plugin-transform-sticky-regex" "^7.16.7" - "@babel/plugin-transform-template-literals" "^7.16.7" - "@babel/plugin-transform-typeof-symbol" "^7.16.7" - "@babel/plugin-transform-unicode-escapes" "^7.16.7" - "@babel/plugin-transform-unicode-regex" "^7.16.7" - "@babel/preset-modules" "^0.1.5" - "@babel/types" "^7.16.8" - babel-plugin-polyfill-corejs2 "^0.3.0" - babel-plugin-polyfill-corejs3 "^0.5.0" - babel-plugin-polyfill-regenerator "^0.3.0" - core-js-compat "^3.20.2" - semver "^6.3.0" - - "@babel/preset-modules@^0.1.5": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.5.tgz#ef939d6e7f268827e1841638dc6ff95515e115d9" - integrity sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA== - dependencies: - "@babel/helper-plugin-utils" "^7.0.0" - "@babel/plugin-proposal-unicode-property-regex" "^7.4.4" - "@babel/plugin-transform-dotall-regex" "^7.4.4" - "@babel/types" "^7.4.4" - esutils "^2.0.2" - - "@babel/preset-typescript@7.16.7", "@babel/preset-typescript@^7.16.7": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.16.7.tgz#ab114d68bb2020afc069cd51b37ff98a046a70b9" - integrity sha512-WbVEmgXdIyvzB77AQjGBEyYPZx+8tTsO50XtfozQrkW8QB2rLJpH2lgx0TRw5EJrBxOZQ+wCcyPVQvS8tjEHpQ== - dependencies: - "@babel/helper-plugin-utils" "^7.16.7" - "@babel/helper-validator-option" "^7.16.7" - "@babel/plugin-transform-typescript" "^7.16.7" - - "@babel/runtime-corejs3@^7.10.2": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/runtime-corejs3/-/runtime-corejs3-7.17.7.tgz#cf914f474c490ef1aa8661d47adaa0a993636e7e" - integrity sha512-TvliGJjhxis5m7xIMvlXH/xG8Oa/LK0SCUCyfKD6nLi42n5fB4WibDJ0g9trmmBB6hwpMNx+Lzbxy9/4gpMaVw== - dependencies: - core-js-pure "^3.20.2" - regenerator-runtime "^0.13.4" - - "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.13.17", "@babel/runtime@^7.14.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.16.3", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.0": - version "7.17.7" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.7.tgz#a5f3328dc41ff39d803f311cfe17703418cf9825" - integrity sha512-L6rvG9GDxaLgFjg41K+5Yv9OMrU98sWe+Ykmc6FDJW/+vYZMhdOMKkISgzptMaERHvS2Y2lw9MDRm2gHhlQQoA== - dependencies: - regenerator-runtime "^0.13.4" - - "@babel/runtime@^7.8.4": - version "7.17.8" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.8.tgz#3e56e4aff81befa55ac3ac6a0967349fd1c5bca2" - integrity sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA== - dependencies: - regenerator-runtime "^0.13.4" - - "@babel/template@^7.12.13", "@babel/template@^7.16.7", "@babel/template@^7.3.3": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.7.tgz#8d126c8701fde4d66b264b3eba3d96f07666d155" - integrity sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/parser" "^7.16.7" - "@babel/types" "^7.16.7" - - "@babel/traverse@7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.13.0.tgz#6d95752475f86ee7ded06536de309a65fc8966cc" - integrity sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ== - dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.13.0" - "@babel/helper-function-name" "^7.12.13" - "@babel/helper-split-export-declaration" "^7.12.13" - "@babel/parser" "^7.13.0" - "@babel/types" "^7.13.0" - debug "^4.1.0" - globals "^11.1.0" - lodash "^4.17.19" - - "@babel/traverse@^7.1.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.16.10", "@babel/traverse@^7.16.7", "@babel/traverse@^7.16.8", "@babel/traverse@^7.17.0", "@babel/traverse@^7.17.3", "@babel/traverse@^7.7.2": - version "7.17.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.17.3.tgz#0ae0f15b27d9a92ba1f2263358ea7c4e7db47b57" - integrity sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw== - dependencies: - "@babel/code-frame" "^7.16.7" - "@babel/generator" "^7.17.3" - "@babel/helper-environment-visitor" "^7.16.7" - "@babel/helper-function-name" "^7.16.7" - "@babel/helper-hoist-variables" "^7.16.7" - "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/parser" "^7.17.3" - "@babel/types" "^7.17.0" - debug "^4.1.0" - globals "^11.1.0" - - "@babel/types@7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.0.tgz#74424d2816f0171b4100f0ab34e9a374efdf7f80" - integrity sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA== - dependencies: - "@babel/helper-validator-identifier" "^7.12.11" - lodash "^4.17.19" - to-fast-properties "^2.0.0" - - "@babel/types@^7.0.0", "@babel/types@^7.13.0", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.17.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": - version "7.17.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.17.0.tgz#a826e368bccb6b3d84acd76acad5c0d87342390b" - integrity sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw== - dependencies: - "@babel/helper-validator-identifier" "^7.16.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== - - "@boxyhq/saml-jackson@0.3.6": - version "0.3.6" - resolved "https://registry.yarnpkg.com/@boxyhq/saml-jackson/-/saml-jackson-0.3.6.tgz#fc76e696094d5dcb780167a8c730d073cdb4ec1b" - integrity sha512-5kRk4VqkxlYwAJ1S4KMvrbn0R6YddT1/dA60w6HVO4CZiKDnspreLG6Q3WSU8D1hLj7mhqDUz4Joacvwynx+fg== - dependencies: - "@boxyhq/saml20" "0.2.0" - "@peculiar/webcrypto" "1.2.3" - "@peculiar/x509" "1.6.1" - cors "2.8.5" - express "4.17.2" - mongodb "4.3.0" - mysql2 "2.3.3" - pg "8.7.1" - rambda "7.0.1" - redis "4.0.1" - reflect-metadata "0.1.13" - ripemd160 "2.0.2" - thumbprint "0.0.1" - typeorm "0.2.41" - xml-crypto "2.1.3" - xml2js "0.4.23" - xmlbuilder "15.1.1" - - "@boxyhq/saml20@0.2.0": - version "0.2.0" - resolved "https://registry.yarnpkg.com/@boxyhq/saml20/-/saml20-0.2.0.tgz#251eb675f3c08ff65bc67e009d5f5119dcc4719f" - integrity sha512-octyllYuCD//N8DagXB5BMpDQ4B1aA6wTDC0XI72z2E+GJMwPzwYLSvzwKpSetsaXRUYPiIexxqyPYRqA+Uqnw== - dependencies: - "@xmldom/xmldom" "0.7.5" - lodash "^4.17.21" - thumbprint "^0.0.1" - xml-crypto "^2.1.3" - xml2js "^0.4.23" - - "@cnakazawa/watch@^1.0.3": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" - integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== - dependencies: - exec-sh "^0.3.2" - minimist "^1.2.0" - - "@cspotcode/source-map-consumer@0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" - integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== - - "@cspotcode/source-map-support@0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5" - integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA== - dependencies: - "@cspotcode/source-map-consumer" "0.8.0" - - "@daily-co/daily-js@^0.18.0": - version "0.18.0" - resolved "https://registry.yarnpkg.com/@daily-co/daily-js/-/daily-js-0.18.0.tgz#b8341c2ac12b6e27fec2ab187be6cca699e60dce" - integrity sha512-MXY6mpC0bJ1RCbVLlNioOfoNFhMX8lwoI/G9t3d/CAQqO9brxnp73t2Ltyaf2SXMIR+S88flgtfMcRtEBnFsjQ== - dependencies: - "@babel/runtime" "^7.12.5" - bowser "^2.8.1" - events "^3.1.0" - fast-equals "^1.6.3" - lodash "^4.17.15" - - "@daily-co/daily-js@^0.21.0": - version "0.21.0" - resolved "https://registry.yarnpkg.com/@daily-co/daily-js/-/daily-js-0.21.0.tgz#f0773d5e430dc886763ddfe8d100262774db3ce6" - integrity sha512-yE5xXrhaVWxXMGYraJkFvuohHnuh8ytv2WudQxcPe+et3Vajx2gG4TMnBAu+bH6Nf3WBcIJjETIq++jjvrSUiw== - dependencies: - "@babel/runtime" "^7.12.5" - bowser "^2.8.1" - events "^3.1.0" - fast-equals "^1.6.3" - lodash "^4.17.15" - - "@emotion/babel-plugin@^11.7.1": - version "11.7.2" - resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.7.2.tgz#fec75f38a6ab5b304b0601c74e2a5e77c95e5fa0" - integrity sha512-6mGSCWi9UzXut/ZAN6lGFu33wGR3SJisNl3c0tvlmb8XChH1b2SUvxvnOh7hvLpqyRdHHU9AiazV3Cwbk5SXKQ== - dependencies: - "@babel/helper-module-imports" "^7.12.13" - "@babel/plugin-syntax-jsx" "^7.12.13" - "@babel/runtime" "^7.13.10" - "@emotion/hash" "^0.8.0" - "@emotion/memoize" "^0.7.5" - "@emotion/serialize" "^1.0.2" - babel-plugin-macros "^2.6.1" - convert-source-map "^1.5.0" - escape-string-regexp "^4.0.0" - find-root "^1.1.0" - source-map "^0.5.7" - stylis "4.0.13" - - "@emotion/cache@^11.4.0", "@emotion/cache@^11.7.1": - version "11.7.1" - resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.7.1.tgz#08d080e396a42e0037848214e8aa7bf879065539" - integrity sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A== - dependencies: - "@emotion/memoize" "^0.7.4" - "@emotion/sheet" "^1.1.0" - "@emotion/utils" "^1.0.0" - "@emotion/weak-memoize" "^0.2.5" - stylis "4.0.13" - - "@emotion/hash@^0.8.0": - version "0.8.0" - resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413" - integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow== - - "@emotion/memoize@^0.7.4", "@emotion/memoize@^0.7.5": - version "0.7.5" - resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.7.5.tgz#2c40f81449a4e554e9fc6396910ed4843ec2be50" - integrity sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ== - - "@emotion/react@^11.1.1": - version "11.8.2" - resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.8.2.tgz#e51f5e6372e22e82780836c9288da19af4b51e70" - integrity sha512-+1bcHBaNJv5nkIIgnGKVsie3otS0wF9f1T1hteF3WeVvMNQEtfZ4YyFpnphGoot3ilU/wWMgP2SgIDuHLE/wAA== - dependencies: - "@babel/runtime" "^7.13.10" - "@emotion/babel-plugin" "^11.7.1" - "@emotion/cache" "^11.7.1" - "@emotion/serialize" "^1.0.2" - "@emotion/utils" "^1.1.0" - "@emotion/weak-memoize" "^0.2.5" - hoist-non-react-statics "^3.3.1" - - "@emotion/serialize@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.0.2.tgz#77cb21a0571c9f68eb66087754a65fa97bfcd965" - integrity sha512-95MgNJ9+/ajxU7QIAruiOAdYNjxZX7G2mhgrtDWswA21VviYIRP1R5QilZ/bDY42xiKsaktP4egJb3QdYQZi1A== - dependencies: - "@emotion/hash" "^0.8.0" - "@emotion/memoize" "^0.7.4" - "@emotion/unitless" "^0.7.5" - "@emotion/utils" "^1.0.0" - csstype "^3.0.2" - - "@emotion/sheet@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.1.0.tgz#56d99c41f0a1cda2726a05aa6a20afd4c63e58d2" - integrity sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g== - - "@emotion/unitless@^0.7.5": - version "0.7.5" - resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.7.5.tgz#77211291c1900a700b8a78cfafda3160d76949ed" - integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg== - - "@emotion/utils@^1.0.0", "@emotion/utils@^1.1.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.1.0.tgz#86b0b297f3f1a0f2bdb08eeac9a2f49afd40d0cf" - integrity sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ== - - "@emotion/weak-memoize@^0.2.5": - version "0.2.5" - resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz#8eed982e2ee6f7f4e44c253e12962980791efd46" - integrity sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA== - - "@eslint/eslintrc@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.1.tgz#8b5e1c49f4077235516bc9ec7d41378c0f69b8c6" - integrity sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ== - dependencies: - ajv "^6.12.4" - debug "^4.3.2" - espree "^9.3.1" - globals "^13.9.0" - ignore "^5.2.0" - import-fresh "^3.2.1" - js-yaml "^4.1.0" - minimatch "^3.0.4" - strip-json-comments "^3.1.1" - - "@ethereumjs/common@^2.5.0", "@ethereumjs/common@^2.6.1": - version "2.6.2" - resolved "https://registry.yarnpkg.com/@ethereumjs/common/-/common-2.6.2.tgz#eb006c9329c75c80f634f340dc1719a5258244df" - integrity sha512-vDwye5v0SVeuDky4MtKsu+ogkH2oFUV8pBKzH/eNBzT8oI91pKa8WyzDuYuxOQsgNgv5R34LfFDh2aaw3H4HbQ== - dependencies: - crc-32 "^1.2.0" - ethereumjs-util "^7.1.4" - - "@ethereumjs/tx@^3.3.2": - version "3.5.0" - resolved "https://registry.yarnpkg.com/@ethereumjs/tx/-/tx-3.5.0.tgz#783b0aeb08518b9991b23f5155763bbaf930a037" - integrity sha512-/+ZNbnJhQhXC83Xuvy6I9k4jT5sXiV0tMR9C+AzSSpcCV64+NB8dTE1m3x98RYMqb8+TLYWA+HML4F5lfXTlJw== - dependencies: - "@ethereumjs/common" "^2.6.1" - ethereumjs-util "^7.1.4" - - "@ethersproject/abi@5.0.7": - version "5.0.7" - resolved "https://registry.yarnpkg.com/@ethersproject/abi/-/abi-5.0.7.tgz#79e52452bd3ca2956d0e1c964207a58ad1a0ee7b" - integrity sha512-Cqktk+hSIckwP/W8O47Eef60VwmoSC/L3lY0+dIBhQPCNn9E4V7rwmm2aFrNRRDJfFlGuZ1khkQUOc3oBX+niw== - dependencies: - "@ethersproject/address" "^5.0.4" - "@ethersproject/bignumber" "^5.0.7" - "@ethersproject/bytes" "^5.0.4" - "@ethersproject/constants" "^5.0.4" - "@ethersproject/hash" "^5.0.4" - "@ethersproject/keccak256" "^5.0.3" - "@ethersproject/logger" "^5.0.5" - "@ethersproject/properties" "^5.0.3" - "@ethersproject/strings" "^5.0.4" - - "@ethersproject/abstract-provider@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-provider/-/abstract-provider-5.6.0.tgz#0c4ac7054650dbd9c476cf5907f588bbb6ef3061" - integrity sha512-oPMFlKLN+g+y7a79cLK3WiLcjWFnZQtXWgnLAbHZcN3s7L4v90UHpTOrLk+m3yr0gt+/h9STTM6zrr7PM8uoRw== - dependencies: - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/networks" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/transactions" "^5.6.0" - "@ethersproject/web" "^5.6.0" - - "@ethersproject/abstract-signer@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/abstract-signer/-/abstract-signer-5.6.0.tgz#9cd7ae9211c2b123a3b29bf47aab17d4d016e3e7" - integrity sha512-WOqnG0NJKtI8n0wWZPReHtaLkDByPL67tn4nBaDAhmVq8sjHTPbCdz4DRhVu/cfTOvfy9w3iq5QZ7BX7zw56BQ== - dependencies: - "@ethersproject/abstract-provider" "^5.6.0" - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - - "@ethersproject/address@^5.0.4", "@ethersproject/address@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/address/-/address-5.6.0.tgz#13c49836d73e7885fc148ad633afad729da25012" - integrity sha512-6nvhYXjbXsHPS+30sHZ+U4VMagFC/9zAk6Gd/h3S21YW4+yfb0WfRtaAIZ4kfM4rrVwqiy284LP0GtL5HXGLxQ== - dependencies: - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/keccak256" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/rlp" "^5.6.0" - - "@ethersproject/base64@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/base64/-/base64-5.6.0.tgz#a12c4da2a6fb86d88563216b0282308fc15907c9" - integrity sha512-2Neq8wxJ9xHxCF9TUgmKeSh9BXJ6OAxWfeGWvbauPh8FuHEjamgHilllx8KkSd5ErxyHIX7Xv3Fkcud2kY9ezw== - dependencies: - "@ethersproject/bytes" "^5.6.0" - - "@ethersproject/bignumber@^5.0.7", "@ethersproject/bignumber@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bignumber/-/bignumber-5.6.0.tgz#116c81b075c57fa765a8f3822648cf718a8a0e26" - integrity sha512-VziMaXIUHQlHJmkv1dlcd6GY2PmT0khtAqaMctCIDogxkrarMzA9L94KN1NeXqqOfFD6r0sJT3vCTOFSmZ07DA== - dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - bn.js "^4.11.9" - - "@ethersproject/bytes@^5.0.4", "@ethersproject/bytes@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.6.0.tgz#81652f2a0e04533575befadce555213c11d8aa20" - integrity sha512-3hJPlYemb9V4VLfJF5BfN0+55vltPZSHU3QKUyP9M3Y2TcajbiRrz65UG+xVHOzBereB1b9mn7r12o177xgN7w== - dependencies: - "@ethersproject/logger" "^5.6.0" - - "@ethersproject/constants@^5.0.4", "@ethersproject/constants@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/constants/-/constants-5.6.0.tgz#55e3eb0918584d3acc0688e9958b0cedef297088" - integrity sha512-SrdaJx2bK0WQl23nSpV/b1aq293Lh0sUaZT/yYKPDKn4tlAbkH96SPJwIhwSwTsoQQZxuh1jnqsKwyymoiBdWA== - dependencies: - "@ethersproject/bignumber" "^5.6.0" - - "@ethersproject/hash@^5.0.4": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/hash/-/hash-5.6.0.tgz#d24446a5263e02492f9808baa99b6e2b4c3429a2" - integrity sha512-fFd+k9gtczqlr0/BruWLAu7UAOas1uRRJvOR84uDf4lNZ+bTkGl366qvniUZHKtlqxBRU65MkOobkmvmpHU+jA== - dependencies: - "@ethersproject/abstract-signer" "^5.6.0" - "@ethersproject/address" "^5.6.0" - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/keccak256" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/strings" "^5.6.0" - - "@ethersproject/keccak256@^5.0.3", "@ethersproject/keccak256@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/keccak256/-/keccak256-5.6.0.tgz#fea4bb47dbf8f131c2e1774a1cecbfeb9d606459" - integrity sha512-tk56BJ96mdj/ksi7HWZVWGjCq0WVl/QvfhFQNeL8fxhBlGoP+L80uDCiQcpJPd+2XxkivS3lwRm3E0CXTfol0w== - dependencies: - "@ethersproject/bytes" "^5.6.0" - js-sha3 "0.8.0" - - "@ethersproject/logger@^5.0.5", "@ethersproject/logger@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.6.0.tgz#d7db1bfcc22fd2e4ab574cba0bb6ad779a9a3e7a" - integrity sha512-BiBWllUROH9w+P21RzoxJKzqoqpkyM1pRnEKG69bulE9TSQD8SAIvTQqIMZmmCO8pUNkgLP1wndX1gKghSpBmg== - - "@ethersproject/networks@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/networks/-/networks-5.6.0.tgz#486d03fff29b4b6b5414d47a232ded09fe10de5e" - integrity sha512-DaVzgyThzHgSDLuURhvkp4oviGoGe9iTZW4jMEORHDRCgSZ9K9THGFKqL+qGXqPAYLEgZTf5z2w56mRrPR1MjQ== - dependencies: - "@ethersproject/logger" "^5.6.0" - - "@ethersproject/properties@^5.0.3", "@ethersproject/properties@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/properties/-/properties-5.6.0.tgz#38904651713bc6bdd5bdd1b0a4287ecda920fa04" - integrity sha512-szoOkHskajKePTJSZ46uHUWWkbv7TzP2ypdEK6jGMqJaEt2sb0jCgfBo0gH0m2HBpRixMuJ6TBRaQCF7a9DoCg== - dependencies: - "@ethersproject/logger" "^5.6.0" - - "@ethersproject/rlp@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/rlp/-/rlp-5.6.0.tgz#55a7be01c6f5e64d6e6e7edb6061aa120962a717" - integrity sha512-dz9WR1xpcTL+9DtOT/aDO+YyxSSdO8YIS0jyZwHHSlAmnxA6cKU3TrTd4Xc/bHayctxTgGLYNuVVoiXE4tTq1g== - dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - - "@ethersproject/signing-key@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/signing-key/-/signing-key-5.6.0.tgz#4f02e3fb09e22b71e2e1d6dc4bcb5dafa69ce042" - integrity sha512-S+njkhowmLeUu/r7ir8n78OUKx63kBdMCPssePS89So1TH4hZqnWFsThEd/GiXYp9qMxVrydf7KdM9MTGPFukA== - dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - bn.js "^4.11.9" - elliptic "6.5.4" - hash.js "1.1.7" - - "@ethersproject/strings@^5.0.4", "@ethersproject/strings@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/strings/-/strings-5.6.0.tgz#9891b26709153d996bf1303d39a7f4bc047878fd" - integrity sha512-uv10vTtLTZqrJuqBZR862ZQjTIa724wGPWQqZrofaPI/kUsf53TBG0I0D+hQ1qyNtllbNzaW+PDPHHUI6/65Mg== - dependencies: - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/constants" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - - "@ethersproject/transactions@^5.0.0-beta.135", "@ethersproject/transactions@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/transactions/-/transactions-5.6.0.tgz#4b594d73a868ef6e1529a2f8f94a785e6791ae4e" - integrity sha512-4HX+VOhNjXHZyGzER6E/LVI2i6lf9ejYeWD6l4g50AdmimyuStKc39kvKf1bXWQMg7QNVh+uC7dYwtaZ02IXeg== - dependencies: - "@ethersproject/address" "^5.6.0" - "@ethersproject/bignumber" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/constants" "^5.6.0" - "@ethersproject/keccak256" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/rlp" "^5.6.0" - "@ethersproject/signing-key" "^5.6.0" - - "@ethersproject/web@^5.6.0": - version "5.6.0" - resolved "https://registry.yarnpkg.com/@ethersproject/web/-/web-5.6.0.tgz#4bf8b3cbc17055027e1a5dd3c357e37474eaaeb8" - integrity sha512-G/XHj0hV1FxI2teHRfCGvfBUHFmU+YOSbCxlAMqJklxSa7QMiHFQfAxvwY2PFqgvdkxEKwRNr/eCjfAPEm2Ctg== - dependencies: - "@ethersproject/base64" "^5.6.0" - "@ethersproject/bytes" "^5.6.0" - "@ethersproject/logger" "^5.6.0" - "@ethersproject/properties" "^5.6.0" - "@ethersproject/strings" "^5.6.0" - - "@formatjs/ecma402-abstract@1.11.3": - version "1.11.3" - resolved "https://registry.yarnpkg.com/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.3.tgz#f25276dfd4ef3dac90da667c3961d8aa9732e384" - integrity sha512-kP/Buv5vVFMAYLHNvvUzr0lwRTU0u2WTy44Tqwku1X3C3lJ5dKqDCYVqA8wL+Y19Bq+MwHgxqd5FZJRCIsLRyQ== - dependencies: - "@formatjs/intl-localematcher" "0.2.24" - tslib "^2.1.0" - - "@formatjs/fast-memoize@1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@formatjs/fast-memoize/-/fast-memoize-1.2.1.tgz#e6f5aee2e4fd0ca5edba6eba7668e2d855e0fc21" - integrity sha512-Rg0e76nomkz3vF9IPlKeV+Qynok0r7YZjL6syLz4/urSg0IbjPZCB/iYUMNsYA643gh4mgrX3T7KEIFIxJBQeg== - dependencies: - tslib "^2.1.0" - - "@formatjs/icu-messageformat-parser@2.0.18": - version "2.0.18" - resolved "https://registry.yarnpkg.com/@formatjs/icu-messageformat-parser/-/icu-messageformat-parser-2.0.18.tgz#b09e8f16b88e988fd125e7c5810300e8a6dd2c42" - integrity sha512-vquIzsAJJmZ5jWVH8dEgUKcbG4yu3KqtyPet+q35SW5reLOvblkfeCXTRW2TpIwNXzdVqsJBwjbTiRiSU9JxwQ== - dependencies: - "@formatjs/ecma402-abstract" "1.11.3" - "@formatjs/icu-skeleton-parser" "1.3.5" - tslib "^2.1.0" - - "@formatjs/icu-skeleton-parser@1.3.5": - version "1.3.5" - resolved "https://registry.yarnpkg.com/@formatjs/icu-skeleton-parser/-/icu-skeleton-parser-1.3.5.tgz#babc93a1c36383cf87cbb3d2f2145d26c2f7cb40" - integrity sha512-Nhyo2/6kG7ZfgeEfo02sxviOuBcvtzH6SYUharj3DLCDJH3A/4OxkKcmx/2PWGX4bc6iSieh+FA94CsKDxnZBQ== - dependencies: - "@formatjs/ecma402-abstract" "1.11.3" - tslib "^2.1.0" - - "@formatjs/intl-displaynames@5.4.2": - version "5.4.2" - resolved "https://registry.yarnpkg.com/@formatjs/intl-displaynames/-/intl-displaynames-5.4.2.tgz#feb6b41087a88286d178032490a8ca78bafd4c56" - integrity sha512-SLesCDan9NCMqBbHPXMEwqAcPn3tnbQw0sv0rssH1JQDLDUQYwKXL93kz30X3yskTyQS7N+pd47bhoIe3kbXyw== - dependencies: - "@formatjs/ecma402-abstract" "1.11.3" - "@formatjs/intl-localematcher" "0.2.24" - tslib "^2.1.0" - - "@formatjs/intl-listformat@6.5.2": - version "6.5.2" - resolved "https://registry.yarnpkg.com/@formatjs/intl-listformat/-/intl-listformat-6.5.2.tgz#7fbc310db89e866250e34084e914894c67e09254" - integrity sha512-/IYagQJkzTvpBlhhaysGYNgM3o72WBg1ZWZcpookkgXEJbINwLP5kVagHxmgxffYKs1CDzQ8rmKHghu2qR/7zw== - dependencies: - "@formatjs/ecma402-abstract" "1.11.3" - "@formatjs/intl-localematcher" "0.2.24" - tslib "^2.1.0" - - "@formatjs/intl-localematcher@0.2.24": - version "0.2.24" - resolved "https://registry.yarnpkg.com/@formatjs/intl-localematcher/-/intl-localematcher-0.2.24.tgz#b49fd753c0f54421f26a3c1d0e9cf98a3966e78f" - integrity sha512-K/HRGo6EMnCbhpth/y3u4rW4aXkmQNqRe1L2G+Y5jNr3v0gYhvaucV8WixNju/INAMbPBlbsRBRo/nfjnoOnxQ== - dependencies: - tslib "^2.1.0" - - "@formatjs/intl@2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@formatjs/intl/-/intl-2.1.0.tgz#383b186b1f26195ac896fc6912871abccf9dad2d" - integrity sha512-1iGGqKcCym+ZH+cktHa6YILVGn8Sve+yuYK7hJpN21JiPKCPJuFJViKFY6rDM5jnj5LDCeH8N5YbhQjccDVOVA== - dependencies: - "@formatjs/ecma402-abstract" "1.11.3" - "@formatjs/fast-memoize" "1.2.1" - "@formatjs/icu-messageformat-parser" "2.0.18" - "@formatjs/intl-displaynames" "5.4.2" - "@formatjs/intl-listformat" "6.5.2" - intl-messageformat "9.11.4" - tslib "^2.1.0" - - "@glidejs/glide@^3.5.2": - version "3.5.2" - resolved "https://registry.yarnpkg.com/@glidejs/glide/-/glide-3.5.2.tgz#7012c5920ecf202bbda44d8526fc979984b6dd54" - integrity sha512-7jGciNJ2bQ4eZLSNlSZ+VAyW63kALf420CvkEpK4lEsUfWJq9odqimci0YCiyNyMUFB+pWHwLYyNc57dijYsCg== - - "@headlessui/react@^1.4.1": - version "1.5.0" - resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.5.0.tgz#483b44ba2c8b8d4391e1d2c863898d7dd0cc0296" - integrity sha512-aaRnYxBb3MU2FNJf3Ut9RMTUqqU3as0aI1lQhgo2n9Fa67wRu14iOGqx93xB+uMNVfNwZ5B3y/Ndm7qZGuFeMQ== - - "@heroicons/react@^1.0.4", "@heroicons/react@^1.0.5": - version "1.0.6" - resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-1.0.6.tgz#35dd26987228b39ef2316db3b1245c42eb19e324" - integrity sha512-JJCXydOFWMDpCP4q13iEplA503MQO3xLoZiKum+955ZCtHINWnx26CUxVxxFQu/uLb4LW3ge15ZpzIkXKkJ8oQ== - - "@hookform/error-message@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@hookform/error-message/-/error-message-2.0.0.tgz#9b1b037fd816ea9b1531c06aa7fab5f5154aa740" - integrity sha512-Y90nHzjgL2MP7GFy75kscdvxrCTjtyxGmOLLxX14nd08OXRIh9lMH/y9Kpdo0p1IPowJBiZMHyueg7p+yrqynQ== - - "@hookform/resolvers@^2.8.1", "@hookform/resolvers@^2.8.5": - version "2.8.8" - resolved "https://registry.yarnpkg.com/@hookform/resolvers/-/resolvers-2.8.8.tgz#17cf806485435877fdafce9f3bee6ff68f7f87b6" - integrity sha512-meAEDur1IJBfKyTo9yPYAuzjIfrxA7m9Ov+1nxaW/YupsqMeseWifoUjWK03+hz/RJizsVQAaUjVxFEkyu0GWg== - - "@humanwhocodes/config-array@^0.9.2": - version "0.9.5" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" - integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw== - dependencies: - "@humanwhocodes/object-schema" "^1.2.1" - debug "^4.1.1" - minimatch "^3.0.4" - - "@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== - - "@istanbuljs/load-nyc-config@^1.0.0": - version "1.1.0" - resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" - integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== - dependencies: - camelcase "^5.3.1" - find-up "^4.1.0" - get-package-type "^0.1.0" - js-yaml "^3.13.1" - resolve-from "^5.0.0" - - "@istanbuljs/schema@^0.1.2": - version "0.1.3" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" - integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== - - "@jest/console@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.6.2.tgz#4e04bc464014358b03ab4937805ee36a0aeb98f2" - integrity sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g== - dependencies: - "@jest/types" "^26.6.2" - "@types/node" "*" - chalk "^4.0.0" - jest-message-util "^26.6.2" - jest-util "^26.6.2" - slash "^3.0.0" - - "@jest/console@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.5.1.tgz#260fe7239602fe5130a94f1aa386eff54b014bba" - integrity sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg== - dependencies: - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - jest-message-util "^27.5.1" - jest-util "^27.5.1" - slash "^3.0.0" - - "@jest/core@^26.6.3": - version "26.6.3" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.6.3.tgz#7639fcb3833d748a4656ada54bde193051e45fad" - integrity sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw== - dependencies: - "@jest/console" "^26.6.2" - "@jest/reporters" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.4" - jest-changed-files "^26.6.2" - jest-config "^26.6.3" - jest-haste-map "^26.6.2" - jest-message-util "^26.6.2" - jest-regex-util "^26.0.0" - jest-resolve "^26.6.2" - jest-resolve-dependencies "^26.6.3" - jest-runner "^26.6.3" - jest-runtime "^26.6.3" - jest-snapshot "^26.6.2" - jest-util "^26.6.2" - jest-validate "^26.6.2" - jest-watcher "^26.6.2" - micromatch "^4.0.2" - p-each-series "^2.1.0" - rimraf "^3.0.0" - slash "^3.0.0" - strip-ansi "^6.0.0" - - "@jest/core@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.5.1.tgz#267ac5f704e09dc52de2922cbf3af9edcd64b626" - integrity sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ== - dependencies: - "@jest/console" "^27.5.1" - "@jest/reporters" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - emittery "^0.8.1" - exit "^0.1.2" - graceful-fs "^4.2.9" - jest-changed-files "^27.5.1" - jest-config "^27.5.1" - jest-haste-map "^27.5.1" - jest-message-util "^27.5.1" - jest-regex-util "^27.5.1" - jest-resolve "^27.5.1" - jest-resolve-dependencies "^27.5.1" - jest-runner "^27.5.1" - jest-runtime "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" - jest-validate "^27.5.1" - jest-watcher "^27.5.1" - micromatch "^4.0.4" - rimraf "^3.0.0" - slash "^3.0.0" - strip-ansi "^6.0.0" - - "@jest/environment@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.6.2.tgz#ba364cc72e221e79cc8f0a99555bf5d7577cf92c" - integrity sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA== - dependencies: - "@jest/fake-timers" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - jest-mock "^26.6.2" - - "@jest/environment@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.5.1.tgz#d7425820511fe7158abbecc010140c3fd3be9c74" - integrity sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA== - dependencies: - "@jest/fake-timers" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - jest-mock "^27.5.1" - - "@jest/fake-timers@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.6.2.tgz#459c329bcf70cee4af4d7e3f3e67848123535aad" - integrity sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA== - dependencies: - "@jest/types" "^26.6.2" - "@sinonjs/fake-timers" "^6.0.1" - "@types/node" "*" - jest-message-util "^26.6.2" - jest-mock "^26.6.2" - jest-util "^26.6.2" - - "@jest/fake-timers@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.5.1.tgz#76979745ce0579c8a94a4678af7a748eda8ada74" - integrity sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ== - dependencies: - "@jest/types" "^27.5.1" - "@sinonjs/fake-timers" "^8.0.1" - "@types/node" "*" - jest-message-util "^27.5.1" - jest-mock "^27.5.1" - jest-util "^27.5.1" - - "@jest/globals@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.6.2.tgz#5b613b78a1aa2655ae908eba638cc96a20df720a" - integrity sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA== - dependencies: - "@jest/environment" "^26.6.2" - "@jest/types" "^26.6.2" - expect "^26.6.2" - - "@jest/globals@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.5.1.tgz#7ac06ce57ab966566c7963431cef458434601b2b" - integrity sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/types" "^27.5.1" - expect "^27.5.1" - - "@jest/reporters@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.6.2.tgz#1f518b99637a5f18307bd3ecf9275f6882a667f6" - integrity sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" - chalk "^4.0.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.2" - graceful-fs "^4.2.4" - istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^4.0.3" - istanbul-lib-report "^3.0.0" - istanbul-lib-source-maps "^4.0.0" - istanbul-reports "^3.0.2" - jest-haste-map "^26.6.2" - jest-resolve "^26.6.2" - jest-util "^26.6.2" - jest-worker "^26.6.2" - slash "^3.0.0" - source-map "^0.6.0" - string-length "^4.0.1" - terminal-link "^2.0.0" - v8-to-istanbul "^7.0.0" - optionalDependencies: - node-notifier "^8.0.0" - - "@jest/reporters@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.5.1.tgz#ceda7be96170b03c923c37987b64015812ffec04" - integrity sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw== - dependencies: - "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.2" - 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-haste-map "^27.5.1" - jest-resolve "^27.5.1" - jest-util "^27.5.1" - jest-worker "^27.5.1" - slash "^3.0.0" - source-map "^0.6.0" - string-length "^4.0.1" - terminal-link "^2.0.0" - v8-to-istanbul "^8.1.0" - - "@jest/source-map@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.6.2.tgz#29af5e1e2e324cafccc936f218309f54ab69d535" - integrity sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA== - dependencies: - callsites "^3.0.0" - graceful-fs "^4.2.4" - source-map "^0.6.0" - - "@jest/source-map@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.5.1.tgz#6608391e465add4205eae073b55e7f279e04e8cf" - integrity sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg== - dependencies: - callsites "^3.0.0" - graceful-fs "^4.2.9" - source-map "^0.6.0" - - "@jest/test-result@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.6.2.tgz#55da58b62df134576cc95476efa5f7949e3f5f18" - integrity sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ== - dependencies: - "@jest/console" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/istanbul-lib-coverage" "^2.0.0" - collect-v8-coverage "^1.0.0" - - "@jest/test-result@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.5.1.tgz#56a6585fa80f7cdab72b8c5fc2e871d03832f5bb" - integrity sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag== - dependencies: - "@jest/console" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/istanbul-lib-coverage" "^2.0.0" - collect-v8-coverage "^1.0.0" - - "@jest/test-sequencer@^26.6.3": - version "26.6.3" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz#98e8a45100863886d074205e8ffdc5a7eb582b17" - integrity sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw== - dependencies: - "@jest/test-result" "^26.6.2" - graceful-fs "^4.2.4" - jest-haste-map "^26.6.2" - jest-runner "^26.6.3" - jest-runtime "^26.6.3" - - "@jest/test-sequencer@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz#4057e0e9cea4439e544c6353c6affe58d095745b" - integrity sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ== - dependencies: - "@jest/test-result" "^27.5.1" - graceful-fs "^4.2.9" - jest-haste-map "^27.5.1" - jest-runtime "^27.5.1" - - "@jest/transform@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.6.2.tgz#5ac57c5fa1ad17b2aae83e73e45813894dcf2e4b" - integrity sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA== - dependencies: - "@babel/core" "^7.1.0" - "@jest/types" "^26.6.2" - babel-plugin-istanbul "^6.0.0" - chalk "^4.0.0" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.2.4" - jest-haste-map "^26.6.2" - jest-regex-util "^26.0.0" - jest-util "^26.6.2" - micromatch "^4.0.2" - pirates "^4.0.1" - slash "^3.0.0" - source-map "^0.6.1" - write-file-atomic "^3.0.0" - - "@jest/transform@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.5.1.tgz#6c3501dcc00c4c08915f292a600ece5ecfe1f409" - integrity sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw== - dependencies: - "@babel/core" "^7.1.0" - "@jest/types" "^27.5.1" - 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 "^27.5.1" - jest-regex-util "^27.5.1" - jest-util "^27.5.1" - micromatch "^4.0.4" - pirates "^4.0.4" - slash "^3.0.0" - source-map "^0.6.1" - write-file-atomic "^3.0.0" - - "@jest/types@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" - integrity sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^15.0.0" - chalk "^4.0.0" - - "@jest/types@^27.2.5", "@jest/types@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80" - integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^3.0.0" - "@types/node" "*" - "@types/yargs" "^16.0.0" - chalk "^4.0.0" - - "@jimp/bmp@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/bmp/-/bmp-0.16.1.tgz#6e2da655b2ba22e721df0795423f34e92ef13768" - integrity sha512-iwyNYQeBawrdg/f24x3pQ5rEx+/GwjZcCXd3Kgc+ZUd+Ivia7sIqBsOnDaMZdKCBPlfW364ekexnlOqyVa0NWg== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - bmp-js "^0.1.0" - - "@jimp/core@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/core/-/core-0.16.1.tgz#68c4288f6ef7f31a0f6b859ba3fb28dae930d39d" - integrity sha512-la7kQia31V6kQ4q1kI/uLimu8FXx7imWVajDGtwUG8fzePLWDFJyZl0fdIXVCL1JW2nBcRHidUot6jvlRDi2+g== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - any-base "^1.1.0" - buffer "^5.2.0" - exif-parser "^0.1.12" - file-type "^9.0.0" - load-bmfont "^1.3.1" - mkdirp "^0.5.1" - phin "^2.9.1" - pixelmatch "^4.0.2" - tinycolor2 "^1.4.1" - - "@jimp/custom@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/custom/-/custom-0.16.1.tgz#28b659c59e20a1d75a0c46067bd3f4bd302cf9c5" - integrity sha512-DNUAHNSiUI/j9hmbatD6WN/EBIyeq4AO0frl5ETtt51VN1SvE4t4v83ZA/V6ikxEf3hxLju4tQ5Pc3zmZkN/3A== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/core" "^0.16.1" - - "@jimp/gif@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/gif/-/gif-0.16.1.tgz#d1f7c3a58f4666482750933af8b8f4666414f3ca" - integrity sha512-r/1+GzIW1D5zrP4tNrfW+3y4vqD935WBXSc8X/wm23QTY9aJO9Lw6PEdzpYCEY+SOklIFKaJYUAq/Nvgm/9ryw== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - gifwrap "^0.9.2" - omggif "^1.0.9" - - "@jimp/jpeg@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/jpeg/-/jpeg-0.16.1.tgz#3b7bb08a4173f2f6d81f3049b251df3ee2ac8175" - integrity sha512-8352zrdlCCLFdZ/J+JjBslDvml+fS3Z8gttdml0We759PnnZGqrnPRhkOEOJbNUlE+dD4ckLeIe6NPxlS/7U+w== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - jpeg-js "0.4.2" - - "@jimp/plugin-blit@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-blit/-/plugin-blit-0.16.1.tgz#09ea919f9d326de3b9c2826fe4155da37dde8edb" - integrity sha512-fKFNARm32RoLSokJ8WZXHHH2CGzz6ire2n1Jh6u+XQLhk9TweT1DcLHIXwQMh8oR12KgjbgsMGvrMVlVknmOAg== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - - "@jimp/plugin-blur@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-blur/-/plugin-blur-0.16.1.tgz#e614fa002797dcd662e705d4cea376e7db968bf5" - integrity sha512-1WhuLGGj9MypFKRcPvmW45ht7nXkOKu+lg3n2VBzIB7r4kKNVchuI59bXaCYQumOLEqVK7JdB4glaDAbCQCLyw== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - - "@jimp/plugin-circle@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-circle/-/plugin-circle-0.16.1.tgz#20e3194a67ca29740aba2630fd4d0a89afa27491" - integrity sha512-JK7yi1CIU7/XL8hdahjcbGA3V7c+F+Iw+mhMQhLEi7Q0tCnZ69YJBTamMiNg3fWPVfMuvWJJKOBRVpwNTuaZRg== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - - "@jimp/plugin-color@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-color/-/plugin-color-0.16.1.tgz#0f298ba74dee818b663834cd80d53e56f3755233" - integrity sha512-9yQttBAO5SEFj7S6nJK54f+1BnuBG4c28q+iyzm1JjtnehjqMg6Ljw4gCSDCvoCQ3jBSYHN66pmwTV74SU1B7A== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - tinycolor2 "^1.4.1" - - "@jimp/plugin-contain@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-contain/-/plugin-contain-0.16.1.tgz#3c5f5c495fd9bb08a970739d83694934f58123f2" - integrity sha512-44F3dUIjBDHN+Ym/vEfg+jtjMjAqd2uw9nssN67/n4FdpuZUVs7E7wadKY1RRNuJO+WgcD5aDQcsvurXMETQTg== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - - "@jimp/plugin-cover@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-cover/-/plugin-cover-0.16.1.tgz#0e8caec16a40abe15b1b32e5383a603a3306dc41" - integrity sha512-YztWCIldBAVo0zxcQXR+a/uk3/TtYnpKU2CanOPJ7baIuDlWPsG+YE4xTsswZZc12H9Kl7CiziEbDtvF9kwA/Q== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - - "@jimp/plugin-crop@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-crop/-/plugin-crop-0.16.1.tgz#b362497c873043fe47ba881ab08604bf7226f50f" - integrity sha512-UQdva9oQzCVadkyo3T5Tv2CUZbf0klm2cD4cWMlASuTOYgaGaFHhT9st+kmfvXjKL8q3STkBu/zUPV6PbuV3ew== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - - "@jimp/plugin-displace@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-displace/-/plugin-displace-0.16.1.tgz#4dd9db518c3e78de9d723f86a234bf98922afe8d" - integrity sha512-iVAWuz2+G6Heu8gVZksUz+4hQYpR4R0R/RtBzpWEl8ItBe7O6QjORAkhxzg+WdYLL2A/Yd4ekTpvK0/qW8hTVw== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - - "@jimp/plugin-dither@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-dither/-/plugin-dither-0.16.1.tgz#b47de2c0bb09608bed228b41c3cd01a85ec2d45b" - integrity sha512-tADKVd+HDC9EhJRUDwMvzBXPz4GLoU6s5P7xkVq46tskExYSptgj5713J5Thj3NMgH9Rsqu22jNg1H/7tr3V9Q== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - - "@jimp/plugin-fisheye@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-fisheye/-/plugin-fisheye-0.16.1.tgz#f625047b6cdbe1b83b89e9030fd025ab19cdb1a4" - integrity sha512-BWHnc5hVobviTyIRHhIy9VxI1ACf4CeSuCfURB6JZm87YuyvgQh5aX5UDKtOz/3haMHXBLP61ZBxlNpMD8CG4A== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - - "@jimp/plugin-flip@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-flip/-/plugin-flip-0.16.1.tgz#7a99ea22bde802641017ed0f2615870c144329bb" - integrity sha512-KdxTf0zErfZ8DyHkImDTnQBuHby+a5YFdoKI/G3GpBl3qxLBvC+PWkS2F/iN3H7wszP7/TKxTEvWL927pypT0w== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - - "@jimp/plugin-gaussian@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-gaussian/-/plugin-gaussian-0.16.1.tgz#0845e314085ccd52e34fad9a83949bc0d81a68e8" - integrity sha512-u9n4wjskh3N1mSqketbL6tVcLU2S5TEaFPR40K6TDv4phPLZALi1Of7reUmYpVm8mBDHt1I6kGhuCJiWvzfGyg== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - - "@jimp/plugin-invert@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-invert/-/plugin-invert-0.16.1.tgz#7e6f5a15707256f3778d06921675bbcf18545c97" - integrity sha512-2DKuyVXANH8WDpW9NG+PYFbehzJfweZszFYyxcaewaPLN0GxvxVLOGOPP1NuUTcHkOdMFbE0nHDuB7f+sYF/2w== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - - "@jimp/plugin-mask@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-mask/-/plugin-mask-0.16.1.tgz#e7f2460e05c3cda7af5e76f33ccb0579f66f90df" - integrity sha512-snfiqHlVuj4bSFS0v96vo2PpqCDMe4JB+O++sMo5jF5mvGcGL6AIeLo8cYqPNpdO6BZpBJ8MY5El0Veckhr39Q== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - - "@jimp/plugin-normalize@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-normalize/-/plugin-normalize-0.16.1.tgz#032dfd88eefbc4dedc8b1b2d243832e4f3af30c8" - integrity sha512-dOQfIOvGLKDKXPU8xXWzaUeB0nvkosHw6Xg1WhS1Z5Q0PazByhaxOQkSKgUryNN/H+X7UdbDvlyh/yHf3ITRaw== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - - "@jimp/plugin-print@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-print/-/plugin-print-0.16.1.tgz#66b803563f9d109825970714466e6ab9ae639ff6" - integrity sha512-ceWgYN40jbN4cWRxixym+csyVymvrryuKBQ+zoIvN5iE6OyS+2d7Mn4zlNgumSczb9GGyZZESIgVcBDA1ezq0Q== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - load-bmfont "^1.4.0" - - "@jimp/plugin-resize@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-resize/-/plugin-resize-0.16.1.tgz#65e39d848ed13ba2d6c6faf81d5d590396571d10" - integrity sha512-u4JBLdRI7dargC04p2Ha24kofQBk3vhaf0q8FwSYgnCRwxfvh2RxvhJZk9H7Q91JZp6wgjz/SjvEAYjGCEgAwQ== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - - "@jimp/plugin-rotate@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-rotate/-/plugin-rotate-0.16.1.tgz#53fb5d51a4b3d05af9c91c2a8fffe5d7a1a47c8c" - integrity sha512-ZUU415gDQ0VjYutmVgAYYxC9Og9ixu2jAGMCU54mSMfuIlmohYfwARQmI7h4QB84M76c9hVLdONWjuo+rip/zg== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - - "@jimp/plugin-scale@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-scale/-/plugin-scale-0.16.1.tgz#89f6ba59feed3429847ed226aebda33a240cc647" - integrity sha512-jM2QlgThIDIc4rcyughD5O7sOYezxdafg/2Xtd1csfK3z6fba3asxDwthqPZAgitrLgiKBDp6XfzC07Y/CefUw== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - - "@jimp/plugin-shadow@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-shadow/-/plugin-shadow-0.16.1.tgz#a7af892a740febf41211e10a5467c3c5c521a04c" - integrity sha512-MeD2Is17oKzXLnsphAa1sDstTu6nxscugxAEk3ji0GV1FohCvpHBcec0nAq6/czg4WzqfDts+fcPfC79qWmqrA== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - - "@jimp/plugin-threshold@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugin-threshold/-/plugin-threshold-0.16.1.tgz#34f3078f9965145b7ae26c53a32ad74b1195bbf5" - integrity sha512-iGW8U/wiCSR0+6syrPioVGoSzQFt4Z91SsCRbgNKTAk7D+XQv6OI78jvvYg4o0c2FOlwGhqz147HZV5utoSLxA== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - - "@jimp/plugins@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/plugins/-/plugins-0.16.1.tgz#9f08544c97226d6460a16ced79f57e85bec3257b" - integrity sha512-c+lCqa25b+4q6mJZSetlxhMoYuiltyS+ValLzdwK/47+aYsq+kcJNl+TuxIEKf59yr9+5rkbpsPkZHLF/V7FFA== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/plugin-blit" "^0.16.1" - "@jimp/plugin-blur" "^0.16.1" - "@jimp/plugin-circle" "^0.16.1" - "@jimp/plugin-color" "^0.16.1" - "@jimp/plugin-contain" "^0.16.1" - "@jimp/plugin-cover" "^0.16.1" - "@jimp/plugin-crop" "^0.16.1" - "@jimp/plugin-displace" "^0.16.1" - "@jimp/plugin-dither" "^0.16.1" - "@jimp/plugin-fisheye" "^0.16.1" - "@jimp/plugin-flip" "^0.16.1" - "@jimp/plugin-gaussian" "^0.16.1" - "@jimp/plugin-invert" "^0.16.1" - "@jimp/plugin-mask" "^0.16.1" - "@jimp/plugin-normalize" "^0.16.1" - "@jimp/plugin-print" "^0.16.1" - "@jimp/plugin-resize" "^0.16.1" - "@jimp/plugin-rotate" "^0.16.1" - "@jimp/plugin-scale" "^0.16.1" - "@jimp/plugin-shadow" "^0.16.1" - "@jimp/plugin-threshold" "^0.16.1" - timm "^1.6.1" - - "@jimp/png@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/png/-/png-0.16.1.tgz#f24cfc31529900b13a2dd9d4fdb4460c1e4d814e" - integrity sha512-iyWoCxEBTW0OUWWn6SveD4LePW89kO7ZOy5sCfYeDM/oTPLpR8iMIGvZpZUz1b8kvzFr27vPst4E5rJhGjwsdw== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/utils" "^0.16.1" - pngjs "^3.3.3" - - "@jimp/tiff@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/tiff/-/tiff-0.16.1.tgz#0e8756695687d7574b6bc73efab0acd4260b7a12" - integrity sha512-3K3+xpJS79RmSkAvFMgqY5dhSB+/sxhwTFA9f4AVHUK0oKW+u6r52Z1L0tMXHnpbAdR9EJ+xaAl2D4x19XShkQ== - dependencies: - "@babel/runtime" "^7.7.2" - utif "^2.0.1" - - "@jimp/types@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/types/-/types-0.16.1.tgz#0dbab37b3202315c91010f16c31766d35a2322cc" - integrity sha512-g1w/+NfWqiVW4CaXSJyD28JQqZtm2eyKMWPhBBDCJN9nLCN12/Az0WFF3JUAktzdsEC2KRN2AqB1a2oMZBNgSQ== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/bmp" "^0.16.1" - "@jimp/gif" "^0.16.1" - "@jimp/jpeg" "^0.16.1" - "@jimp/png" "^0.16.1" - "@jimp/tiff" "^0.16.1" - timm "^1.6.1" - - "@jimp/utils@^0.16.1": - version "0.16.1" - resolved "https://registry.yarnpkg.com/@jimp/utils/-/utils-0.16.1.tgz#2f51e6f14ff8307c4aa83d5e1a277da14a9fe3f7" - integrity sha512-8fULQjB0x4LzUSiSYG6ZtQl355sZjxbv8r9PPAuYHzS9sGiSHJQavNqK/nKnpDsVkU88/vRGcE7t3nMU0dEnVw== - dependencies: - "@babel/runtime" "^7.7.2" - regenerator-runtime "^0.13.3" - - "@jitsu/sdk-js@^2.2.4": - version "2.4.0" - resolved "https://registry.yarnpkg.com/@jitsu/sdk-js/-/sdk-js-2.4.0.tgz#fccfe5821766e7b623e89386ef0d359d797031b4" - integrity sha512-2BO6NYJOLdKy3jt5fCAQPXukK+esFTRD1g3D1vqLPq7iHgCwOJgG1V9j02ILeTEFlaFKeu59B3FM81orhbGymA== - - "@jridgewell/resolve-uri@^3.0.3": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz#68eb521368db76d040a6315cdb24bf2483037b9c" - integrity sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew== - - "@jridgewell/sourcemap-codec@^1.4.10": - version "1.4.11" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.11.tgz#771a1d8d744eeb71b6adb35808e1a6c7b9b8c8ec" - integrity sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg== - - "@jridgewell/trace-mapping@^0.3.0": - version "0.3.4" - resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.4.tgz#f6a0832dffd5b8a6aaa633b7d9f8e8e94c83a0c3" - integrity sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ== - dependencies: - "@jridgewell/resolve-uri" "^3.0.3" - "@jridgewell/sourcemap-codec" "^1.4.10" - - "@mdx-js/loader@^2.0.0-next.9": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@mdx-js/loader/-/loader-2.0.0.tgz#4ff3278d341e7a15ecf87c4623a8ecd533cb3dbc" - integrity sha512-gPuzQQ19K9OUkgRVMUMRu8lYXgJPwSQaHcc6olvRxbdUMms4mtn6so3v4v8J+f58bAk0R98IzBbkvBenAOZu7g== - dependencies: - "@mdx-js/mdx" "^2.0.0" - source-map "^0.7.0" - - "@mdx-js/mdx@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@mdx-js/mdx/-/mdx-2.0.0.tgz#7f270df1e77c46f8338fc32089016b3ea383d023" - integrity sha512-Q/Zv+gdm80qcxpmL/Dtd/b9+UyZjjJUCQeZyywLAQqre648hRYgeGNPu7Bl2hB7M8/WBLXpabQEKW3dmGdDTDQ== - dependencies: - "@types/estree-jsx" "^0.0.1" - "@types/mdx" "^2.0.0" - astring "^1.6.0" - estree-util-build-jsx "^2.0.0" - estree-util-is-identifier-name "^2.0.0" - estree-walker "^3.0.0" - hast-util-to-estree "^2.0.0" - markdown-extensions "^1.0.0" - periscopic "^3.0.0" - remark-mdx "^2.0.0" - remark-parse "^10.0.0" - remark-rehype "^10.0.0" - unified "^10.0.0" - unist-util-position-from-estree "^1.0.0" - unist-util-stringify-position "^3.0.0" - unist-util-visit "^4.0.0" - vfile "^5.0.0" - - "@mdx-js/react@^1.6.16": - version "1.6.22" - resolved "https://registry.yarnpkg.com/@mdx-js/react/-/react-1.6.22.tgz#ae09b4744fddc74714ee9f9d6f17a66e77c43573" - integrity sha512-TDoPum4SHdfPiGSAaRBw7ECyI8VaHpK8GJugbJIJuqyh6kzw9ZLJZW3HGL3NNrJGxcAixUvqROm+YuQOo5eXtg== - - "@metamask/object-multiplex@^1.1.0": - version "1.2.0" - resolved "https://registry.yarnpkg.com/@metamask/object-multiplex/-/object-multiplex-1.2.0.tgz#38fc15c142f61939391e1b9a8eed679696c7e4f4" - integrity sha512-hksV602d3NWE2Q30Mf2Np1WfVKaGqfJRy9vpHAmelbaD0OkDt06/0KQkRR6UVYdMbTbkuEu8xN5JDUU80inGwQ== - dependencies: - end-of-stream "^1.4.4" - once "^1.4.0" - readable-stream "^2.3.3" - - "@metamask/providers@^8.1.1": - version "8.1.1" - resolved "https://registry.yarnpkg.com/@metamask/providers/-/providers-8.1.1.tgz#7b0dbb54700c949aafba24c9b98e6f4e9d81f325" - integrity sha512-CG1sAuD6Mp4MZ5U90anf1FT0moDbStGXT+80TQFYXJbBeTQjhp321WgC/F2IgIJ3mFqOiByC3MQHLuunEVMQOA== - dependencies: - "@metamask/object-multiplex" "^1.1.0" - "@metamask/safe-event-emitter" "^2.0.0" - "@types/chrome" "^0.0.136" - detect-browser "^5.2.0" - eth-rpc-errors "^4.0.2" - extension-port-stream "^2.0.1" - fast-deep-equal "^2.0.1" - is-stream "^2.0.0" - json-rpc-engine "^6.1.0" - json-rpc-middleware-stream "^3.0.0" - pump "^3.0.0" - webextension-polyfill-ts "^0.25.0" - - "@metamask/safe-event-emitter@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@metamask/safe-event-emitter/-/safe-event-emitter-2.0.0.tgz#af577b477c683fad17c619a78208cede06f9605c" - integrity sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q== - - "@microsoft/microsoft-graph-types-beta@0.15.0-preview": - version "0.15.0-preview" - resolved "https://registry.yarnpkg.com/@microsoft/microsoft-graph-types-beta/-/microsoft-graph-types-beta-0.15.0-preview.tgz#fed0a99be4e1151d566cf063f024913fb48640cd" - integrity sha512-M0zC4t3pmkDz7Qsjx/iZcS+zRuckzsbHESvT9qjLFv64RUgkRmDdmhcvPMiUqUzw/h3YxfYAq9MU+XWjROk/dg== - - "@next/bundle-analyzer@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/bundle-analyzer/-/bundle-analyzer-12.1.0.tgz#9f6d6cda2a26220c936805be407243e22790f4b7" - integrity sha512-pOtWRWaKQXff8A80Ex3E67EH8XuERHxBPn8cQgKzfhRKQwoTEareHe2nWJO1uXTQm6m7ZRhmhb4+uwp+UvmITQ== - dependencies: - webpack-bundle-analyzer "4.3.0" - - "@next/env@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/env/-/env-12.1.0.tgz#73713399399b34aa5a01771fb73272b55b22c314" - integrity sha512-nrIgY6t17FQ9xxwH3jj0a6EOiQ/WDHUos35Hghtr+SWN/ntHIQ7UpuvSi0vaLzZVHQWaDupKI+liO5vANcDeTQ== - - "@next/eslint-plugin-next@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/eslint-plugin-next/-/eslint-plugin-next-12.1.0.tgz#32586a11378b3ffa5a93ac40a3c44ad99d70e95a" - integrity sha512-WFiyvSM2G5cQmh32t/SiQuJ+I2O+FHVlK/RFw5b1565O2kEM/36EXncjt88Pa+X5oSc+1SS+tWxowWJd1lqI+g== - dependencies: - glob "7.1.7" - - "@next/swc-android-arm64@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.1.0.tgz#865ba3a9afc204ff2bdeea49dd64d58705007a39" - integrity sha512-/280MLdZe0W03stA69iL+v6I+J1ascrQ6FrXBlXGCsGzrfMaGr7fskMa0T5AhQIVQD4nA/46QQWxG//DYuFBcA== - - "@next/swc-darwin-arm64@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.0.tgz#08e8b411b8accd095009ed12efbc2f1d4d547135" - integrity sha512-R8vcXE2/iONJ1Unf5Ptqjk6LRW3bggH+8drNkkzH4FLEQkHtELhvcmJwkXcuipyQCsIakldAXhRbZmm3YN1vXg== - - "@next/swc-darwin-x64@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.0.tgz#fcd684497a76e8feaca88db3c394480ff0b007cd" - integrity sha512-ieAz0/J0PhmbZBB8+EA/JGdhRHBogF8BWaeqR7hwveb6SYEIJaDNQy0I+ZN8gF8hLj63bEDxJAs/cEhdnTq+ug== - - "@next/swc-linux-arm-gnueabihf@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.0.tgz#9ec6380a27938a5799aaa6035c205b3c478468a7" - integrity sha512-njUd9hpl6o6A5d08dC0cKAgXKCzm5fFtgGe6i0eko8IAdtAPbtHxtpre3VeSxdZvuGFh+hb0REySQP9T1ttkog== - - "@next/swc-linux-arm64-gnu@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.0.tgz#7f4196dff1049cea479607c75b81033ae2dbd093" - integrity sha512-OqangJLkRxVxMhDtcb7Qn1xjzFA3s50EIxY7mljbSCLybU+sByPaWAHY4px97ieOlr2y4S0xdPKkQ3BCAwyo6Q== - - "@next/swc-linux-arm64-musl@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.0.tgz#b445f767569cdc2dddee785ca495e1a88c025566" - integrity sha512-hB8cLSt4GdmOpcwRe2UzI5UWn6HHO/vLkr5OTuNvCJ5xGDwpPXelVkYW/0+C3g5axbDW2Tym4S+MQCkkH9QfWA== - - "@next/swc-linux-x64-gnu@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.0.tgz#67610e9be4fbc987de7535f1bcb17e45fe12f90e" - integrity sha512-OKO4R/digvrVuweSw/uBM4nSdyzsBV5EwkUeeG4KVpkIZEe64ZwRpnFB65bC6hGwxIBnTv5NMSnJ+0K/WmG78A== - - "@next/swc-linux-x64-musl@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.0.tgz#ea19a23db08a9f2e34ac30401f774cf7d1669d31" - integrity sha512-JohhgAHZvOD3rQY7tlp7NlmvtvYHBYgY0x5ZCecUT6eCCcl9lv6iV3nfu82ErkxNk1H893fqH0FUpznZ/H3pSw== - - "@next/swc-win32-arm64-msvc@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.0.tgz#eadf054fc412085659b98e145435bbba200b5283" - integrity sha512-T/3gIE6QEfKIJ4dmJk75v9hhNiYZhQYAoYm4iVo1TgcsuaKLFa+zMPh4056AHiG6n9tn2UQ1CFE8EoybEsqsSw== - - "@next/swc-win32-ia32-msvc@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.0.tgz#68faeae10c89f698bf9d28759172b74c9c21bda1" - integrity sha512-iwnKgHJdqhIW19H9PRPM9j55V6RdcOo6rX+5imx832BCWzkDbyomWnlzBfr6ByUYfhohb8QuH4hSGEikpPqI0Q== - - "@next/swc-win32-x64-msvc@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.0.tgz#d27e7e76c87a460a4da99c5bfdb1618dcd6cd064" - integrity sha512-aBvcbMwuanDH4EMrL2TthNJy+4nP59Bimn8egqv6GHMVj0a44cU6Au4PjOhLNqEh9l+IpRGBqMTzec94UdC5xg== - - "@node-redis/client@^1.0.1": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@node-redis/client/-/client-1.0.4.tgz#fe185750df3bcc07524f63fe8dbc8d14d22d6cbb" - integrity sha512-IM/NRAqg7MvNC3bIRQipXGrEarunrdgvrbAzsd3ty93LSHi/M+ybQulOERQi8a3M+P5BL8HenwXjiIoKm6ml2g== - dependencies: - cluster-key-slot "1.1.0" - generic-pool "3.8.2" - redis-parser "3.0.0" - yallist "4.0.0" - - "@node-redis/json@^1.0.1": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@node-redis/json/-/json-1.0.2.tgz#8ad2d0f026698dc1a4238cc3d1eb099a3bee5ab8" - integrity sha512-qVRgn8WfG46QQ08CghSbY4VhHFgaTY71WjpwRBGEuqGPfWwfRcIf3OqSpR7Q/45X+v3xd8mvYjywqh0wqJ8T+g== - - "@node-redis/search@^1.0.1": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@node-redis/search/-/search-1.0.3.tgz#7c3d026bf994caf82019fd0c3924cfc09f041a29" - integrity sha512-rsrzkGWI84di/uYtEctS/4qLusWt0DESx/psjfB0TFpORDhe7JfC0h8ary+eHulTksumor244bXLRSqQXbFJmw== - - "@node-redis/time-series@^1.0.0": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@node-redis/time-series/-/time-series-1.0.2.tgz#5dd3638374edd85ebe0aa6b0e87addc88fb9df69" - integrity sha512-HGQ8YooJ8Mx7l28tD7XjtB3ImLEjlUxG1wC1PAjxu6hPJqjPshUZxAICzDqDjtIbhDTf48WXXUcx8TQJB1XTKA== - - "@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - - "@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - - "@nodelib/fs.walk@^1.2.3": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - - "@otplib/core@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@otplib/core/-/core-12.0.1.tgz#73720a8cedce211fe5b3f683cd5a9c098eaf0f8d" - integrity sha512-4sGntwbA/AC+SbPhbsziRiD+jNDdIzsZ3JUyfZwjtKyc/wufl1pnSIaG4Uqx8ymPagujub0o92kgBnB89cuAMA== - - "@otplib/plugin-crypto@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@otplib/plugin-crypto/-/plugin-crypto-12.0.1.tgz#2b42c624227f4f9303c1c041fca399eddcbae25e" - integrity sha512-qPuhN3QrT7ZZLcLCyKOSNhuijUi9G5guMRVrxq63r9YNOxxQjPm59gVxLM+7xGnHnM6cimY57tuKsjK7y9LM1g== - dependencies: - "@otplib/core" "^12.0.1" - - "@otplib/plugin-thirty-two@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@otplib/plugin-thirty-two/-/plugin-thirty-two-12.0.1.tgz#5cc9b56e6e89f2a1fe4a2b38900ca4e11c87aa9e" - integrity sha512-MtT+uqRso909UkbrrYpJ6XFjj9D+x2Py7KjTO9JDPhL0bJUYVu5kFP4TFZW4NFAywrAtFRxOVY261u0qwb93gA== - dependencies: - "@otplib/core" "^12.0.1" - thirty-two "^1.0.2" - - "@otplib/preset-default@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@otplib/preset-default/-/preset-default-12.0.1.tgz#cb596553c08251e71b187ada4a2246ad2a3165ba" - integrity sha512-xf1v9oOJRyXfluBhMdpOkr+bsE+Irt+0D5uHtvg6x1eosfmHCsCC6ej/m7FXiWqdo0+ZUI6xSKDhJwc8yfiOPQ== - dependencies: - "@otplib/core" "^12.0.1" - "@otplib/plugin-crypto" "^12.0.1" - "@otplib/plugin-thirty-two" "^12.0.1" - - "@otplib/preset-v11@^12.0.1": - version "12.0.1" - resolved "https://registry.yarnpkg.com/@otplib/preset-v11/-/preset-v11-12.0.1.tgz#4c7266712e7230500b421ba89252963c838fc96d" - integrity sha512-9hSetMI7ECqbFiKICrNa4w70deTUfArtwXykPUvSHWOdzOlfa9ajglu7mNCntlvxycTiOAXkQGwjQCzzDEMRMg== - dependencies: - "@otplib/core" "^12.0.1" - "@otplib/plugin-crypto" "^12.0.1" - "@otplib/plugin-thirty-two" "^12.0.1" - - "@panva/hkdf@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@panva/hkdf/-/hkdf-1.0.1.tgz#ed0da773bd5f794d0603f5a5b5cee6d2354e5660" - integrity sha512-mMyQ9vjpuFqePkfe5bZVIf/H3Dmk6wA8Kjxff9RcO4kqzJo+Ek9pGKwZHpeMr7Eku0QhLXMCd7fNCSnEnRMubg== - - "@peculiar/asn1-cms@^2.0.44": - version "2.0.44" - resolved "https://registry.yarnpkg.com/@peculiar/asn1-cms/-/asn1-cms-2.0.44.tgz#ebe8bc1490d5301f9af4c84d1e23526994590efa" - integrity sha512-CzjCz8VZqG2jqRI/4YKCk3D9WS8V9cezt0tftWT5zmYxeZvAWOmtInj013zSooHEn1Oi65rzdDZ1m+wgascmiw== - dependencies: - "@peculiar/asn1-schema" "^2.0.44" - "@peculiar/asn1-x509" "^2.0.44" - "@peculiar/asn1-x509-attr" "^2.0.44" - asn1js "^2.1.1" - tslib "^2.3.0" - - "@peculiar/asn1-csr@^2.0.44": - version "2.0.44" - resolved "https://registry.yarnpkg.com/@peculiar/asn1-csr/-/asn1-csr-2.0.44.tgz#fd7df64036840a536dda71d474bdcaf4eb906907" - integrity sha512-9FG9ySzLyYIlk/W3o/mpE+ukn/XMokv+BysqyhNGifUet362slp+uF4XliKGLt53TO53uYCsQimVyTK4vwe/yg== - dependencies: - "@peculiar/asn1-schema" "^2.0.44" - "@peculiar/asn1-x509" "^2.0.44" - asn1js "^2.1.1" - tslib "^2.3.0" - - "@peculiar/asn1-ecc@^2.0.44": - version "2.0.44" - resolved "https://registry.yarnpkg.com/@peculiar/asn1-ecc/-/asn1-ecc-2.0.44.tgz#11f45324efb01419aa8fb779a2ea3c8dc712094b" - integrity sha512-GvfifE5xCZjEz9EsOl9gqTVgex9m7ATLloTaSE3Go+iG8bc7C/VDK8lOnFb3/UsCqfI46Gwh4Q3RQCP2JB3GDQ== - dependencies: - "@peculiar/asn1-schema" "^2.0.44" - "@peculiar/asn1-x509" "^2.0.44" - asn1js "^2.1.1" - tslib "^2.3.0" - - "@peculiar/asn1-pfx@^2.0.44": - version "2.0.44" - resolved "https://registry.yarnpkg.com/@peculiar/asn1-pfx/-/asn1-pfx-2.0.44.tgz#fd0b4b61b4427687305b2d2a94f0f2bb8d1b96b5" - integrity sha512-rVsGoZWMtensS9+AEtU97cImHXEu+Oi6K31/EzzzdqfUx/aF49RYCVKOyuCjUg5cwIOE93WsNm0hQFYB2pYwVQ== - dependencies: - "@peculiar/asn1-cms" "^2.0.44" - "@peculiar/asn1-pkcs8" "^2.0.44" - "@peculiar/asn1-rsa" "^2.0.44" - "@peculiar/asn1-schema" "^2.0.44" - asn1js "^2.1.1" - tslib "^2.3.0" - - "@peculiar/asn1-pkcs8@^2.0.44": - version "2.0.44" - resolved "https://registry.yarnpkg.com/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.0.44.tgz#62b28efcd59c495c4c3a46914859584a20033f8c" - integrity sha512-cs/zGEv/6Jxx14tZ6NS82PNJFMCb4aFOiAFzv+I1I1ud7o5wyDGOOAIiIs4vI+Z6xtkoSyF+hWH51kRutdFV4A== - dependencies: - "@peculiar/asn1-schema" "^2.0.44" - "@peculiar/asn1-x509" "^2.0.44" - asn1js "^2.1.1" - tslib "^2.3.0" - - "@peculiar/asn1-pkcs9@^2.0.44": - version "2.0.44" - resolved "https://registry.yarnpkg.com/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.0.44.tgz#9153555be59ea6518c77d7b28989fc4cc81ea338" - integrity sha512-b54VRWsM5NdIOlSuBbfBeximwVQIHcUoUdx10mHM6QuvZlXKciVP/nkerxg0ytQzC5BvPbohfYuiq46gYCPZSA== - dependencies: - "@peculiar/asn1-cms" "^2.0.44" - "@peculiar/asn1-pfx" "^2.0.44" - "@peculiar/asn1-pkcs8" "^2.0.44" - "@peculiar/asn1-schema" "^2.0.44" - "@peculiar/asn1-x509" "^2.0.44" - "@peculiar/asn1-x509-attr" "^2.0.44" - asn1js "^2.1.1" - tslib "^2.3.0" - - "@peculiar/asn1-rsa@^2.0.44": - version "2.0.44" - resolved "https://registry.yarnpkg.com/@peculiar/asn1-rsa/-/asn1-rsa-2.0.44.tgz#1a1455d129905c1378f8056af0d25429a34054fa" - integrity sha512-DYfo33Yl3y4Bu8V0RrAhKBZJDy1ESEGQzKVl7DxCUJna164/U/JB767W9ze0Vlq7quTawUJLMX3RRfesEFGigA== - dependencies: - "@peculiar/asn1-schema" "^2.0.44" - "@peculiar/asn1-x509" "^2.0.44" - asn1js "^2.1.1" - tslib "^2.3.0" - - "@peculiar/asn1-schema@^2.0.44": - version "2.0.44" - resolved "https://registry.yarnpkg.com/@peculiar/asn1-schema/-/asn1-schema-2.0.44.tgz#dcb1b8f84a4dd5f07f674028beade9c3de43cc06" - integrity sha512-uaCnjQ9A9WwQSMuDJcNOCYEPXTahgKbFMvI7eMOMd8lXgx0J1eU7F3BoMsK5PFxa3dVUxjSQbaOjfgGoeHGgoQ== - dependencies: - "@types/asn1js" "^2.0.2" - asn1js "^2.1.1" - pvtsutils "^1.2.1" - tslib "^2.3.0" - - "@peculiar/asn1-x509-attr@^2.0.44": - version "2.0.44" - resolved "https://registry.yarnpkg.com/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.0.44.tgz#b3146aa6f57c531858114ef1ed229cd41cf610dc" - integrity sha512-mYyf1fMT1JVrmPInjqVC3O2Vm3LBm7sd75Mg2hKB0A/zPKIYZ5WRz396lliucHagg17PalMjDOxtIQFOqs1WGg== - dependencies: - "@peculiar/asn1-schema" "^2.0.44" - "@peculiar/asn1-x509" "^2.0.44" - asn1js "^2.1.1" - tslib "^2.3.0" - - "@peculiar/asn1-x509@^2.0.44": - version "2.0.44" - resolved "https://registry.yarnpkg.com/@peculiar/asn1-x509/-/asn1-x509-2.0.44.tgz#0798819ffb9d8380dedbd98f6cd069952e9ec130" - integrity sha512-jKGy+7Ew1PADjzInblBaQWVdh9kTiy49lkTko/MiYg5lHyCi/N9xPtQCuincpY1UeNPwXaeoT2DXRJOuN6U/8A== - dependencies: - "@peculiar/asn1-schema" "^2.0.44" - asn1js "^2.1.1" - ipaddr.js "^2.0.1" - pvtsutils "^1.2.1" - tslib "^2.3.0" - - "@peculiar/json-schema@^1.1.12": - version "1.1.12" - resolved "https://registry.yarnpkg.com/@peculiar/json-schema/-/json-schema-1.1.12.tgz#fe61e85259e3b5ba5ad566cb62ca75b3d3cd5339" - integrity sha512-coUfuoMeIB7B8/NMekxaDzLhaYmp0HZNPEjYRm9goRou8UZIC3z21s0sL9AWoCw4EG876QyO3kYrc61WNF9B/w== - dependencies: - tslib "^2.0.0" - - "@peculiar/webcrypto@1.2.3": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@peculiar/webcrypto/-/webcrypto-1.2.3.tgz#79268ef0a8068bed2a40fc33bc68b4d3546fe2cc" - integrity sha512-q7wDfZy3k/tpnsYB23/MyyDkjn6IdHh8w+xwoVMS5cu6CjVoFzngXDZEOOuSE4zus2yO6ciQhhHxd4XkLpwVnQ== - dependencies: - "@peculiar/asn1-schema" "^2.0.44" - "@peculiar/json-schema" "^1.1.12" - pvtsutils "^1.2.1" - tslib "^2.3.1" - webcrypto-core "^1.4.0" - - "@peculiar/x509@1.6.1": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@peculiar/x509/-/x509-1.6.1.tgz#cc33807ab481824c69145e884cb40012aec501b0" - integrity sha512-C4oxpCuYasfjuhy6QRFJhs0R6gyeQSRsB7MsT6JkO3qaFi4b75mm8hNEKa+sIJPtTjXCC94tW9rHx1hw5dOvnQ== - dependencies: - "@peculiar/asn1-cms" "^2.0.44" - "@peculiar/asn1-csr" "^2.0.44" - "@peculiar/asn1-ecc" "^2.0.44" - "@peculiar/asn1-pkcs9" "^2.0.44" - "@peculiar/asn1-rsa" "^2.0.44" - "@peculiar/asn1-schema" "^2.0.44" - "@peculiar/asn1-x509" "^2.0.44" - pvtsutils "^1.2.1" - reflect-metadata "^0.1.13" - tslib "^2.3.1" - tsyringe "^4.6.0" - - "@playwright/test@^1.18.1": - version "1.19.2" - resolved "https://registry.yarnpkg.com/@playwright/test/-/test-1.19.2.tgz#429d1aa70f5e4cd521cdc8a5d9861ae4fcda3f7c" - integrity sha512-5oCmlYHjtOL662OxSkZBYGnoHWIQui7b4YHWNeSCYwhQjmjVcV5njRc8oBZlU8IwJgG7ZH2yhDk1haU96ygbWw== - dependencies: - "@babel/code-frame" "7.16.7" - "@babel/core" "7.16.12" - "@babel/plugin-proposal-class-properties" "7.16.7" - "@babel/plugin-proposal-dynamic-import" "7.16.7" - "@babel/plugin-proposal-export-namespace-from" "7.16.7" - "@babel/plugin-proposal-logical-assignment-operators" "7.16.7" - "@babel/plugin-proposal-nullish-coalescing-operator" "7.16.7" - "@babel/plugin-proposal-numeric-separator" "7.16.7" - "@babel/plugin-proposal-optional-chaining" "7.16.7" - "@babel/plugin-proposal-private-methods" "7.16.11" - "@babel/plugin-proposal-private-property-in-object" "7.16.7" - "@babel/plugin-syntax-async-generators" "7.8.4" - "@babel/plugin-syntax-json-strings" "7.8.3" - "@babel/plugin-syntax-object-rest-spread" "7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "7.8.3" - "@babel/plugin-transform-modules-commonjs" "7.16.8" - "@babel/plugin-transform-react-jsx" "7.16.7" - "@babel/preset-typescript" "7.16.7" - babel-plugin-module-resolver "4.1.0" - colors "1.4.0" - commander "8.3.0" - debug "4.3.3" - expect "27.2.5" - jest-matcher-utils "27.2.5" - jpeg-js "0.4.3" - json5 "2.2.0" - mime "3.0.0" - minimatch "3.0.4" - ms "2.1.3" - open "8.4.0" - pirates "4.0.4" - pixelmatch "5.2.1" - playwright-core "1.19.2" - pngjs "6.0.0" - rimraf "3.0.2" - source-map-support "0.4.18" - stack-utils "2.0.5" - yazl "2.5.1" - - "@polka/url@^1.0.0-next.20": - version "1.0.0-next.21" - resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.21.tgz#5de5a2385a35309427f6011992b544514d559aa1" - integrity sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g== - - "@prisma/client@3.10.0": - version "3.10.0" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.10.0.tgz#4782fe6f1b0e43c2a11a75ad4bb1098599d1dfb1" - integrity sha512-6P4sV7WFuODSfSoSEzCH1qfmWMrCUBk1LIIuTbQf6m1LI/IOpLN4lnqGDmgiBGprEzuWobnGLfe9YsXLn0inrg== - dependencies: - "@prisma/engines-version" "3.10.0-50.73e60b76d394f8d37d8ebd1f8918c79029f0db86" - - "@prisma/debug@3.8.1": - version "3.8.1" - resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-3.8.1.tgz#3c6717d6e0501651709714774ea6d90127c6a2d3" - integrity sha512-ft4VPTYME1UBJ7trfrBuF2w9jX1ipDy786T9fAEskNGb+y26gPDqz5fiEWc2kgHNeVdz/qTI/V3wXILRyEcgxQ== - dependencies: - "@types/debug" "4.1.7" - ms "2.1.3" - strip-ansi "6.0.1" - - "@prisma/engines-version@3.10.0-50.73e60b76d394f8d37d8ebd1f8918c79029f0db86": - version "3.10.0-50.73e60b76d394f8d37d8ebd1f8918c79029f0db86" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.10.0-50.73e60b76d394f8d37d8ebd1f8918c79029f0db86.tgz#82750856fa637dd89b8f095d2dcc6ac0631231c6" - integrity sha512-cVYs5gyQH/qyut24hUvDznCfPrWiNMKNfPb9WmEoiU6ihlkscIbCfkmuKTtspVLWRdl0LqjYEC7vfnPv17HWhw== - - "@prisma/engines@3.10.0-50.73e60b76d394f8d37d8ebd1f8918c79029f0db86": - version "3.10.0-50.73e60b76d394f8d37d8ebd1f8918c79029f0db86" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.10.0-50.73e60b76d394f8d37d8ebd1f8918c79029f0db86.tgz#2964113729a78b8b21e186b5592affd1fde73c16" - integrity sha512-LjRssaWu9w2SrXitofnutRIyURI7l0veQYIALz7uY4shygM9nMcK3omXcObRm7TAcw3Z+9ytfK1B+ySOsOesxQ== - - "@prisma/generator-helper@~3.8.1": - version "3.8.1" - resolved "https://registry.yarnpkg.com/@prisma/generator-helper/-/generator-helper-3.8.1.tgz#eb1dcc8382faa17c784a9d0e0d79fd207a222aa4" - integrity sha512-3zSy+XTEjmjLj6NO+/YPN1Cu7or3xA11TOoOnLRJ9G4pTT67RJXjK0L9Xy5n+3I0Xlb7xrWCgo8MvQQLMWzxPA== - dependencies: - "@prisma/debug" "3.8.1" - "@types/cross-spawn" "6.0.2" - chalk "4.1.2" - cross-spawn "7.0.3" - - "@radix-ui/number@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@radix-ui/number/-/number-0.1.0.tgz#73ad13d5cc5f75fa5e147d72e5d5d5e50d688256" - integrity sha512-rpf6QiOWLHAkM4FEMYu9i+5Jr8cKT893+R4mPpcdsy4LD7omr9JfdOqj/h/xPA5+EcVrpMMlU6rrRYpUB5UI8g== - dependencies: - "@babel/runtime" "^7.13.10" - - "@radix-ui/popper@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@radix-ui/popper/-/popper-0.1.0.tgz#c387a38f31b7799e1ea0d2bb1ca0c91c2931b063" - integrity sha512-uzYeElL3w7SeNMuQpXiFlBhTT+JyaNMCwDfjKkrzugEcYrf5n52PHqncNdQPUtR42hJh8V9FsqyEDbDxkeNjJQ== - dependencies: - "@babel/runtime" "^7.13.10" - csstype "^3.0.4" - - "@radix-ui/primitive@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-0.1.0.tgz#6206b97d379994f0d1929809db035733b337e543" - integrity sha512-tqxZKybwN5Fa3VzZry4G6mXAAb9aAqKmPtnVbZpL0vsBwvOHTBwsjHVPXylocYLwEtBY9SCe665bYnNB515uoA== - dependencies: - "@babel/runtime" "^7.13.10" - - "@radix-ui/react-arrow@0.1.4": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@radix-ui/react-arrow/-/react-arrow-0.1.4.tgz#a871448a418cd3507d83840fdd47558cb961672b" - integrity sha512-BB6XzAb7Ml7+wwpFdYVtZpK1BlMgqyafSQNGzhIpSZ4uXvXOHPlR5GP8M449JkeQzgQjv9Mp1AsJxFC0KuOtuA== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/react-primitive" "0.1.4" - - "@radix-ui/react-avatar@^0.1.0": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@radix-ui/react-avatar/-/react-avatar-0.1.4.tgz#36210e629e0eecde44027195c82d2a4101cbd7e9" - integrity sha512-RTs3KQTToVKJHHsn/E+vC2MyP0LnA6uMdcD7thwaCJEbI6NAvf56Y+RNJPSsGXz1o2LkD7Iy5SogsrzBwXQk6A== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/react-context" "0.1.1" - "@radix-ui/react-primitive" "0.1.4" - "@radix-ui/react-use-callback-ref" "0.1.0" - "@radix-ui/react-use-layout-effect" "0.1.0" - - "@radix-ui/react-collapsible@^0.1.0": - version "0.1.6" - resolved "https://registry.yarnpkg.com/@radix-ui/react-collapsible/-/react-collapsible-0.1.6.tgz#3eeadac476761b3c9b8dd91e8a32eb1a547e5a06" - integrity sha512-Gkf8VuqMc6HTLzA2AxVYnyK6aMczVLpatCjdD9Lj4wlYLXCz9KtiqZYslLMeqnQFLwLyZS0WKX/pQ8j5fioIBw== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/primitive" "0.1.0" - "@radix-ui/react-compose-refs" "0.1.0" - "@radix-ui/react-context" "0.1.1" - "@radix-ui/react-id" "0.1.5" - "@radix-ui/react-presence" "0.1.2" - "@radix-ui/react-primitive" "0.1.4" - "@radix-ui/react-use-controllable-state" "0.1.0" - "@radix-ui/react-use-layout-effect" "0.1.0" - - "@radix-ui/react-collection@0.1.4": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@radix-ui/react-collection/-/react-collection-0.1.4.tgz#734061ffd5bb93e88889d49b87391a73a63824c9" - integrity sha512-3muGI15IdgaDFjOcO7xX8a35HQRBRF6LH9pS6UCeZeRmbslkVeHyJRQr2rzICBUoX7zgIA0kXyMDbpQnJGyJTA== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/react-compose-refs" "0.1.0" - "@radix-ui/react-context" "0.1.1" - "@radix-ui/react-primitive" "0.1.4" - "@radix-ui/react-slot" "0.1.2" - - "@radix-ui/react-compose-refs@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-0.1.0.tgz#cff6e780a0f73778b976acff2c2a5b6551caab95" - integrity sha512-eyclbh+b77k+69Dk72q3694OHrn9B3QsoIRx7ywX341U9RK1ThgQjMFZoPtmZNQTksXHLNEiefR8hGVeFyInGg== - dependencies: - "@babel/runtime" "^7.13.10" - - "@radix-ui/react-context@0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-0.1.1.tgz#06996829ea124d9a1bc1dbe3e51f33588fab0875" - integrity sha512-PkyVX1JsLBioeu0jB9WvRpDBBLtLZohVDT3BB5CTSJqActma8S8030P57mWZb4baZifMvN7KKWPAA40UmWKkQg== - dependencies: - "@babel/runtime" "^7.13.10" - - "@radix-ui/react-dialog@^0.1.0": - version "0.1.7" - resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-0.1.7.tgz#285414cf66f5bbf42bc9935314e0381abe01e7d0" - integrity sha512-jXt8srGhHBRvEr9jhEAiwwJzWCWZoGRJ030aC9ja/gkRJbZdy0iD3FwXf+Ff4RtsZyLUMHW7VUwFOlz3Ixe1Vw== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/primitive" "0.1.0" - "@radix-ui/react-compose-refs" "0.1.0" - "@radix-ui/react-context" "0.1.1" - "@radix-ui/react-dismissable-layer" "0.1.5" - "@radix-ui/react-focus-guards" "0.1.0" - "@radix-ui/react-focus-scope" "0.1.4" - "@radix-ui/react-id" "0.1.5" - "@radix-ui/react-portal" "0.1.4" - "@radix-ui/react-presence" "0.1.2" - "@radix-ui/react-primitive" "0.1.4" - "@radix-ui/react-slot" "0.1.2" - "@radix-ui/react-use-controllable-state" "0.1.0" - aria-hidden "^1.1.1" - react-remove-scroll "^2.4.0" - - "@radix-ui/react-dismissable-layer@0.1.5": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-0.1.5.tgz#9379032351e79028d472733a5cc8ba4a0ea43314" - integrity sha512-J+fYWijkX4M4QKwf9dtu1oC0U6e6CEl8WhBp3Ad23yz2Hia0XCo6Pk/mp5CAFy4QBtQedTSkhW05AdtSOEoajQ== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/primitive" "0.1.0" - "@radix-ui/react-compose-refs" "0.1.0" - "@radix-ui/react-primitive" "0.1.4" - "@radix-ui/react-use-body-pointer-events" "0.1.1" - "@radix-ui/react-use-callback-ref" "0.1.0" - "@radix-ui/react-use-escape-keydown" "0.1.0" - - "@radix-ui/react-dropdown-menu@^0.1.1": - version "0.1.6" - resolved "https://registry.yarnpkg.com/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-0.1.6.tgz#3203229788cd57e552c9f19dcc7008e2b545919c" - integrity sha512-RZhtzjWwJ4ZBN7D8ek4Zn+ilHzYuYta9yIxFnbC0pfqMnSi67IQNONo1tuuNqtFh9SRHacPKc65zo+kBBlxtdg== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/primitive" "0.1.0" - "@radix-ui/react-compose-refs" "0.1.0" - "@radix-ui/react-context" "0.1.1" - "@radix-ui/react-id" "0.1.5" - "@radix-ui/react-menu" "0.1.6" - "@radix-ui/react-primitive" "0.1.4" - "@radix-ui/react-use-controllable-state" "0.1.0" - - "@radix-ui/react-focus-guards@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-guards/-/react-focus-guards-0.1.0.tgz#ba3b6f902cba7826569f8edc21ff8223dece7def" - integrity sha512-kRx/swAjEfBpQ3ns7J3H4uxpXuWCqN7MpALiSDOXiyo2vkWv0L9sxvbpZeTulINuE3CGMzicVMuNc/VWXjFKOg== - dependencies: - "@babel/runtime" "^7.13.10" - - "@radix-ui/react-focus-scope@0.1.4": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@radix-ui/react-focus-scope/-/react-focus-scope-0.1.4.tgz#c830724e212d42ffaaa81aee49533213d09b47df" - integrity sha512-fbA4ES3H4Wkxp+OeLhvN6SwL7mXNn/aBtUf7DRYxY9+Akrf7dRxl2ck4lgcpPsSg3zSDsEwLcY+h5cmj5yvlug== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/react-compose-refs" "0.1.0" - "@radix-ui/react-primitive" "0.1.4" - "@radix-ui/react-use-callback-ref" "0.1.0" - - "@radix-ui/react-id@0.1.5", "@radix-ui/react-id@^0.1.0": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@radix-ui/react-id/-/react-id-0.1.5.tgz#010d311bedd5a2884c1e9bb6aaaa4e6cc1d1d3b8" - integrity sha512-IPc4H/63bes0IZ1GJJozSEkSWcDyhNGtKFWUpJ+XtaLyQ1X3x7Mf6fWwWhDcpqlYEP+5WtAvfqcyEsyjP+ZhBQ== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/react-use-layout-effect" "0.1.0" - - "@radix-ui/react-label@0.1.5": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@radix-ui/react-label/-/react-label-0.1.5.tgz#12cd965bfc983e0148121d4c99fb8e27a917c45c" - integrity sha512-Au9+n4/DhvjR0IHhvZ1LPdx/OW+3CGDie30ZyCkbSHIuLp4/CV4oPPGBwJ1vY99Jog3zyQhsGww9MXj8O9Aj/A== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/react-compose-refs" "0.1.0" - "@radix-ui/react-context" "0.1.1" - "@radix-ui/react-id" "0.1.5" - "@radix-ui/react-primitive" "0.1.4" - - "@radix-ui/react-menu@0.1.6": - version "0.1.6" - resolved "https://registry.yarnpkg.com/@radix-ui/react-menu/-/react-menu-0.1.6.tgz#7f9521a10f6a9cd819b33b33d5ed9538d79b2e75" - integrity sha512-ho3+bhpr3oAFkOBJ8VkUb1BcGoiZBB3OmcWPqa6i5RTUKrzNX/d6rauochu2xDlWjiRtpVuiAcsTVOeIC4FbYQ== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/primitive" "0.1.0" - "@radix-ui/react-collection" "0.1.4" - "@radix-ui/react-compose-refs" "0.1.0" - "@radix-ui/react-context" "0.1.1" - "@radix-ui/react-dismissable-layer" "0.1.5" - "@radix-ui/react-focus-guards" "0.1.0" - "@radix-ui/react-focus-scope" "0.1.4" - "@radix-ui/react-id" "0.1.5" - "@radix-ui/react-popper" "0.1.4" - "@radix-ui/react-portal" "0.1.4" - "@radix-ui/react-presence" "0.1.2" - "@radix-ui/react-primitive" "0.1.4" - "@radix-ui/react-roving-focus" "0.1.5" - "@radix-ui/react-use-callback-ref" "0.1.0" - "@radix-ui/react-use-direction" "0.1.0" - aria-hidden "^1.1.1" - react-remove-scroll "^2.4.0" - - "@radix-ui/react-popper@0.1.4": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@radix-ui/react-popper/-/react-popper-0.1.4.tgz#dfc055dcd7dfae6a2eff7a70d333141d15a5d029" - integrity sha512-18gDYof97t8UQa7zwklG1Dr8jIdj3u+rVOQLzPi9f5i1YQak/pVGkaqw8aY+iDUknKKuZniTk/7jbAJUYlKyOw== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/popper" "0.1.0" - "@radix-ui/react-arrow" "0.1.4" - "@radix-ui/react-compose-refs" "0.1.0" - "@radix-ui/react-context" "0.1.1" - "@radix-ui/react-primitive" "0.1.4" - "@radix-ui/react-use-rect" "0.1.1" - "@radix-ui/react-use-size" "0.1.1" - "@radix-ui/rect" "0.1.1" - - "@radix-ui/react-portal@0.1.4": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@radix-ui/react-portal/-/react-portal-0.1.4.tgz#17bdce3d7f1a9a0b35cb5e935ab8bc562441a7d2" - integrity sha512-MO0wRy2eYRTZ/CyOri9NANCAtAtq89DEtg90gicaTlkCfdqCLEBsLb+/q66BZQTr3xX/Vq01nnVfc/TkCqoqvw== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/react-primitive" "0.1.4" - "@radix-ui/react-use-layout-effect" "0.1.0" - - "@radix-ui/react-presence@0.1.2": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@radix-ui/react-presence/-/react-presence-0.1.2.tgz#9f11cce3df73cf65bc348e8b76d891f0d54c1fe3" - integrity sha512-3BRlFZraooIUfRlyN+b/Xs5hq1lanOOo/+3h6Pwu2GMFjkGKKa4Rd51fcqGqnVlbr3jYg+WLuGyAV4KlgqwrQw== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/react-compose-refs" "0.1.0" - "@radix-ui/react-use-layout-effect" "0.1.0" - - "@radix-ui/react-primitive@0.1.4": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@radix-ui/react-primitive/-/react-primitive-0.1.4.tgz#6c233cf08b0cb87fecd107e9efecb3f21861edc1" - integrity sha512-6gSl2IidySupIMJFjYnDIkIWRyQdbu/AHK7rbICPani+LW4b0XdxBXc46og/iZvuwW8pjCS8I2SadIerv84xYA== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/react-slot" "0.1.2" - - "@radix-ui/react-radio-group@^0.1.1": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@radix-ui/react-radio-group/-/react-radio-group-0.1.5.tgz#ca8a676123a18b44804aff10af46129e2c2b37c3" - integrity sha512-ybgHsmh/V2crKvK6xZ56dpPul7b+vyxcq7obWqHbr5W6Ca11wdm0E7lS0i/Y6pgfIKYOWIARmZYDpRMEeRCPOw== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/primitive" "0.1.0" - "@radix-ui/react-compose-refs" "0.1.0" - "@radix-ui/react-context" "0.1.1" - "@radix-ui/react-label" "0.1.5" - "@radix-ui/react-presence" "0.1.2" - "@radix-ui/react-primitive" "0.1.4" - "@radix-ui/react-roving-focus" "0.1.5" - "@radix-ui/react-use-controllable-state" "0.1.0" - "@radix-ui/react-use-previous" "0.1.1" - "@radix-ui/react-use-size" "0.1.1" - - "@radix-ui/react-roving-focus@0.1.5": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@radix-ui/react-roving-focus/-/react-roving-focus-0.1.5.tgz#cc48d17a36b56f253d54905b0fd60ee134cb97ee" - integrity sha512-ClwKPS5JZE+PaHCoW7eu1onvE61pDv4kO8W4t5Ra3qMFQiTJLZMdpBQUhksN//DaVygoLirz4Samdr5Y1x1FSA== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/primitive" "0.1.0" - "@radix-ui/react-collection" "0.1.4" - "@radix-ui/react-compose-refs" "0.1.0" - "@radix-ui/react-context" "0.1.1" - "@radix-ui/react-id" "0.1.5" - "@radix-ui/react-primitive" "0.1.4" - "@radix-ui/react-use-callback-ref" "0.1.0" - "@radix-ui/react-use-controllable-state" "0.1.0" - - "@radix-ui/react-slider@^0.1.0", "@radix-ui/react-slider@^0.1.1": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@radix-ui/react-slider/-/react-slider-0.1.4.tgz#a7b7a480ee00158195794b08cd3f1583cf102518" - integrity sha512-0z3bCcdrAi+FIcoLXS6r0ESVWuuyMnUJoCsFm7tC7Rtv95x34YtaI8YfSyQmzuMVS4rTsNtCCTZ/s727uRaVkQ== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/number" "0.1.0" - "@radix-ui/primitive" "0.1.0" - "@radix-ui/react-collection" "0.1.4" - "@radix-ui/react-compose-refs" "0.1.0" - "@radix-ui/react-context" "0.1.1" - "@radix-ui/react-primitive" "0.1.4" - "@radix-ui/react-use-controllable-state" "0.1.0" - "@radix-ui/react-use-direction" "0.1.0" - "@radix-ui/react-use-layout-effect" "0.1.0" - "@radix-ui/react-use-previous" "0.1.1" - "@radix-ui/react-use-size" "0.1.1" - - "@radix-ui/react-slot@0.1.2": - version "0.1.2" - resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-0.1.2.tgz#e6f7ad9caa8ce81cc8d532c854c56f9b8b6307c8" - integrity sha512-ADkqfL+agEzEguU3yS26jfB50hRrwf7U4VTwAOZEmi/g+ITcBWe12yM46ueS/UCIMI9Py+gFUaAdxgxafFvY2Q== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/react-compose-refs" "0.1.0" - - "@radix-ui/react-switch@^0.1.1": - version "0.1.5" - resolved "https://registry.yarnpkg.com/@radix-ui/react-switch/-/react-switch-0.1.5.tgz#071ffa19a17a47fdc5c5e6f371bd5901c9fef2f4" - integrity sha512-ITtslJPK+Yi34iNf7K9LtsPaLD76oRIVzn0E8JpEO5HW8gpRBGb2NNI9mxKtEB30TVqIcdjdL10AmuIfOMwjtg== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/primitive" "0.1.0" - "@radix-ui/react-compose-refs" "0.1.0" - "@radix-ui/react-context" "0.1.1" - "@radix-ui/react-label" "0.1.5" - "@radix-ui/react-primitive" "0.1.4" - "@radix-ui/react-use-controllable-state" "0.1.0" - "@radix-ui/react-use-previous" "0.1.1" - "@radix-ui/react-use-size" "0.1.1" - - "@radix-ui/react-tooltip@^0.1.0": - version "0.1.7" - resolved "https://registry.yarnpkg.com/@radix-ui/react-tooltip/-/react-tooltip-0.1.7.tgz#6f8c00d6e489565d14abf209ce0fb8853c8c8ee3" - integrity sha512-eiBUsVOHenZ0JR16tl970bB0DafJBz6mFgSGfIGIVpflFj0LIsIDiLMsYyvYdx1KwwsIUDTEZtxcPm/sWjPzqA== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/primitive" "0.1.0" - "@radix-ui/react-compose-refs" "0.1.0" - "@radix-ui/react-context" "0.1.1" - "@radix-ui/react-id" "0.1.5" - "@radix-ui/react-popper" "0.1.4" - "@radix-ui/react-portal" "0.1.4" - "@radix-ui/react-presence" "0.1.2" - "@radix-ui/react-primitive" "0.1.4" - "@radix-ui/react-slot" "0.1.2" - "@radix-ui/react-use-controllable-state" "0.1.0" - "@radix-ui/react-use-escape-keydown" "0.1.0" - "@radix-ui/react-use-previous" "0.1.1" - "@radix-ui/react-use-rect" "0.1.1" - "@radix-ui/react-visually-hidden" "0.1.4" - - "@radix-ui/react-use-body-pointer-events@0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@radix-ui/react-use-body-pointer-events/-/react-use-body-pointer-events-0.1.1.tgz#63e7fd81ca7ffd30841deb584cd2b7f460df2597" - integrity sha512-R8leV2AWmJokTmERM8cMXFHWSiv/fzOLhG/JLmRBhLTAzOj37EQizssq4oW0Z29VcZy2tODMi9Pk/htxwb+xpA== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/react-use-layout-effect" "0.1.0" - - "@radix-ui/react-use-callback-ref@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-0.1.0.tgz#934b6e123330f5b3a6b116460e6662cbc663493f" - integrity sha512-Va041McOFFl+aV+sejvl0BS2aeHx86ND9X/rVFmEFQKTXCp6xgUK0NGUAGcgBlIjnJSbMYPGEk1xKSSlVcN2Aw== - dependencies: - "@babel/runtime" "^7.13.10" - - "@radix-ui/react-use-controllable-state@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-0.1.0.tgz#4fced164acfc69a4e34fb9d193afdab973a55de1" - integrity sha512-zv7CX/PgsRl46a52Tl45TwqwVJdmqnlQEQhaYMz/yBOD2sx2gCkCFSoF/z9mpnYWmS6DTLNTg5lIps3fV6EnXg== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/react-use-callback-ref" "0.1.0" - - "@radix-ui/react-use-direction@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@radix-ui/react-use-direction/-/react-use-direction-0.1.0.tgz#97ac1d52e497c974389e7988f809238ed72e7df7" - integrity sha512-NajpY/An9TCPSfOVkgWIdXJV+VuWl67PxB6kOKYmtNAFHvObzIoh8o0n9sAuwSAyFCZVq211FEf9gvVDRhOyiA== - dependencies: - "@babel/runtime" "^7.13.10" - - "@radix-ui/react-use-escape-keydown@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-0.1.0.tgz#dc80cb3753e9d1bd992adbad9a149fb6ea941874" - integrity sha512-tDLZbTGFmvXaazUXXv8kYbiCcbAE8yKgng9s95d8fCO+Eundv0Jngbn/hKPhDDs4jj9ChwRX5cDDnlaN+ugYYQ== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/react-use-callback-ref" "0.1.0" - - "@radix-ui/react-use-layout-effect@0.1.0": - version "0.1.0" - resolved "https://registry.yarnpkg.com/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-0.1.0.tgz#ebf71bd6d2825de8f1fbb984abf2293823f0f223" - integrity sha512-+wdeS51Y+E1q1Wmd+1xSSbesZkpVj4jsg0BojCbopWvgq5iBvixw5vgemscdh58ep98BwUbsFYnrywFhV9yrVg== - dependencies: - "@babel/runtime" "^7.13.10" - - "@radix-ui/react-use-previous@0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@radix-ui/react-use-previous/-/react-use-previous-0.1.1.tgz#0226017f72267200f6e832a7103760e96a6db5d0" - integrity sha512-O/ZgrDBr11dR8rhO59ED8s5zIXBRFi8MiS+CmFGfi7MJYdLbfqVOmQU90Ghf87aifEgWe6380LA69KBneaShAg== - dependencies: - "@babel/runtime" "^7.13.10" - - "@radix-ui/react-use-rect@0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@radix-ui/react-use-rect/-/react-use-rect-0.1.1.tgz#6c15384beee59c086e75b89a7e66f3d2e583a856" - integrity sha512-kHNNXAsP3/PeszEmM/nxBBS9Jbo93sO+xuMTcRfwzXsmxT5gDXQzAiKbZQ0EecCPtJIzqvr7dlaQi/aP1PKYqQ== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/rect" "0.1.1" - - "@radix-ui/react-use-size@0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@radix-ui/react-use-size/-/react-use-size-0.1.1.tgz#f6b75272a5d41c3089ca78c8a2e48e5f204ef90f" - integrity sha512-pTgWM5qKBu6C7kfKxrKPoBI2zZYZmp2cSXzpUiGM3qEBQlMLtYhaY2JXdXUCxz+XmD1YEjc8oRwvyfsD4AG4WA== - dependencies: - "@babel/runtime" "^7.13.10" - - "@radix-ui/react-visually-hidden@0.1.4": - version "0.1.4" - resolved "https://registry.yarnpkg.com/@radix-ui/react-visually-hidden/-/react-visually-hidden-0.1.4.tgz#6c75eae34fb5d084b503506fbfc05587ced05f03" - integrity sha512-K/q6AEEzqeeEq/T0NPChvBqnwlp8Tl4NnQdrI/y8IOY7BRR+Ug0PEsVk6g48HJ7cA1//COugdxXXVVK/m0X1mA== - dependencies: - "@babel/runtime" "^7.13.10" - "@radix-ui/react-primitive" "0.1.4" - - "@radix-ui/rect@0.1.1": - version "0.1.1" - resolved "https://registry.yarnpkg.com/@radix-ui/rect/-/rect-0.1.1.tgz#95b5ba51f469bea6b1b841e2d427e17e37d38419" - integrity sha512-g3hnE/UcOg7REdewduRPAK88EPuLZtaq7sA9ouu8S+YEtnyFRI16jgv6GZYe3VMoQLL1T171ebmEPtDjyxWLzw== - dependencies: - "@babel/runtime" "^7.13.10" - - "@reach/skip-nav@^0.11.2": - version "0.11.2" - resolved "https://registry.yarnpkg.com/@reach/skip-nav/-/skip-nav-0.11.2.tgz#015498b2125ad8ef1e48cb8ab33dca93925fcbc8" - integrity sha512-cXGQJodYcyUBLBv59oxB4ywwgFDHnoyt8+W+ZgdR1LR9eDxx6170shP0yPcwf/5KV2tXJtNF2McRUObkUW90+Q== - dependencies: - "@reach/utils" "0.11.2" - tslib "^2.0.0" - - "@reach/utils@0.11.2": - version "0.11.2" - resolved "https://registry.yarnpkg.com/@reach/utils/-/utils-0.11.2.tgz#be1f03650db56fd67a16d3fc70e5262cdb139cec" - integrity sha512-fBTolYj+rKTROXmf0zHO0rCWSvw7J0ALmYj5QxW4DmITMOH5uyRuWDWOfqohIGFbOtF/sum50WTB3tvx76d+Aw== - dependencies: - "@types/warning" "^3.0.0" - tslib "^2.0.0" - warning "^4.0.3" - - "@rollup/plugin-inject@^4.0.0": - version "4.0.4" - resolved "https://registry.yarnpkg.com/@rollup/plugin-inject/-/plugin-inject-4.0.4.tgz#fbeee66e9a700782c4f65c8b0edbafe58678fbc2" - integrity sha512-4pbcU4J/nS+zuHk+c+OL3WtmEQhqxlZ9uqfjQMQDOHOPld7PsCd8k5LWs8h5wjwJN7MgnAn768F2sDxEP4eNFQ== - dependencies: - "@rollup/pluginutils" "^3.1.0" - estree-walker "^2.0.1" - magic-string "^0.25.7" - - "@rollup/pluginutils@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-3.1.0.tgz#706b4524ee6dc8b103b3c995533e5ad680c02b9b" - integrity sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg== - dependencies: - "@types/estree" "0.0.39" - estree-walker "^1.0.1" - picomatch "^2.2.2" - - "@rushstack/eslint-patch@^1.0.8": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.1.1.tgz#782fa5da44c4f38ae9fd38e9184b54e451936118" - integrity sha512-BUyKJGdDWqvWC5GEhyOiUrGNi9iJUr4CU0O2WxJL6QJhHeeA/NVBalH+FeK0r/x/W0rPymXt5s78TDS7d6lCwg== - - "@sindresorhus/is@^0.14.0": - version "0.14.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" - integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== - - "@sindresorhus/is@^0.7.0": - version "0.7.0" - resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.7.0.tgz#9a06f4f137ee84d7df0460c1fdb1135ffa6c50fd" - integrity sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow== - - "@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@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40" - integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== - dependencies: - "@sinonjs/commons" "^1.7.0" - - "@sinonjs/fake-timers@^8.0.1": - version "8.1.0" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz#3fdc2b6cb58935b21bfb8d1625eb1300484316e7" - integrity sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg== - dependencies: - "@sinonjs/commons" "^1.7.0" - - "@socket.io/component-emitter@~3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.0.0.tgz#8863915676f837d9dad7b76f50cb500c1e9422e9" - integrity sha512-2pTGuibAXJswAPJjaKisthqS/NOK5ypG4LYT6tEAV0S/mxW0zOIvYvGK0V8w8+SHxAm6vRMSjqSalFXeBAqs+Q== - - "@sqltools/formatter@^1.2.2": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.3.tgz#1185726610acc37317ddab11c3c7f9066966bd20" - integrity sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg== - - "@stripe/react-stripe-js@^1.4.1": - version "1.7.0" - resolved "https://registry.yarnpkg.com/@stripe/react-stripe-js/-/react-stripe-js-1.7.0.tgz#83c993a09a903703205d556617f9729784a896c3" - integrity sha512-L20v8Jq0TDZFL2+y+uXD751t6q9SalSFkSYZpmZ2VWrGZGK7HAGfRQ804dzYSSr5fGenW6iz6y7U0YKfC/TK3g== - dependencies: - prop-types "^15.7.2" - - "@stripe/stripe-js@^1.16.0", "@stripe/stripe-js@^1.17.1": - version "1.24.0" - resolved "https://registry.yarnpkg.com/@stripe/stripe-js/-/stripe-js-1.24.0.tgz#d23977f364565981f8ab30b1b540e367f72abc5c" - integrity sha512-8CEILOpzoRhGwvgcf6y+BlPyEq1ZqxAv3gsX7LvokFYvbcyH72GRcHQMGXuZS3s7HqfYQuTSFrvZNL/qdkgA9Q== - - "@szmarczak/http-timer@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" - integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== - dependencies: - defer-to-connect "^1.0.1" - - "@tailwindcss/forms@^0.5.0": - version "0.5.0" - resolved "https://registry.yarnpkg.com/@tailwindcss/forms/-/forms-0.5.0.tgz#d4bea2560a10aac642573e72d3b4d62a88960449" - integrity sha512-KzWugryEBFkmoaYcBE18rs6gthWCFHHO7cAZm2/hv3hwD67AzwP7udSCa22E7R1+CEJL/FfhYsJWrc0b1aeSzw== - dependencies: - mini-svg-data-uri "^1.2.3" - - "@tailwindcss/typography@^0.5.2": - version "0.5.2" - resolved "https://registry.yarnpkg.com/@tailwindcss/typography/-/typography-0.5.2.tgz#24b069dab24d7a2467d01aca0dd432cb4b29f0ee" - integrity sha512-coq8DBABRPFcVhVIk6IbKyyHUt7YTEC/C992tatFB+yEx5WGBQrCgsSFjxHUr8AWXphWckadVJbominEduYBqw== - dependencies: - lodash.castarray "^4.4.0" - lodash.isplainobject "^4.0.6" - lodash.merge "^4.6.2" - - "@tootallnate/once@1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" - integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== - - "@trivago/prettier-plugin-sort-imports@3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-3.2.0.tgz#7a32b6b3085c436eda0143b2710c440a4a56db90" - integrity sha512-DnwLe+z8t/dZX5xBbYZV1+C5STkyK/P6SSq3Nk6NXlJZsgvDZX2eN4ND7bMFgGV/NL/YChWzcNf6ziGba1ktQQ== - dependencies: - "@babel/core" "7.13.10" - "@babel/generator" "7.13.9" - "@babel/parser" "7.14.6" - "@babel/traverse" "7.13.0" - "@babel/types" "7.13.0" - javascript-natural-sort "0.7.1" - lodash "4.17.21" - - "@trpc/client@^9.16.0": - version "9.20.1" - resolved "https://registry.yarnpkg.com/@trpc/client/-/client-9.20.1.tgz#a9a5e5e4ebceacb18f31950838942a02a37b9138" - integrity sha512-nsRToriDb6ny5UpgNGB/ux2NXGmSs4/cWh9QREXi8S3jbDogFjs++J+xRzq5Q5RHtchcyOile5wxtIy3iHVhtQ== - dependencies: - "@babel/runtime" "^7.9.0" - - "@trpc/next@^9.16.0": - version "9.20.1" - resolved "https://registry.yarnpkg.com/@trpc/next/-/next-9.20.1.tgz#16bee230db13f028444be03dfe6b4283d85d0ae7" - integrity sha512-gKNguAQ8Fbi2Yvdpm7t/qhP7ZZAqwmuJRpjpus+sM/j/fGf3p5vQSB0gUepAHv8DxDhqU9691ugGQRc9ltmTyg== - dependencies: - "@babel/runtime" "^7.9.0" - react-ssr-prepass "^1.5.0" - - "@trpc/react@^9.16.0": - version "9.20.1" - resolved "https://registry.yarnpkg.com/@trpc/react/-/react-9.20.1.tgz#64a97ec1892aba2ea9d38b28b6de1b6a90ba348b" - integrity sha512-hz03YP2nL6yTknEtNQkRK2fx2ZY1cWW708CxHAUuWlyUX9NPSiHVEN1qirhceOeLiBDSmXGD9+CunxBSMAci+A== - dependencies: - "@babel/runtime" "^7.9.0" - - "@trpc/server@^9.16.0": - version "9.20.1" - resolved "https://registry.yarnpkg.com/@trpc/server/-/server-9.20.1.tgz#e222283e64a2f2ded6aceba762a219976079f8ab" - integrity sha512-UsuDslmzWrhkv1JZ12/fK4Z/5lSaPj5UJg23j1EE1gkH5aSkQgY5CHzvNv+jkiAR6rR4K2HDOMpVF4Tz50YE9Q== - dependencies: - tslib "^2.1.0" - - "@ts-morph/common@~0.12.3": - version "0.12.3" - resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.12.3.tgz#a96e250217cd30e480ab22ec6a0ebbe65fd784ff" - integrity sha512-4tUmeLyXJnJWvTFOKtcNJ1yh0a3SsTLi2MUoyj8iUNznFRN1ZquaNe7Oukqrnki2FzZkm0J9adCNLDZxUzvj+w== - dependencies: - fast-glob "^3.2.7" - minimatch "^3.0.4" - mkdirp "^1.0.4" - path-browserify "^1.0.1" - - "@tsconfig/node10@^1.0.7": - version "1.0.8" - resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" - integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== - - "@tsconfig/node12@^1.0.7": - version "1.0.9" - resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" - integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== - - "@tsconfig/node14@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" - integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== - - "@tsconfig/node16@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" - integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== - - "@typeform/embed-react@^1.2.4": - version "1.13.0" - resolved "https://registry.yarnpkg.com/@typeform/embed-react/-/embed-react-1.13.0.tgz#9b50f0b880f212480b95d4ec2f1390998b2d3561" - integrity sha512-LSN7DQ1Eg9U7IvbfSfn152SspkkSaWlsWytEAGsqmau/HtH99T2ra/FoQ/zPajAObmWWpdH3p/jQiUL96vytPw== - dependencies: - "@typeform/embed" "1.34.1" - fast-deep-equal "^3.1.3" - - "@typeform/embed@1.34.1": - version "1.34.1" - resolved "https://registry.yarnpkg.com/@typeform/embed/-/embed-1.34.1.tgz#53f1f0b6fee7af24aa2446cf2e258c042df2e48f" - integrity sha512-FdteCw0TKHcNiSmz0t0CfFfK4xL7pc6jce/FWZJ9MLPTKcMzwaAvdaQ0Byll2kSG1RtNv+dfcBtth7xjhCKs3Q== - - "@types/accept-language-parser@1.5.2": - version "1.5.2" - resolved "https://registry.yarnpkg.com/@types/accept-language-parser/-/accept-language-parser-1.5.2.tgz#ea48ed07a3dc9d2ba6666d45c018ad1b5e59d665" - integrity sha512-G8NhvYQ4JVT0GhvgPSVDVskFwWhjFvjbTNou3rRkkDgB8dTBZtxZ1xcU9jqJSth5qTGCzbrKwRf+vKleKdrb7w== - - "@types/acorn@^4.0.0": - version "4.0.6" - resolved "https://registry.yarnpkg.com/@types/acorn/-/acorn-4.0.6.tgz#d61ca5480300ac41a7d973dd5b84d0a591154a22" - integrity sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ== - dependencies: - "@types/estree" "*" - - "@types/asn1js@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@types/asn1js/-/asn1js-2.0.2.tgz#bb1992291381b5f06e22a829f2ae009267cdf8c5" - integrity sha512-t4YHCgtD+ERvH0FyxvNlYwJ2ezhqw7t+Ygh4urQ7dJER8i185JPv6oIM3ey5YQmGN6Zp9EMbpohkjZi9t3UxwA== - - "@types/async@^3.2.10": - version "3.2.12" - resolved "https://registry.yarnpkg.com/@types/async/-/async-3.2.12.tgz#0ebbfaf3f249ffa0fdc50179b07705f69c90d70c" - integrity sha512-4i4w4tfNDo73BOjk0qHcB2YJ8A2SjITCrU4BTsgdJFTsVr6atPDXa0T9r0QZTrX3axtWwkqpZqF4B3gR0TqBGw== - - "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14", "@types/babel__core@^7.1.7": - version "7.1.18" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.18.tgz#1a29abcc411a9c05e2094c98f9a1b7da6cdf49f8" - integrity sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ== - 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.4", "@types/babel__traverse@^7.0.6": - version "7.14.2" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" - integrity sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA== - dependencies: - "@babel/types" "^7.3.0" - - "@types/bcryptjs@^2.4.2": - version "2.4.2" - resolved "https://registry.yarnpkg.com/@types/bcryptjs/-/bcryptjs-2.4.2.tgz#e3530eac9dd136bfdfb0e43df2c4c5ce1f77dfae" - integrity sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ== - - "@types/bn.js@^4.11.5": - version "4.11.6" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" - integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== - dependencies: - "@types/node" "*" - - "@types/bn.js@^5.1.0": - version "5.1.0" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.0.tgz#32c5d271503a12653c62cf4d2b45e6eab8cebc68" - integrity sha512-QSSVYj7pYFN49kW77o2s9xTCwZ8F2xLbjLLSEVh8D2F4JUhZtPAGOFLTD+ffqksBx/u4cE/KImFjyhqCjn/LIA== - dependencies: - "@types/node" "*" - - "@types/chrome@^0.0.136": - version "0.0.136" - resolved "https://registry.yarnpkg.com/@types/chrome/-/chrome-0.0.136.tgz#7c011b9f997b0156f25a140188a0c5689d3f368f" - integrity sha512-XDEiRhLkMd+SB7Iw3ZUIj/fov3wLd4HyTdLltVszkgl1dBfc3Rb7oPMVZ2Mz2TLqnF7Ow+StbR8E7r9lqpb4DA== - dependencies: - "@types/filesystem" "*" - "@types/har-format" "*" - - "@types/cross-spawn@6.0.2": - version "6.0.2" - resolved "https://registry.yarnpkg.com/@types/cross-spawn/-/cross-spawn-6.0.2.tgz#168309de311cd30a2b8ae720de6475c2fbf33ac7" - integrity sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw== - dependencies: - "@types/node" "*" - - "@types/debug@4.1.7", "@types/debug@^4.0.0": - version "4.1.7" - resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82" - integrity sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg== - dependencies: - "@types/ms" "*" - - "@types/engine.io@*": - version "3.1.7" - resolved "https://registry.yarnpkg.com/@types/engine.io/-/engine.io-3.1.7.tgz#86e541a5dc52fb7e97735383564a6ae4cfe2e8f5" - integrity sha512-qNjVXcrp+1sS8YpRUa714r0pgzOwESdW5UjHL7D/2ZFdBX0BXUXtg1LUrp+ylvqbvMcMWUy73YpRoxPN2VoKAQ== - dependencies: - "@types/node" "*" - - "@types/estree-jsx@^0.0.1": - version "0.0.1" - resolved "https://registry.yarnpkg.com/@types/estree-jsx/-/estree-jsx-0.0.1.tgz#c36d7a1afeb47a95a8ee0b7bc8bc705db38f919d" - integrity sha512-gcLAYiMfQklDCPjQegGn0TBAn9it05ISEsEhlKQUddIk7o2XDokOcTN7HBO8tznM0D9dGezvHEfRZBfZf6me0A== - dependencies: - "@types/estree" "*" - - "@types/estree@*": - version "0.0.51" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.51.tgz#cfd70924a25a3fd32b218e5e420e6897e1ac4f40" - integrity sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ== - - "@types/estree@0.0.39": - version "0.0.39" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" - integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== - - "@types/estree@^0.0.46": - version "0.0.46" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.46.tgz#0fb6bfbbeabd7a30880504993369c4bf1deab1fe" - integrity sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg== - - "@types/estree@^0.0.50": - version "0.0.50" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.50.tgz#1e0caa9364d3fccd2931c3ed96fdbeaa5d4cca83" - integrity sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw== - - "@types/filesystem@*": - version "0.0.32" - resolved "https://registry.yarnpkg.com/@types/filesystem/-/filesystem-0.0.32.tgz#307df7cc084a2293c3c1a31151b178063e0a8edf" - integrity sha512-Yuf4jR5YYMR2DVgwuCiP11s0xuVRyPKmz8vo6HBY3CGdeMj8af93CFZX+T82+VD1+UqHOxTq31lO7MI7lepBtQ== - dependencies: - "@types/filewriter" "*" - - "@types/filewriter@*": - version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/filewriter/-/filewriter-0.0.29.tgz#a48795ecadf957f6c0d10e0c34af86c098fa5bee" - integrity sha512-BsPXH/irW0ht0Ji6iw/jJaK8Lj3FJemon2gvEqHKpCdDCeemHa+rI3WBGq5z7cDMZgoLjY40oninGxqk+8NzNQ== - - "@types/glidejs__glide@^3.4.1": - version "3.4.1" - resolved "https://registry.yarnpkg.com/@types/glidejs__glide/-/glidejs__glide-3.4.1.tgz#220bbce087500eda3700e476c728e17d096eb6f0" - integrity sha512-ib2VRchnLSXGOdiZFfCt6QEIYviw5g+Yey8Q2+kMzUxGXsnR9ZwZi1qPXI1ttrvR/AtUYZmSSHDVVSoIyt6LPw== - - "@types/graceful-fs@^4.1.2": - 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/har-format@*": - version "1.2.8" - resolved "https://registry.yarnpkg.com/@types/har-format/-/har-format-1.2.8.tgz#e6908b76d4c88be3db642846bb8b455f0bfb1c4e" - integrity sha512-OP6L9VuZNdskgNN3zFQQ54ceYD8OLq5IbqO4VK91ORLfOm7WdT/CiT/pHEBSQEqCInJ2y3O6iCm/zGtPElpgJQ== - - "@types/hast@^2.0.0": - version "2.3.4" - resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.4.tgz#8aa5ef92c117d20d974a82bdfb6a648b08c0bafc" - integrity sha512-wLEm0QvaoawEDoTRwzTXp4b4jpwiJDvR5KMnFnVodm3scufTlBOWRD6N1OBf9TZMhjlNsSfcO5V+7AF4+Vy+9g== - dependencies: - "@types/unist" "*" - - "@types/hoist-non-react-statics@^3.3.1": - version "3.3.1" - resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz#1124aafe5118cb591977aeb1ceaaed1070eb039f" - integrity sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA== - dependencies: - "@types/react" "*" - hoist-non-react-statics "^3.3.0" - - "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz#8467d4b3c087805d63580480890791277ce35c44" - integrity sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g== - - "@types/istanbul-lib-report@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" - integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== - dependencies: - "@types/istanbul-lib-coverage" "*" - - "@types/istanbul-reports@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" - integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== - dependencies: - "@types/istanbul-lib-report" "*" - - "@types/jest@^27.0.3": - version "27.4.1" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.4.1.tgz#185cbe2926eaaf9662d340cc02e548ce9e11ab6d" - integrity sha512-23iPJADSmicDVrWk+HT58LMJtzLAnB2AgIzplQuq/bSrGaxCrlvRFjGbXmamnnk/mAmCdLStiGqggu28ocUyiw== - dependencies: - jest-matcher-utils "^27.0.0" - pretty-format "^27.0.0" - - "@types/json-schema@^7.0.9": - version "7.0.10" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.10.tgz#9b05b7896166cd00e9cbd59864853abf65d9ac23" - integrity sha512-BLO9bBq59vW3fxCpD4o0N4U+DXsvwvIcl+jofw0frQo/GrBFC+/jRZj1E7kgp6dvTyNmA4y6JCV5Id/r3mNP5A== - - "@types/json5@^0.0.29": - version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" - integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= - - "@types/lodash@^4.14.175", "@types/lodash@^4.14.177": - version "4.14.179" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.179.tgz#490ec3288088c91295780237d2497a3aa9dfb5c5" - integrity sha512-uwc1x90yCKqGcIOAT6DwOSuxnrAbpkdPsUOZtwrXb4D/6wZs+6qG7QnIawDuZWg0sWpxl+ltIKCaLoMlna678w== - - "@types/mdast@^3.0.0": - version "3.0.10" - resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.10.tgz#4724244a82a4598884cbbe9bcfd73dff927ee8af" - integrity sha512-W864tg/Osz1+9f4lrGTZpCSO5/z4608eUp19tbozkq2HJK6i3z1kT0H9tlADXuYIb1YYOBByU4Jsqkk75q48qA== - dependencies: - "@types/unist" "*" - - "@types/mdurl@^1.0.0": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@types/mdurl/-/mdurl-1.0.2.tgz#e2ce9d83a613bacf284c7be7d491945e39e1f8e9" - integrity sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA== - - "@types/mdx@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/mdx/-/mdx-2.0.1.tgz#e4c05d355d092d7b58db1abfe460e53f41102ac8" - integrity sha512-JPEv4iAl0I+o7g8yVWDwk30es8mfVrjkvh5UeVR2sYPpZCK44vrAPsbJpIS+rJAUxLgaSAMKTEH5Vn5qd9XsrQ== - - "@types/micro@7.3.6": - version "7.3.6" - resolved "https://registry.yarnpkg.com/@types/micro/-/micro-7.3.6.tgz#7d68eb5a780ac4761e3b80687b4ee7328ebc3f2e" - integrity sha512-rZHvZ3+Ev3cGJJSy/wtSiXZmafU8guI07PHXf4ku9sQLfDuFALHMCiV+LuH4VOaeMMMnRs8nqxU392gxfn661g== - dependencies: - "@types/node" "*" - "@types/socket.io" "2.1.13" - - "@types/micro@^7.3.6": - version "7.3.7" - resolved "https://registry.yarnpkg.com/@types/micro/-/micro-7.3.7.tgz#84bef63ef8cc113a70b9a64345ebea2d99946647" - integrity sha512-MFsX7eCj0Tg3TtphOQvANNvNtFpya+s/rYOCdV6o+DFjOQPFi2EVRbBALjbbgZTXUaJP1Q281MJiJOD40d0UxQ== - dependencies: - "@types/node" "*" - - "@types/module-alias@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/module-alias/-/module-alias-2.0.1.tgz#e5893236ce922152d57c5f3f978f764f4deeb45f" - integrity sha512-DN/CCT1HQG6HquBNJdLkvV+4v5l/oEuwOHUPLxI+Eub0NED+lk0YUfba04WGH90EINiUrNgClkNnwGmbICeWMQ== - - "@types/ms@*": - version "0.7.31" - resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" - integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== - - "@types/node@*", "@types/node@>=8.1.0": - version "17.0.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.21.tgz#864b987c0c68d07b4345845c3e63b75edd143644" - integrity sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ== - - "@types/node@^12.12.6": - version "12.20.47" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.47.tgz#ca9237d51f2a2557419688511dab1c8daf475188" - integrity sha512-BzcaRsnFuznzOItW1WpQrDHM7plAa7GIDMZ6b5pnMbkqEtM/6WCOhvZar39oeMQP79gwvFUWjjptE7/KGcNqFg== - - "@types/node@^16.11.24": - version "16.11.26" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.26.tgz#63d204d136c9916fb4dcd1b50f9740fe86884e47" - integrity sha512-GZ7bu5A6+4DtG7q9GsoHXy3ALcgeIHP4NnL0Vv2wu0uUB/yQex26v0tf6/na1mm0+bS9Uw+0DFex7aaKr2qawQ== - - "@types/nodemailer@^6.4.4": - version "6.4.4" - resolved "https://registry.yarnpkg.com/@types/nodemailer/-/nodemailer-6.4.4.tgz#c265f7e7a51df587597b3a49a023acaf0c741f4b" - integrity sha512-Ksw4t7iliXeYGvIQcSIgWQ5BLuC/mljIEbjf615svhZL10PE9t+ei8O9gDaD3FPCasUJn9KTLwz2JFJyiiyuqw== - dependencies: - "@types/node" "*" - - "@types/normalize-package-data@^2.4.0": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" - integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== - - "@types/parse-json@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" - integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== - - "@types/pbkdf2@^3.0.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@types/pbkdf2/-/pbkdf2-3.1.0.tgz#039a0e9b67da0cdc4ee5dab865caa6b267bb66b1" - integrity sha512-Cf63Rv7jCQ0LaL8tNXmEyqTHuIJxRdlS5vMh1mj5voN4+QFhVZnlZruezqpWYDiJ8UTzhP0VmeLXCmBk66YrMQ== - dependencies: - "@types/node" "*" - - "@types/prettier@^2.0.0", "@types/prettier@^2.1.5": - version "2.4.4" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.4.4.tgz#5d9b63132df54d8909fce1c3f8ca260fdd693e17" - integrity sha512-ReVR2rLTV1kvtlWFyuot+d1pkpG2Fw/XKE3PDAdj57rbM97ttSp9JZ2UsP+2EHTylra9cUf6JA7tGwW1INzUrA== - - "@types/prop-types@*": - version "15.7.4" - resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.4.tgz#fcf7205c25dff795ee79af1e30da2c9790808f11" - integrity sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ== - - "@types/qrcode@^1.4.1": - version "1.4.2" - resolved "https://registry.yarnpkg.com/@types/qrcode/-/qrcode-1.4.2.tgz#7d7142d6fa9921f195db342ed08b539181546c74" - integrity sha512-7uNT9L4WQTNJejHTSTdaJhfBSCN73xtXaHFyBJ8TSwiLhe4PRuTue7Iph0s2nG9R/ifUaSnGhLUOZavlBEqDWQ== - dependencies: - "@types/node" "*" - - "@types/react-calendar@^3.0.0": - version "3.5.0" - resolved "https://registry.yarnpkg.com/@types/react-calendar/-/react-calendar-3.5.0.tgz#8195a33e20395e1f5171eea9c80156f3a5115b43" - integrity sha512-qVSA5M0+SwLRINpE81TMUTh0NwJVed8T+lplJ7v0XAe4EHlMyNeNlkN9suKBxlwIEZ/62QP/m0QjGNCwdOy8PQ== - dependencies: - "@types/react" "*" - - "@types/react-dom@^17.0.11": - version "17.0.13" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.13.tgz#a3323b974ee4280070982b3112351bb1952a7809" - integrity sha512-wEP+B8hzvy6ORDv1QBhcQia4j6ea4SFIBttHYpXKPFZRviBvknq0FRh3VrIxeXUmsPkwuXVZrVGG7KUVONmXCQ== - dependencies: - "@types/react" "*" - - "@types/react-phone-number-input@^3.0.13": - version "3.0.13" - resolved "https://registry.yarnpkg.com/@types/react-phone-number-input/-/react-phone-number-input-3.0.13.tgz#4eb7dcd278dcf9eb2a8d2ce2cb304657cbf1b4e5" - integrity sha512-27k7AvLbzCjpuRORFhehFdRHVan1q6RhSTV7dFiXwZ2ojnS/JMx77wd9OyAU464oN0GIlkfhc0njGzL97/xNcw== - dependencies: - "@types/react" "*" - - "@types/react-transition-group@^4.4.0": - version "4.4.4" - resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.4.tgz#acd4cceaa2be6b757db61ed7b432e103242d163e" - integrity sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug== - dependencies: - "@types/react" "*" - - "@types/react-virtualized-auto-sizer@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.1.tgz#b3187dae1dfc4c15880c9cfc5b45f2719ea6ebd4" - integrity sha512-GH8sAnBEM5GV9LTeiz56r4ZhMOUSrP43tAQNSRVxNexDjcNKLCEtnxusAItg1owFUFE6k0NslV26gqVClVvong== - dependencies: - "@types/react" "*" - - "@types/react-window@^1.8.5": - version "1.8.5" - resolved "https://registry.yarnpkg.com/@types/react-window/-/react-window-1.8.5.tgz#285fcc5cea703eef78d90f499e1457e9b5c02fc1" - integrity sha512-V9q3CvhC9Jk9bWBOysPGaWy/Z0lxYcTXLtLipkt2cnRj1JOSFNF7wqGpkScSXMgBwC+fnVRg/7shwgddBG5ICw== - dependencies: - "@types/react" "*" - - "@types/react@*", "@types/react@16 || 17", "@types/react@^17.0.37": - version "17.0.40" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.40.tgz#dc010cee6254d5239a138083f3799a16638e6bad" - integrity sha512-UrXhD/JyLH+W70nNSufXqMZNuUD2cXHu6UjCllC6pmOQgBX4SGXOH8fjRka0O0Ee0HrFxapDD8Bwn81Kmiz6jQ== - dependencies: - "@types/prop-types" "*" - "@types/scheduler" "*" - csstype "^3.0.2" - - "@types/react@17.0.20": - version "17.0.20" - resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.20.tgz#a4284b184d47975c71658cd69e759b6bd37c3b8c" - integrity sha512-wWZrPlihslrPpcKyCSlmIlruakxr57/buQN1RjlIeaaTWDLtJkTtRW429MoQJergvVKc4IWBpRhWw7YNh/7GVA== - dependencies: - "@types/prop-types" "*" - "@types/scheduler" "*" - csstype "^3.0.2" - - "@types/scheduler@*": - version "0.16.2" - resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39" - integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew== - - "@types/secp256k1@^4.0.1": - version "4.0.3" - resolved "https://registry.yarnpkg.com/@types/secp256k1/-/secp256k1-4.0.3.tgz#1b8e55d8e00f08ee7220b4d59a6abe89c37a901c" - integrity sha512-Da66lEIFeIz9ltsdMZcpQvmrmmoqrfju8pm1BH8WbYjZSwUgCwXLb9C+9XYogwBITnbsSaMdVPb2ekf7TV+03w== - dependencies: - "@types/node" "*" - - "@types/socket.io-parser@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/socket.io-parser/-/socket.io-parser-3.0.0.tgz#9726d3ab9235757a0a30dd5ccf8975dce54e5e2c" - integrity sha512-Ry/rbTE6HQNL9eu3LpL1Ocup5VexXu1bSSGlSho/IR5LuRc8YvxwSNJ3JxqTltVJEATLbZkMQETSbxfKNgp4Ew== - dependencies: - socket.io-parser "*" - - "@types/socket.io@2.1.13": - version "2.1.13" - resolved "https://registry.yarnpkg.com/@types/socket.io/-/socket.io-2.1.13.tgz#b6d694234e99956c96ff99e197eda824b6f9dc48" - integrity sha512-JRgH3nCgsWel4OPANkhH8TelpXvacAJ9VeryjuqCDiaVDMpLysd6sbt0dr6Z15pqH3p2YpOT3T1C5vQ+O/7uyg== - dependencies: - "@types/engine.io" "*" - "@types/node" "*" - "@types/socket.io-parser" "*" - - "@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/stripe@^8.0.417": - version "8.0.417" - resolved "https://registry.yarnpkg.com/@types/stripe/-/stripe-8.0.417.tgz#b651677a9fc33be8ce8fd5bceadd7ca077214244" - integrity sha512-PTuqskh9YKNENnOHGVJBm4sM0zE8B1jZw1JIskuGAPkMB+OH236QeN8scclhYGPA4nG6zTtPXgwpXdp+HPDTVw== - dependencies: - stripe "*" - - "@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2": - version "2.0.6" - resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" - integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== - - "@types/uuid@8.3.1": - version "8.3.1" - resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.1.tgz#1a32969cf8f0364b3d8c8af9cc3555b7805df14f" - integrity sha512-Y2mHTRAbqfFkpjldbkHGY8JIzRN6XqYRliG8/24FcHm2D2PwW24fl5xMRTVGdrb7iMrwCaIEbLWerGIkXuFWVg== - - "@types/warning@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/warning/-/warning-3.0.0.tgz#0d2501268ad8f9962b740d387c4654f5f8e23e52" - integrity sha1-DSUBJorY+ZYrdA04fEZU9fjiPlI= - - "@types/web@^0.0.55": - version "0.0.55" - resolved "https://registry.yarnpkg.com/@types/web/-/web-0.0.55.tgz#0677cd86c6a4dd8c3592bd5f36435aa7e1b99028" - integrity sha512-YMH9aZrSJIMRMioCUwrgauI3iS/w2wRFN45Xxm0FE9Tt3hqaqkvOzjDFGsNjyKZzz7GJC0ilb+0tv59ytSUbrQ== - - "@types/webidl-conversions@*": - version "6.1.1" - resolved "https://registry.yarnpkg.com/@types/webidl-conversions/-/webidl-conversions-6.1.1.tgz#e33bc8ea812a01f63f90481c666334844b12a09e" - integrity sha512-XAahCdThVuCFDQLT7R7Pk/vqeObFNL3YqRyFZg+AqAP/W1/w3xHaIxuW7WszQqTbIBOPRcItYJIou3i/mppu3Q== - - "@types/whatwg-url@^8.2.1": - version "8.2.1" - resolved "https://registry.yarnpkg.com/@types/whatwg-url/-/whatwg-url-8.2.1.tgz#f1aac222dab7c59e011663a0cb0a3117b2ef05d4" - integrity sha512-2YubE1sjj5ifxievI5Ge1sckb9k/Er66HyR2c+3+I6VDUUg1TLPdYYTEbQ+DjRkS4nTxMJhgWfSfMRD2sl2EYQ== - dependencies: - "@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@^15.0.0": - version "15.0.14" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06" - integrity sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ== - dependencies: - "@types/yargs-parser" "*" - - "@types/yargs@^16.0.0": - version "16.0.4" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" - integrity sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw== - dependencies: - "@types/yargs-parser" "*" - - "@types/yauzl@^2.9.1": - version "2.9.2" - resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.9.2.tgz#c48e5d56aff1444409e39fa164b0b4d4552a7b7a" - integrity sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA== - dependencies: - "@types/node" "*" - - "@types/zen-observable@0.8.3": - version "0.8.3" - resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.3.tgz#781d360c282436494b32fe7d9f7f8e64b3118aa3" - integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw== - - "@typescript-eslint/eslint-plugin@^5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.16.0.tgz#78f246dd8d1b528fc5bfca99a8a64d4023a3d86d" - integrity sha512-SJoba1edXvQRMmNI505Uo4XmGbxCK9ARQpkvOd00anxzri9RNQk0DDCxD+LIl+jYhkzOJiOMMKYEHnHEODjdCw== - dependencies: - "@typescript-eslint/scope-manager" "5.16.0" - "@typescript-eslint/type-utils" "5.16.0" - "@typescript-eslint/utils" "5.16.0" - debug "^4.3.2" - functional-red-black-tree "^1.0.1" - ignore "^5.1.8" - regexpp "^3.2.0" - semver "^7.3.5" - tsutils "^3.21.0" - - "@typescript-eslint/parser@^5.0.0": - version "5.14.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.14.0.tgz#7c79f898aa3cff0ceee6f1d34eeed0f034fb9ef3" - integrity sha512-aHJN8/FuIy1Zvqk4U/gcO/fxeMKyoSv/rS46UXMXOJKVsLQ+iYPuXNbpbH7cBLcpSbmyyFbwrniLx5+kutu1pw== - dependencies: - "@typescript-eslint/scope-manager" "5.14.0" - "@typescript-eslint/types" "5.14.0" - "@typescript-eslint/typescript-estree" "5.14.0" - debug "^4.3.2" - - "@typescript-eslint/scope-manager@5.14.0": - version "5.14.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.14.0.tgz#ea518962b42db8ed0a55152ea959c218cb53ca7b" - integrity sha512-LazdcMlGnv+xUc5R4qIlqH0OWARyl2kaP8pVCS39qSL3Pd1F7mI10DbdXeARcE62sVQE4fHNvEqMWsypWO+yEw== - dependencies: - "@typescript-eslint/types" "5.14.0" - "@typescript-eslint/visitor-keys" "5.14.0" - - "@typescript-eslint/scope-manager@5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.16.0.tgz#7e7909d64bd0c4d8aef629cdc764b9d3e1d3a69a" - integrity sha512-P+Yab2Hovg8NekLIR/mOElCDPyGgFZKhGoZA901Yax6WR6HVeGLbsqJkZ+Cvk5nts/dAlFKm8PfL43UZnWdpIQ== - dependencies: - "@typescript-eslint/types" "5.16.0" - "@typescript-eslint/visitor-keys" "5.16.0" - - "@typescript-eslint/type-utils@5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.16.0.tgz#b482bdde1d7d7c0c7080f7f2f67ea9580b9e0692" - integrity sha512-SKygICv54CCRl1Vq5ewwQUJV/8padIWvPgCxlWPGO/OgQLCijY9G7lDu6H+mqfQtbzDNlVjzVWQmeqbLMBLEwQ== - dependencies: - "@typescript-eslint/utils" "5.16.0" - debug "^4.3.2" - tsutils "^3.21.0" - - "@typescript-eslint/types@5.14.0": - version "5.14.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.14.0.tgz#96317cf116cea4befabc0defef371a1013f8ab11" - integrity sha512-BR6Y9eE9360LNnW3eEUqAg6HxS9Q35kSIs4rp4vNHRdfg0s+/PgHgskvu5DFTM7G5VKAVjuyaN476LCPrdA7Mw== - - "@typescript-eslint/types@5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.16.0.tgz#5827b011982950ed350f075eaecb7f47d3c643ee" - integrity sha512-oUorOwLj/3/3p/HFwrp6m/J2VfbLC8gjW5X3awpQJ/bSG+YRGFS4dpsvtQ8T2VNveV+LflQHjlLvB6v0R87z4g== - - "@typescript-eslint/typescript-estree@5.14.0": - version "5.14.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.14.0.tgz#78b7f7385d5b6f2748aacea5c9b7f6ae62058314" - integrity sha512-QGnxvROrCVtLQ1724GLTHBTR0lZVu13izOp9njRvMkCBgWX26PKvmMP8k82nmXBRD3DQcFFq2oj3cKDwr0FaUA== - dependencies: - "@typescript-eslint/types" "5.14.0" - "@typescript-eslint/visitor-keys" "5.14.0" - debug "^4.3.2" - globby "^11.0.4" - is-glob "^4.0.3" - semver "^7.3.5" - tsutils "^3.21.0" - - "@typescript-eslint/typescript-estree@5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.16.0.tgz#32259459ec62f5feddca66adc695342f30101f61" - integrity sha512-SE4VfbLWUZl9MR+ngLSARptUv2E8brY0luCdgmUevU6arZRY/KxYoLI/3V/yxaURR8tLRN7bmZtJdgmzLHI6pQ== - dependencies: - "@typescript-eslint/types" "5.16.0" - "@typescript-eslint/visitor-keys" "5.16.0" - debug "^4.3.2" - globby "^11.0.4" - is-glob "^4.0.3" - semver "^7.3.5" - tsutils "^3.21.0" - - "@typescript-eslint/utils@5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.16.0.tgz#42218b459d6d66418a4eb199a382bdc261650679" - integrity sha512-iYej2ER6AwmejLWMWzJIHy3nPJeGDuCqf8Jnb+jAQVoPpmWzwQOfa9hWVB8GIQE5gsCv/rfN4T+AYb/V06WseQ== - dependencies: - "@types/json-schema" "^7.0.9" - "@typescript-eslint/scope-manager" "5.16.0" - "@typescript-eslint/types" "5.16.0" - "@typescript-eslint/typescript-estree" "5.16.0" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - - "@typescript-eslint/visitor-keys@5.14.0": - version "5.14.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.14.0.tgz#1927005b3434ccd0d3ae1b2ecf60e65943c36986" - integrity sha512-yL0XxfzR94UEkjBqyymMLgCBdojzEuy/eim7N9/RIcTNxpJudAcqsU8eRyfzBbcEzGoPWfdM3AGak3cN08WOIw== - dependencies: - "@typescript-eslint/types" "5.14.0" - eslint-visitor-keys "^3.0.0" - - "@typescript-eslint/visitor-keys@5.16.0": - version "5.16.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.16.0.tgz#f27dc3b943e6317264c7492e390c6844cd4efbbb" - integrity sha512-jqxO8msp5vZDhikTwq9ubyMHqZ67UIvawohr4qF3KhlpL7gzSjOd+8471H3nh5LyABkaI85laEKKU8SnGUK5/g== - dependencies: - "@typescript-eslint/types" "5.16.0" - eslint-visitor-keys "^3.0.0" - - "@vercel/edge-functions-ui@^0.2.1": - version "0.2.1" - resolved "https://registry.yarnpkg.com/@vercel/edge-functions-ui/-/edge-functions-ui-0.2.1.tgz#8af0a5d8d4d544364fa79c4d075564e3a5bd972e" - integrity sha512-dBomNbO5IuWGEP0OB8deIpjNm+ZeG7Ex5WXIUsVfJihE6CtBXoZi0zWDOlyWxRW1rogqFLnSjgItzDA7G4ADkg== - dependencies: - clsx "^1.1.1" - next-transpile-modules "^8.0.0" - - "@wojtekmaj/date-utils@^1.0.2", "@wojtekmaj/date-utils@^1.0.3": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@wojtekmaj/date-utils/-/date-utils-1.0.3.tgz#2dcfd92881425c5923e429c2aec86fb3609032a1" - integrity sha512-1VPkkTBk07gMR1fjpBtse4G+oJqpmE+0gUFB0dg3VIL7qJmUVaBoD/vlzMm/jNeOPfvlmerl1lpnsZyBUFIRuw== - - "@wojtekmaj/react-daterange-picker@^3.3.1": - version "3.4.0" - resolved "https://registry.yarnpkg.com/@wojtekmaj/react-daterange-picker/-/react-daterange-picker-3.4.0.tgz#bd85e980b16200f6066895961c518a327a830f3a" - integrity sha512-2ONcCSx10YP3+EOfg+1YrOO+Taa0iBdvfOJ5n8ZDW6fwS+9eyzYwWfRfPk78F2xZ7T7CR41ApBQlqM/2DT2Brw== - dependencies: - make-event-props "^1.1.0" - merge-class-names "^1.1.1" - prop-types "^15.6.0" - react-calendar "^3.3.1" - react-date-picker "^8.4.0" - react-fit "^1.4.0" - - "@xmldom/xmldom@0.7.5", "@xmldom/xmldom@^0.7.0": - version "0.7.5" - resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.7.5.tgz#09fa51e356d07d0be200642b0e4f91d8e6dd408d" - integrity sha512-V3BIhmY36fXZ1OtVcI9W+FxQqxVLsPKcNjWigIaa81dLC9IolJl5Mt4Cvhmr0flUnjSpTdrbMTSbXqYqV5dT6A== - - abab@^2.0.3, abab@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" - integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== - - abort-controller@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" - integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== - dependencies: - event-target-shim "^5.0.0" - - abstract-leveldown@~0.12.0, abstract-leveldown@~0.12.1: - version "0.12.4" - resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-0.12.4.tgz#29e18e632e60e4e221d5810247852a63d7b2e410" - integrity sha1-KeGOYy5g5OIh1YECR4UqY9ey5BA= - dependencies: - xtend "~3.0.0" - - accept-language-parser@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/accept-language-parser/-/accept-language-parser-1.5.0.tgz#8877c54040a8dcb59e0a07d9c1fde42298334791" - integrity sha1-iHfFQECo3LWeCgfZwf3kIpgzR5E= - - accepts@^1.3.7, accepts@~1.3.7, accepts@~1.3.8: - version "1.3.8" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== - dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" - - acorn-globals@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" - integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== - dependencies: - acorn "^7.1.1" - acorn-walk "^7.1.1" - - acorn-jsx@^5.0.0, acorn-jsx@^5.3.1: - version "5.3.2" - resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - - acorn-node@^1.6.1: - version "1.8.2" - resolved "https://registry.yarnpkg.com/acorn-node/-/acorn-node-1.8.2.tgz#114c95d64539e53dede23de8b9d96df7c7ae2af8" - integrity sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A== - dependencies: - acorn "^7.0.0" - acorn-walk "^7.0.0" - xtend "^4.0.2" - - acorn-walk@^7.0.0, acorn-walk@^7.1.1: - version "7.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" - integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== - - acorn-walk@^8.0.0, acorn-walk@^8.1.1: - version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" - integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== - - acorn@^7.0.0, acorn@^7.1.1: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - - acorn@^8.0.0, acorn@^8.0.4, acorn@^8.2.4, acorn@^8.4.1, acorn@^8.7.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" - integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== - - agent-base@6, agent-base@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== - dependencies: - debug "4" - - aggregate-error@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" - integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== - dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" - - ajv@^6.10.0, ajv@^6.12.3, ajv@^6.12.4: - version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - - 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== - dependencies: - type-fest "^0.21.3" - - ansi-regex@^5.0.0, ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - - ansi-regex@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" - integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== - - ansi-styles@^3.1.0, ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - - ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - - ansi-styles@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" - integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== - - ansi-styles@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.1.0.tgz#87313c102b8118abd57371afab34618bf7350ed3" - integrity sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ== - - any-base@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/any-base/-/any-base-1.1.0.tgz#ae101a62bc08a597b4c9ab5b7089d456630549fe" - integrity sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg== - - any-promise@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" - integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= - - anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - - anymatch@^3.0.3, anymatch@~3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - - app-root-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad" - integrity sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw== - - arch@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" - integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== - - archive-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/archive-type/-/archive-type-4.0.0.tgz#f92e72233056dfc6969472749c267bdb046b1d70" - integrity sha1-+S5yIzBW38aWlHJ0nCZ72wRrHXA= - dependencies: - file-type "^4.2.0" - - arg@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/arg/-/arg-1.0.0.tgz#444d885a4e25b121640b55155ef7cd03975d6050" - integrity sha512-Wk7TEzl1KqvTGs/uyhmHO/3XLd3t1UeU4IstvPXVzGPM522cTjqjNZ99esCkcL52sjqjo8e8CTBcWhkxvGzoAw== - - arg@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.0.tgz#583c518199419e0037abb74062c37f8519e575f0" - integrity sha512-ZWc51jO3qegGkVh8Hwpv636EkbesNV5ZNQPCtRa+0qytRYPEs9IYT9qITY9buezqUH5uqyzlWLcufrzU2rffdg== - - arg@^4.1.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" - integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== - - arg@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/arg/-/arg-5.0.1.tgz#eb0c9a8f77786cad2af8ff2b862899842d7b6adb" - integrity sha512-e0hDa9H2Z9AwFkk2qDlwhoMYE4eToKarchkQHovNdLTCYMHZHeRjI71crOh+dio4K6u1IcwubQqo79Ga4CyAQA== - - argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - - argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - - aria-hidden@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/aria-hidden/-/aria-hidden-1.1.3.tgz#bb48de18dc84787a3c6eee113709c473c64ec254" - integrity sha512-RhVWFtKH5BiGMycI72q2RAFMLQi8JP9bLuQXgR5a8Znp7P5KOIADSJeyfI8PCVxLEp067B2HbP5JIiI/PXIZeA== - dependencies: - tslib "^1.0.0" - - aria-query@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b" - integrity sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA== - dependencies: - "@babel/runtime" "^7.10.2" - "@babel/runtime-corejs3" "^7.10.2" - - arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= - - arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - - arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= - - array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= - - array-includes@^3.1.3, array-includes@^3.1.4: - version "3.1.4" - resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.4.tgz#f5b493162c760f3539631f005ba2bb46acb45ba9" - integrity sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - get-intrinsic "^1.1.1" - is-string "^1.0.7" - - array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - - array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= - - array.prototype.flat@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz#07e0975d84bbc7c48cd1879d609e682598d33e13" - integrity sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - - array.prototype.flatmap@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz#908dc82d8a406930fdf38598d51e7411d18d4446" - integrity sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - es-abstract "^1.19.0" - - arrify@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" - integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== - - asn1.js@^5.2.0: - version "5.4.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-5.4.1.tgz#11a980b84ebb91781ce35b0fdc2ee294e3783f07" - integrity sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA== - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - safer-buffer "^2.1.0" - - asn1@~0.2.3: - version "0.2.6" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" - integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== - dependencies: - safer-buffer "~2.1.0" - - asn1js@^2.1.1, asn1js@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/asn1js/-/asn1js-2.2.0.tgz#d890fcdda86b8a005693df14a986bfb2c2069c57" - integrity sha512-oagLNqpfNv7CvmyMoexMDNyVDSiq1rya0AEUgcLlNHdHgNl6U/hi8xY370n5y+ZIFEXOx0J4B1qF2NDjMRxklA== - dependencies: - pvutils latest - - assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - - assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= - - ast-types-flow@^0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" - integrity sha1-9wtzXGvKGlycItmCw+Oef+ujva0= - - astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== - - astring@^1.6.0: - version "1.8.1" - resolved "https://registry.yarnpkg.com/astring/-/astring-1.8.1.tgz#a91c4afd4af3523e11f31242a3d5d9af62bb6cc6" - integrity sha512-Aj3mbwVzj7Vve4I/v2JYOPFkCGM2YS7OqQTNSxmUR+LECRpokuPgAYghePgr6SALDo5bD5DlfbSaYjOzGJZOLQ== - - async-limiter@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" - integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== - - async@^3.2.1: - version "3.2.3" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.3.tgz#ac53dafd3f4720ee9e8a160628f18ea91df196c9" - integrity sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g== - - asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - - atob@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" - integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== - - autoprefixer@^10.3.4: - version "10.4.4" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.4.tgz#3e85a245b32da876a893d3ac2ea19f01e7ea5a1e" - integrity sha512-Tm8JxsB286VweiZ5F0anmbyGiNI3v3wGv3mz9W+cxEDYB/6jbnj6GM9H9mK3wIL8ftgl+C07Lcwb8PG5PCCPzA== - dependencies: - browserslist "^4.20.2" - caniuse-lite "^1.0.30001317" - fraction.js "^4.2.0" - normalize-range "^0.1.2" - picocolors "^1.0.0" - postcss-value-parser "^4.2.0" - - autoprefixer@^10.4.0: - version "10.4.3" - resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-10.4.3.tgz#d4b9358be607c30d1900c1412d0d668f98bb5a6a" - integrity sha512-3EIK6tHl2SyJWCoPsQzL3NEqKOdjCWbPzoOInjVAQYo/y/OCEFG9KwB5162dehG5GadiGfgxu7nrWCpExCfRFQ== - dependencies: - browserslist "^4.20.2" - caniuse-lite "^1.0.30001317" - fraction.js "^4.2.0" - normalize-range "^0.1.2" - picocolors "^1.0.0" - postcss-value-parser "^4.2.0" - - available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== - - aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - - aws4@^1.8.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" - integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== - - axe-core@^4.3.5: - version "4.4.1" - resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.4.1.tgz#7dbdc25989298f9ad006645cd396782443757413" - integrity sha512-gd1kmb21kwNuWr6BQz8fv6GNECPBnUasepcoLbekws23NVBLODdsClRZ+bQ8+9Uomf3Sm3+Vwn0oYG9NvwnJCw== - - axobject-query@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" - integrity sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA== - - babel-jest@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" - integrity sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA== - dependencies: - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/babel__core" "^7.1.7" - babel-plugin-istanbul "^6.0.0" - babel-preset-jest "^26.6.2" - chalk "^4.0.0" - graceful-fs "^4.2.4" - slash "^3.0.0" - - babel-jest@^27.3.1, babel-jest@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444" - integrity sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg== - dependencies: - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/babel__core" "^7.1.14" - babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^27.5.1" - 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.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" - integrity sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ== - dependencies: - object.assign "^4.1.0" - - babel-plugin-istanbul@^6.0.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@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz#8185bd030348d254c6d7dd974355e6a28b21e62d" - integrity sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw== - dependencies: - "@babel/template" "^7.3.3" - "@babel/types" "^7.3.3" - "@types/babel__core" "^7.0.0" - "@types/babel__traverse" "^7.0.6" - - babel-plugin-jest-hoist@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz#9be98ecf28c331eb9f5df9c72d6f89deb8181c2e" - integrity sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ== - dependencies: - "@babel/template" "^7.3.3" - "@babel/types" "^7.3.3" - "@types/babel__core" "^7.0.0" - "@types/babel__traverse" "^7.0.6" - - babel-plugin-macros@^2.6.1: - version "2.8.0" - resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz#0f958a7cc6556b1e65344465d99111a1e5e10138" - integrity sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg== - dependencies: - "@babel/runtime" "^7.7.2" - cosmiconfig "^6.0.0" - resolve "^1.12.0" - - 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.1" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz#440f1b70ccfaabc6b676d196239b138f8a2cfba5" - integrity sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w== - dependencies: - "@babel/compat-data" "^7.13.11" - "@babel/helper-define-polyfill-provider" "^0.3.1" - semver "^6.1.1" - - babel-plugin-polyfill-corejs3@^0.5.0: - version "0.5.2" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.2.tgz#aabe4b2fa04a6e038b688c5e55d44e78cd3a5f72" - integrity sha512-G3uJih0XWiID451fpeFaYGVuxHEjzKTHtc9uGFEjR6hHrvNzeS/PX+LLLcetJcytsB5m4j+K3o/EpXJNb/5IEQ== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.1" - core-js-compat "^3.21.0" - - babel-plugin-polyfill-regenerator@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz#2c0678ea47c75c8cc2fbb1852278d8fb68233990" - integrity sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A== - dependencies: - "@babel/helper-define-polyfill-provider" "^0.3.1" - - babel-preset-current-node-syntax@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" - integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== - dependencies: - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-bigint" "^7.8.3" - "@babel/plugin-syntax-class-properties" "^7.8.3" - "@babel/plugin-syntax-import-meta" "^7.8.3" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-top-level-await" "^7.8.3" - - babel-preset-jest@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz#747872b1171df032252426586881d62d31798fee" - integrity sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ== - dependencies: - babel-plugin-jest-hoist "^26.6.2" - babel-preset-current-node-syntax "^1.0.0" - - babel-preset-jest@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz#91f10f58034cb7989cb4f962b69fa6eef6a6bc81" - integrity sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag== - dependencies: - babel-plugin-jest-hoist "^27.5.1" - babel-preset-current-node-syntax "^1.0.0" - - bail@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.5.tgz#b6fa133404a392cbc1f8c4bf63f5953351e7a776" - integrity sha512-xFbRxM1tahm08yHBP16MMjVUAvDaBMD38zsM9EMAUN61omwLmKlOpB/Zku5QkjZ8TZ4vn53pj+t518cH0S03RQ== - - bail@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/bail/-/bail-2.0.2.tgz#d26f5cd8fe5d6f832a31517b9f7c356040ba6d5d" - integrity sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw== - - balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - - base-64@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/base-64/-/base-64-1.0.0.tgz#09d0f2084e32a3fd08c2475b973788eee6ae8f4a" - integrity sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg== - - base-x@^3.0.2, base-x@^3.0.8: - version "3.0.9" - resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" - integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== - dependencies: - safe-buffer "^5.0.1" - - base64-js@^1.3.0, base64-js@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - - base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - - bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" - - bcryptjs@^2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb" - integrity sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms= - - big-integer@^1.6.16: - version "1.6.51" - resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686" - integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg== - - big.js@^5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" - integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== - - bignumber.js@^9.0.0: - version "9.0.2" - resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-9.0.2.tgz#71c6c6bed38de64e24a65ebe16cfcf23ae693673" - integrity sha512-GAcQvbpsM0pUb0zw1EI0KhQEZ+lRwR5fYaAp3vPOYuP7aDvGy6cVN6XHLauvF8SOga2y0dcLcjt3iQDTSEliyw== - - binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== - - bl@^1.0.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.3.tgz#1e8dd80142eac80d7158c9dccc047fb620e035e7" - integrity sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww== - dependencies: - readable-stream "^2.3.5" - safe-buffer "^5.1.1" - - bl@~0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/bl/-/bl-0.8.2.tgz#c9b6bca08d1bc2ea00fc8afb4f1a5fd1e1c66e4e" - integrity sha1-yba8oI0bwuoA/Ir7Txpf0eHGbk4= - dependencies: - readable-stream "~1.0.26" - - blakejs@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/blakejs/-/blakejs-1.1.1.tgz#bf313053978b2cd4c444a48795710be05c785702" - integrity sha512-bLG6PHOCZJKNshTjGRBvET0vTciwQE6zFKOKKXPDJfwFBd4Ac0yBfPZqcGvGJap50l7ktvlpFqc2jGVaUgbJgg== - - bluebird@^3.5.0: - version "3.7.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" - integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== - - bmp-js@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/bmp-js/-/bmp-js-0.1.0.tgz#e05a63f796a6c1ff25f4771ec7adadc148c07233" - integrity sha1-4Fpj95amwf8l9Hcex62twUjAcjM= - - bn.js@4.11.6: - version "4.11.6" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" - integrity sha1-UzRK2xRhehP26N0s4okF0cC6MhU= - - bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.11.6, bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - - bn.js@^5.0.0, bn.js@^5.1.1, bn.js@^5.1.2, bn.js@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" - integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== - - body-parser@1.19.1: - version "1.19.1" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.1.tgz#1499abbaa9274af3ecc9f6f10396c995943e31d4" - integrity sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA== - dependencies: - bytes "3.1.1" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.2" - http-errors "1.8.1" - iconv-lite "0.4.24" - on-finished "~2.3.0" - qs "6.9.6" - raw-body "2.4.2" - type-is "~1.6.18" - - body-parser@1.19.2, body-parser@^1.16.0: - version "1.19.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.2.tgz#4714ccd9c157d44797b8b5607d72c0b89952f26e" - integrity sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw== - dependencies: - bytes "3.1.2" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.2" - http-errors "1.8.1" - iconv-lite "0.4.24" - on-finished "~2.3.0" - qs "6.9.7" - raw-body "2.4.3" - type-is "~1.6.18" - - bowser@^2.8.1: - version "2.11.0" - resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f" - integrity sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA== - - brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - - braces@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - - braces@^3.0.1, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - - broadcast-channel@^3.4.1: - version "3.7.0" - resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.7.0.tgz#2dfa5c7b4289547ac3f6705f9c00af8723889937" - integrity sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg== - dependencies: - "@babel/runtime" "^7.7.2" - detect-node "^2.1.0" - js-sha3 "0.8.0" - microseconds "0.2.0" - nano-time "1.0.0" - oblivious-set "1.0.0" - rimraf "3.0.2" - unload "2.2.0" - - brorand@^1.0.1, brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= - - browser-process-hrtime@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" - integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== - - browserify-aes@^1.0.0, browserify-aes@^1.0.4, browserify-aes@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" - integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - - browserify-cipher@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" - integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - - browserify-des@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" - integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - - browserify-fs@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browserify-fs/-/browserify-fs-1.0.0.tgz#f075aa8a729d4d1716d066620e386fcc1311a96f" - integrity sha1-8HWqinKdTRcW0GZiDjhvzBMRqW8= - dependencies: - level-filesystem "^1.0.1" - level-js "^2.1.3" - levelup "^0.18.2" - - browserify-rsa@^4.0.0, browserify-rsa@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.1.0.tgz#b2fd06b5b75ae297f7ce2dc651f918f5be158c8d" - integrity sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog== - dependencies: - bn.js "^5.0.0" - randombytes "^2.0.1" - - browserify-sign@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.2.1.tgz#eaf4add46dd54be3bb3b36c0cf15abbeba7956c3" - integrity sha512-/vrA5fguVAKKAVTNJjgSm1tRQDHUU6DbwO9IROu/0WAzC8PKhucDSh18J0RMvVeHAn5puMd+QHC2erPRNf8lmg== - dependencies: - bn.js "^5.1.1" - browserify-rsa "^4.0.1" - create-hash "^1.2.0" - create-hmac "^1.1.7" - elliptic "^6.5.3" - inherits "^2.0.4" - parse-asn1 "^5.1.5" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - - browserslist@^4.17.5: - version "4.20.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.0.tgz#35951e3541078c125d36df76056e94738a52ebe9" - integrity sha512-bnpOoa+DownbciXj0jVGENf8VYQnE2LNWomhYuCsMmmx9Jd9lwq0WXODuwpSsp8AVdKM2/HorrzxAfbKvWTByQ== - dependencies: - caniuse-lite "^1.0.30001313" - electron-to-chromium "^1.4.76" - escalade "^3.1.1" - node-releases "^2.0.2" - picocolors "^1.0.0" - - browserslist@^4.19.1, browserslist@^4.20.2: - version "4.20.2" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.2.tgz#567b41508757ecd904dab4d1c646c612cd3d4f88" - integrity sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA== - dependencies: - caniuse-lite "^1.0.30001317" - electron-to-chromium "^1.4.84" - escalade "^3.1.1" - node-releases "^2.0.2" - picocolors "^1.0.0" - - bs-logger@0.x: - version "0.2.6" - resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" - integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== - dependencies: - fast-json-stable-stringify "2.x" - - bs58@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" - integrity sha1-vhYedsNU9veIrkBx9j806MTwpCo= - dependencies: - base-x "^3.0.2" - - bs58check@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/bs58check/-/bs58check-2.1.2.tgz#53b018291228d82a5aa08e7d796fdafda54aebfc" - integrity sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA== - dependencies: - bs58 "^4.0.0" - create-hash "^1.1.0" - safe-buffer "^5.1.2" - - 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.6.1: - version "4.6.1" - resolved "https://registry.yarnpkg.com/bson/-/bson-4.6.1.tgz#2b5da517539bb0f7f3ffb54ac70a384ca899641c" - integrity sha512-I1LQ7Hz5zgwR4QquilLNZwbhPw0Apx7i7X9kGMBTsqPdml/03Q9NBtD9nt/19ahjlphktQImrnderxqpzeVDjw== - dependencies: - buffer "^5.6.0" - - buffer-alloc-unsafe@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" - integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== - - buffer-alloc@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" - integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== - dependencies: - buffer-alloc-unsafe "^1.1.0" - buffer-fill "^1.0.0" - - buffer-crc32@~0.2.3: - version "0.2.13" - resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" - integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= - - buffer-equal-constant-time@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" - integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= - - buffer-equal@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-0.0.1.tgz#91bc74b11ea405bc916bc6aa908faafa5b4aac4b" - integrity sha1-kbx0sR6kBbyRa8aqkI+q+ltKrEs= - - buffer-es6@^4.9.2: - version "4.9.3" - resolved "https://registry.yarnpkg.com/buffer-es6/-/buffer-es6-4.9.3.tgz#f26347b82df76fd37e18bcb5288c4970cfd5c404" - integrity sha1-8mNHuC33b9N+GLy1KIxJcM/VxAQ= - - buffer-fill@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" - integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= - - buffer-from@1.x, buffer-from@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - - buffer-to-arraybuffer@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/buffer-to-arraybuffer/-/buffer-to-arraybuffer-0.0.5.tgz#6064a40fa76eb43c723aba9ef8f6e1216d10511a" - integrity sha1-YGSkD6dutDxyOrqe+PbhIW0QURo= - - buffer-writer@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-2.0.0.tgz#ce7eb81a38f7829db09c873f2fbb792c0c98ec04" - integrity sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw== - - buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= - - buffer@^5.0.5, buffer@^5.2.0, buffer@^5.2.1, buffer@^5.5.0, buffer@^5.6.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" - integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.1.13" - - buffer@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - - bufferutil@^4.0.1: - version "4.0.6" - resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.6.tgz#ebd6c67c7922a0e902f053e5d8be5ec850e48433" - integrity sha512-jduaYOYtnio4aIAyc6UbvPCVcgq7nYpVnucyxr6eCYg/Woad9Hf/oxxBRDnGGjPfjUm6j5O/uBWhIu4iLebFaw== - dependencies: - node-gyp-build "^4.3.0" - - bytes@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= - - bytes@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.1.tgz#3f018291cb4cbad9accb6e6970bca9c8889e879a" - integrity sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg== - - bytes@3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" - integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== - - cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - - cacheable-request@^2.1.1: - version "2.1.4" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-2.1.4.tgz#0d808801b6342ad33c91df9d0b44dc09b91e5c3d" - integrity sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0= - dependencies: - clone-response "1.0.2" - get-stream "3.0.0" - http-cache-semantics "3.8.1" - keyv "3.0.0" - lowercase-keys "1.0.0" - normalize-url "2.0.1" - responselike "1.0.2" - - cacheable-request@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" - integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== - dependencies: - clone-response "^1.0.2" - get-stream "^5.1.0" - http-cache-semantics "^4.0.0" - keyv "^3.0.0" - lowercase-keys "^2.0.0" - normalize-url "^4.1.0" - responselike "^1.0.2" - - call-bind@^1.0.0, call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - - callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - - camelcase-css@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/camelcase-css/-/camelcase-css-2.0.1.tgz#ee978f6947914cc30c6b44741b6ed1df7f043fd5" - integrity sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA== - - camelcase@^5.0.0, camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - - camelcase@^6.0.0, camelcase@^6.2.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" - integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== - - caniuse-lite@^1.0.30001283, caniuse-lite@^1.0.30001313: - version "1.0.30001315" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001315.tgz#f1b1efd1171ee1170d52709a7252632dacbd7c77" - integrity sha512-5v7LFQU4Sb/qvkz7JcZkvtSH1Ko+1x2kgo3ocdBeMGZSOFpuE1kkm0kpTwLtWeFrw5qw08ulLxJjVIXIS8MkiQ== - - caniuse-lite@^1.0.30001317: - version "1.0.30001317" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001317.tgz#0548fb28fd5bc259a70b8c1ffdbe598037666a1b" - integrity sha512-xIZLh8gBm4dqNX0gkzrBeyI86J2eCjWzYAs40q88smG844YIrN4tVQl/RhquHvKEKImWWFIVh1Lxe5n1G/N+GQ== - - capture-exit@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" - integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== - dependencies: - rsvp "^4.8.4" - - caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - - ccount@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.1.0.tgz#246687debb6014735131be8abab2d93898f8d043" - integrity sha512-vlNK021QdI7PNeiUh/lKkC/mNHHfV0m/Ad5JoI0TYtlBnJAslM/JIkm/tGC88bkLIwO6OQ5uV6ztS6kVAtCDlg== - - ccount@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ccount/-/ccount-2.0.1.tgz#17a3bf82302e0870d6da43a01311a8bc02a3ecf5" - integrity sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg== - - chalk@2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba" - integrity sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q== - dependencies: - ansi-styles "^3.1.0" - escape-string-regexp "^1.0.5" - supports-color "^4.0.0" - - chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - - chalk@^2.0.0, chalk@^2.4.1: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - - 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== - - character-entities-html4@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/character-entities-html4/-/character-entities-html4-2.1.0.tgz#1f1adb940c971a4b22ba39ddca6b618dc6e56b2b" - integrity sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA== - - character-entities-legacy@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz#94bc1845dce70a5bb9d2ecc748725661293d8fc1" - integrity sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA== - - character-entities-legacy@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz#76bc83a90738901d7bc223a9e93759fdd560125b" - integrity sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ== - - character-entities@^1.0.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-1.2.4.tgz#e12c3939b7eaf4e5b15e7ad4c5e28e1d48c5b16b" - integrity sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw== - - character-entities@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/character-entities/-/character-entities-2.0.1.tgz#98724833e1e27990dee0bd0f2b8a859c3476aac7" - integrity sha512-OzmutCf2Kmc+6DrFrrPS8/tDh2+DpnrfzdICHWhcVC9eOd0N1PXmQEE1a8iM4IziIAG+8tmTq3K+oo0ubH6RRQ== - - character-reference-invalid@^1.0.0: - version "1.1.4" - resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz#083329cda0eae272ab3dbbf37e9a382c13af1560" - integrity sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg== - - character-reference-invalid@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz#85c66b041e43b47210faf401278abf808ac45cb9" - integrity sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw== - - chokidar@^3.5.3: - version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - - chownr@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" - integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== - - ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" - integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== - - ci-info@^3.2.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" - integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== - - cids@^0.7.1: - version "0.7.5" - resolved "https://registry.yarnpkg.com/cids/-/cids-0.7.5.tgz#60a08138a99bfb69b6be4ceb63bfef7a396b28b2" - integrity sha512-zT7mPeghoWAu+ppn8+BS1tQ5qGmbMfB4AregnQjA/qHY3GC1m1ptI9GkWNlgeu38r7CuRdXB47uY2XgAYt6QVA== - dependencies: - buffer "^5.5.0" - class-is "^1.1.0" - multibase "~0.6.0" - multicodec "^1.0.0" - multihashes "~0.4.15" - - cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - - cjs-module-lexer@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz#4186fcca0eae175970aee870b9fe2d6cf8d5655f" - integrity sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw== - - 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== - - class-is@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/class-is/-/class-is-1.1.0.tgz#9d3c0fba0440d211d843cec3dedfa48055005825" - integrity sha512-rhjH9AG1fvabIDoGRVH587413LPjTZgmDF9fOFCbFJQV4yuocX1mHxxvXI4g3cGwbVY9wAYIoKlg1N79frJKQw== - - class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - - classnames@^2.2.5, classnames@^2.2.6, classnames@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.1.tgz#dfcfa3891e306ec1dad105d0e88f4417b8535e8e" - integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== - - clean-stack@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" - integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== - - cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - - cli-highlight@^2.1.11: - version "2.1.11" - resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" - integrity sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg== - dependencies: - chalk "^4.0.0" - highlight.js "^10.7.1" - mz "^2.4.0" - parse5 "^5.1.1" - parse5-htmlparser2-tree-adapter "^6.0.0" - yargs "^16.0.0" - - cli-truncate@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" - integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== - dependencies: - slice-ansi "^3.0.0" - string-width "^4.2.0" - - cli-truncate@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-3.1.0.tgz#3f23ab12535e3d73e839bb43e73c9de487db1389" - integrity sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA== - dependencies: - slice-ansi "^5.0.0" - string-width "^5.0.0" - - clipboardy@1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-1.2.2.tgz#2ce320b9ed9be1514f79878b53ff9765420903e2" - integrity sha512-16KrBOV7bHmHdxcQiCvfUFYVFyEah4FI8vYT1Fr7CGSA4G+xBWMEfUEQJS1hxeHGtI9ju1Bzs9uXSbj5HZKArw== - dependencies: - arch "^2.1.0" - execa "^0.8.0" - - cliui@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" - integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^6.2.0" - - cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - - clone-response@1.0.2, clone-response@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" - integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= - dependencies: - mimic-response "^1.0.0" - - clone@~0.1.9: - version "0.1.19" - resolved "https://registry.yarnpkg.com/clone/-/clone-0.1.19.tgz#613fb68639b26a494ac53253e15b1a6bd88ada85" - integrity sha1-YT+2hjmyaklKxTJT4Vsaa9iK2oU= - - clsx@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.1.1.tgz#98b3134f9abbdf23b2663491ace13c5c03a73188" - integrity sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA== - - cluster-key-slot@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz#30474b2a981fb12172695833052bc0d01336d10d" - integrity sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw== - - co@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" - integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= - - cobe@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/cobe/-/cobe-0.4.1.tgz#d79846e05700c4da2915dd9ce3ef3b9f282f9328" - integrity sha512-hXVsSFXUisSQONxkBD5YC+z73ucBCbI/0Jw1h7OOwjo001X93HpSSGkYfoidCruxbNYYss/tpT40RZ8N1VIwhw== - dependencies: - phenomenon "^1.6.0" - - code-block-writer@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-11.0.0.tgz#5956fb186617f6740e2c3257757fea79315dd7d4" - integrity sha512-GEqWvEWWsOvER+g9keO4ohFoD3ymwyCnqY3hoTr7GZipYFwEhMHJw+TtV0rfgRhNImM6QWZGO2XYjlJVyYT62w== - dependencies: - tslib "2.3.1" - - 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== - - collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - - color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - - color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - - color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - - color-name@^1.1.4, color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - - colorette@^2.0.16: - version "2.0.16" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da" - integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g== - - colors@1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" - integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== - - combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - - comma-separated-tokens@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-2.0.2.tgz#d4c25abb679b7751c880be623c1179780fe1dd98" - integrity sha512-G5yTt3KQN4Yn7Yk4ed73hlZ1evrFKXeUW3086p3PRFNp7m2vIjI6Pg+Kgb+oyzhd9F2qdcoj67+y3SdxL5XWsg== - - commander@8.3.0, commander@^8.3.0: - version "8.3.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" - integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== - - commander@^2.8.1: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - - commander@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068" - integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA== - - commander@^6.2.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" - integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== - - component-emitter@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== - - concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - - concat-stream@^1.4.4: - version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" - integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^2.2.2" - typedarray "^0.0.6" - - content-disposition@0.5.4, content-disposition@^0.5.2, content-disposition@^0.5.3: - version "0.5.4" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" - integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== - dependencies: - safe-buffer "5.2.1" - - content-hash@^2.5.2: - version "2.5.2" - resolved "https://registry.yarnpkg.com/content-hash/-/content-hash-2.5.2.tgz#bbc2655e7c21f14fd3bfc7b7d4bfe6e454c9e211" - integrity sha512-FvIQKy0S1JaWV10sMsA7TRx8bpU+pqPkhbsfvOJAdjRXvYxEckAwQWGwtRjiaJfh+E0DvcWUGqcdjwMGFjsSdw== - dependencies: - cids "^0.7.1" - multicodec "^0.5.5" - multihashes "^0.4.15" - - content-type@1.0.4, content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== - - convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" - integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== - dependencies: - safe-buffer "~5.1.1" - - cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= - - cookie@0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" - integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== - - cookie@0.4.2, cookie@^0.4.1: - version "0.4.2" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" - integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== - - cookiejar@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.3.tgz#fc7a6216e408e74414b90230050842dacda75acc" - integrity sha512-JxbCBUdrfr6AQjOXrxoTvAMJO4HBTUIlBzslcJPAz+/KT8yk53fXun51u+RenNYvad/+Vc2DIz5o9UxlCDymFQ== - - copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= - - core-js-compat@^3.20.2, core-js-compat@^3.21.0: - version "3.21.1" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.21.1.tgz#cac369f67c8d134ff8f9bd1623e3bc2c42068c82" - integrity sha512-gbgX5AUvMb8gwxC7FLVWYT7Kkgu/y7+h/h1X43yJkNqhlK2fuYyQimqvKGNZFAY6CKii/GFKJ2cp/1/42TN36g== - dependencies: - browserslist "^4.19.1" - semver "7.0.0" - - core-js-pure@^3.20.2: - version "3.21.1" - resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.21.1.tgz#8c4d1e78839f5f46208de7230cebfb72bc3bdb51" - integrity sha512-12VZfFIu+wyVbBebyHmRTuEE/tZrB4tJToWcwAMcsp3h4+sHR+fMJWbKpYiCRWlhFBq+KNyO8rIV9rTkeVmznQ== - - core-js@^3: - version "3.21.1" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.21.1.tgz#f2e0ddc1fc43da6f904706e8e955bc19d06a0d94" - integrity sha512-FRq5b/VMrWlrmCzwRrpDYNxyHP9BcAZC+xHJaqTgIE5091ZV1NTmyh0sGOg5XqpnHvR0svdy0sv1gWA1zmhxig== - - core-util-is@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - - core-util-is@~1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" - integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== - - cors@2.8.5, cors@^2.8.1: - version "2.8.5" - resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" - integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== - dependencies: - object-assign "^4" - vary "^1" - - cosmiconfig@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-6.0.0.tgz#da4fee853c52f6b1e6935f41c1a2fc50bd4a9982" - integrity sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg== - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.1.0" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.7.2" - - cosmiconfig@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" - integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== - dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.2.1" - parse-json "^5.0.0" - path-type "^4.0.0" - yaml "^1.10.0" - - country-flag-icons@^1.0.2: - version "1.4.21" - resolved "https://registry.yarnpkg.com/country-flag-icons/-/country-flag-icons-1.4.21.tgz#0c00f57894890f5f41c8b632bcf5293cce80af02" - integrity sha512-bA9jDr+T5li7EsKdDx0xVnO0bdMdoT8IA3BNbeT2XSWUygR1okhiZ2+eYiC1EKLrFZhI4aEHni2w03lUlOjogg== - - crc-32@^1.2.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/crc-32/-/crc-32-1.2.1.tgz#436d2bcaad27bcb6bd073a2587139d3024a16460" - integrity sha512-Dn/xm/1vFFgs3nfrpEVScHoIslO9NZRITWGz/1E/St6u4xw99vfZzVkW0OSnzx2h9egej9xwMCEut6sqwokM/w== - dependencies: - exit-on-epipe "~1.0.1" - printj "~1.3.1" - - create-ecdh@^4.0.0: - version "4.0.4" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.4.tgz#d6e7f4bffa66736085a0762fd3a632684dabcc4e" - integrity sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A== - dependencies: - bn.js "^4.1.0" - elliptic "^6.5.3" - - create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" - integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" - - create-hmac@^1.1.0, create-hmac@^1.1.4, create-hmac@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" - integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - - create-require@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" - integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== - - cross-fetch@3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" - integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== - dependencies: - node-fetch "2.6.7" - - cross-spawn@7.0.3, cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: - version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - - cross-spawn@^5.0.1: - version "5.1.0" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" - integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk= - dependencies: - lru-cache "^4.0.1" - shebang-command "^1.2.0" - which "^1.2.9" - - cross-spawn@^6.0.0, cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - - crypto-browserify@3.12.0, crypto-browserify@^3.11.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" - integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - randomfill "^1.0.3" - - cssesc@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" - integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== - - cssom@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" - integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== - - cssom@~0.3.6: - version "0.3.8" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" - integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== - - cssstyle@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" - integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== - dependencies: - cssom "~0.3.6" - - csstype@^3.0.2, csstype@^3.0.4: - version "3.0.11" - resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.11.tgz#d66700c5eacfac1940deb4e3ee5642792d85cd33" - integrity sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw== - - d@1, d@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" - integrity sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA== - dependencies: - es5-ext "^0.10.50" - type "^1.0.1" - - damerau-levenshtein@^1.0.7: - version "1.0.8" - resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" - integrity sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA== - - dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - - data-urls@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" - integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== - dependencies: - abab "^2.0.3" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.0.0" - - dayjs-business-time@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/dayjs-business-time/-/dayjs-business-time-1.0.4.tgz#2970b80e832e92bbaa27a06ea62772b0d970b75b" - integrity sha512-v/0ynVV0Ih9Qw/pqJdScVHfoIaHkxLSom8j9+jO+VUOPnxC0fj5QGpDAZ94LUFd7jBkq2UO8C1LrVY+EHFx3aA== - dependencies: - dayjs "^1.10.4" - - dayjs@^1.10.4: - version "1.10.8" - resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.10.8.tgz#267df4bc6276fcb33c04a6735287e3f429abec41" - integrity sha512-wbNwDfBHHur9UOzNUjeKUOJ0fCb0a52Wx0xInmQ7Y8FstyajiV1NmK1e00cxsr9YrE9r7yAChE0VvpuY5Rnlow== - - debounce@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" - integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== - - debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - - debug@4, debug@4.3.3, debug@^4.0.0, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@~4.3.1: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== - dependencies: - ms "2.1.2" - - debug@^3.2.7: - version "3.2.7" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - - decamelize@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= - - decimal.js@^10.2.1: - version "10.3.1" - resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783" - integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ== - - decode-named-character-reference@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/decode-named-character-reference/-/decode-named-character-reference-1.0.1.tgz#57b2bd9112659cacbc449d3577d7dadb8e1f3d1b" - integrity sha512-YV/0HQHreRwKb7uBopyIkLG17jG6Sv2qUchk9qSoVJ2f+flwRsPNBO0hAnjt6mTNYUT+vw9Gy2ihXg4sUWPi2w== - dependencies: - character-entities "^2.0.0" - - decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= - - decompress-response@^3.2.0, decompress-response@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" - integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= - dependencies: - mimic-response "^1.0.0" - - decompress-tar@^4.0.0, decompress-tar@^4.1.0, decompress-tar@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/decompress-tar/-/decompress-tar-4.1.1.tgz#718cbd3fcb16209716e70a26b84e7ba4592e5af1" - integrity sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ== - dependencies: - file-type "^5.2.0" - is-stream "^1.1.0" - tar-stream "^1.5.2" - - decompress-tarbz2@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz#3082a5b880ea4043816349f378b56c516be1a39b" - integrity sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A== - dependencies: - decompress-tar "^4.1.0" - file-type "^6.1.0" - is-stream "^1.1.0" - seek-bzip "^1.0.5" - unbzip2-stream "^1.0.9" - - decompress-targz@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/decompress-targz/-/decompress-targz-4.1.1.tgz#c09bc35c4d11f3de09f2d2da53e9de23e7ce1eee" - integrity sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w== - dependencies: - decompress-tar "^4.1.1" - file-type "^5.2.0" - is-stream "^1.1.0" - - decompress-unzip@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/decompress-unzip/-/decompress-unzip-4.0.1.tgz#deaaccdfd14aeaf85578f733ae8210f9b4848f69" - integrity sha1-3qrM39FK6vhVePczroIQ+bSEj2k= - dependencies: - file-type "^3.8.0" - get-stream "^2.2.0" - pify "^2.3.0" - yauzl "^2.4.2" - - decompress@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/decompress/-/decompress-4.2.1.tgz#007f55cc6a62c055afa37c07eb6a4ee1b773f118" - integrity sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ== - dependencies: - decompress-tar "^4.0.0" - decompress-tarbz2 "^4.0.0" - decompress-targz "^4.0.0" - decompress-unzip "^4.0.1" - graceful-fs "^4.1.10" - make-dir "^1.0.0" - pify "^2.3.0" - strip-dirs "^2.0.0" - - dedent@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" - integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= - - deep-is@^0.1.3, deep-is@~0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - - deepmerge@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" - integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== - - defer-to-connect@^1.0.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" - integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== - - deferred-leveldown@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/deferred-leveldown/-/deferred-leveldown-0.2.0.tgz#2cef1f111e1c57870d8bbb8af2650e587cd2f5b4" - integrity sha1-LO8fER4cV4cNi7uK8mUOWHzS9bQ= - dependencies: - abstract-leveldown "~0.12.1" - - define-lazy-prop@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" - integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== - - define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - - define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= - dependencies: - is-descriptor "^0.1.0" - - define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= - dependencies: - is-descriptor "^1.0.0" - - define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - - defined@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" - integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM= - - delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - - denque@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/denque/-/denque-2.0.1.tgz#bcef4c1b80dc32efe97515744f21a4229ab8934a" - integrity sha512-tfiWc6BQLXNLpNiR5iGd0Ocu3P3VpxfzFiqubLgMfhfOw9WyvgJBd46CClNn9k3qfbjvT//0cf7AlYRX/OslMQ== - - depd@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.1.tgz#5783b4e1c459f06fa5ca27f991f3d06e7a310359" - integrity sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k= - - depd@^1.1.0, depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - - dequal@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.2.tgz#85ca22025e3a87e65ef75a7a437b35284a7e319d" - integrity sha512-q9K8BlJVxK7hQYqa6XISGmBZbtQQWVXSrRrWreHC94rMt1QL/Impruc+7p2CYSYuVIUr+YCt6hjrs1kkdJRTug== - - des.js@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.1.tgz#5382142e1bdc53f85d86d53e5f4aa7deb91e0843" - integrity sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA== - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - - destroy@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= - - detect-browser@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/detect-browser/-/detect-browser-5.3.0.tgz#9705ef2bddf46072d0f7265a1fe300e36fe7ceca" - integrity sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w== - - detect-element-overflow@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/detect-element-overflow/-/detect-element-overflow-1.2.0.tgz#86e504292ffedc3aef813395fbdf0261aaf6afa9" - integrity sha512-Jtr9ivYPhpd9OJux+hjL0QjUKiS1Ghgy8tvIufUjFslQgIWvgGr4mn57H190APbKkiOmXnmtMI6ytaKzMusecg== - - 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== - - detect-node-es@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" - integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ== - - detect-node@^2.0.4, detect-node@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" - integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== - - detective@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/detective/-/detective-5.2.0.tgz#feb2a77e85b904ecdea459ad897cc90a99bd2a7b" - integrity sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg== - dependencies: - acorn-node "^1.6.1" - defined "^1.0.0" - minimist "^1.1.1" - - didyoumean@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/didyoumean/-/didyoumean-1.2.2.tgz#989346ffe9e839b4555ecf5666edea0d3e8ad037" - integrity sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw== - - diff-sequences@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" - integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== - - diff-sequences@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" - integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== - - diff@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" - integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== - - diff@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" - integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== - - diffie-hellman@^5.0.0: - version "5.0.3" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" - integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - - dijkstrajs@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/dijkstrajs/-/dijkstrajs-1.0.2.tgz#2e48c0d3b825462afe75ab4ad5e829c8ece36257" - integrity sha512-QV6PMaHTCNmKSeP6QoXhVTw9snc9VD8MulTT0Bd99Pacp4SS1cjcrYPgBPmibqKVtMJJfqC6XvOXgPMEEPH/fg== - - dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - - dlv@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/dlv/-/dlv-1.1.3.tgz#5c198a8a11453596e751494d49874bc7732f2e79" - integrity sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA== - - doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - - doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - - dom-helpers@^5.0.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" - integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== - dependencies: - "@babel/runtime" "^7.8.7" - csstype "^3.0.2" - - dom-walk@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" - integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== - - domexception@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" - integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== - dependencies: - webidl-conversions "^5.0.0" - - dotenv@^8.2.0: - version "8.6.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" - integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== - - download@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/download/-/download-8.0.0.tgz#afc0b309730811731aae9f5371c9f46be73e51b1" - integrity sha512-ASRY5QhDk7FK+XrQtQyvhpDKanLluEEQtWl/J7Lxuf/b+i8RYh997QeXvL85xitrmRKVlx9c7eTrcRdq2GS4eA== - dependencies: - archive-type "^4.0.0" - content-disposition "^0.5.2" - decompress "^4.2.1" - ext-name "^5.0.0" - file-type "^11.1.0" - filenamify "^3.0.0" - get-stream "^4.1.0" - got "^8.3.1" - make-dir "^2.1.0" - p-event "^2.1.0" - pify "^4.0.1" - - duplexer3@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" - integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= - - duplexer@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" - integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== - - eastasianwidth@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" - integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== - - ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - - ecdsa-sig-formatter@1.0.11, ecdsa-sig-formatter@^1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" - integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== - dependencies: - safe-buffer "^5.0.1" - - ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - - electron-to-chromium@^1.4.76: - version "1.4.82" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.82.tgz#51e123ca434b1eba8c434ece2b54f095b304a651" - integrity sha512-Ks+ANzLoIrFDUOJdjxYMH6CMKB8UQo5modAwvSZTxgF+vEs/U7G5IbWFUp6dS4klPkTDVdxbORuk8xAXXhMsWw== - - electron-to-chromium@^1.4.84: - version "1.4.85" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.85.tgz#a3666ba42147026b9f34d4d8d4caf0740e80f751" - integrity sha512-K9AsQ41WS2bjZUFpRWfvaS4RjEcRCamEkBJN1Z1TQILBfP1H8QnJ9ti0wiLiMv0sRjX3EHKzgs9jDnmGFx2jXg== - - elliptic@6.5.4, elliptic@^6.4.0, elliptic@^6.5.3, elliptic@^6.5.4: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - - emittery@^0.7.1: - version "0.7.2" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" - integrity sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ== - - emittery@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" - integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== - - emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - - emoji-regex@^9.2.2: - version "9.2.2" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" - integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== - - emojis-list@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" - integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== - - encode-utf8@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/encode-utf8/-/encode-utf8-1.0.3.tgz#f30fdd31da07fb596f281beb2f6b027851994cda" - integrity sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw== - - encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= - - end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.4: - version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" - integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== - dependencies: - once "^1.4.0" - - enhanced-resolve@^5.7.0: - version "5.9.2" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz#0224dcd6a43389ebfb2d55efee517e5466772dd9" - integrity sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA== - dependencies: - graceful-fs "^4.2.4" - tapable "^2.2.0" - - env-cmd@10.1.0, env-cmd@^10.1.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/env-cmd/-/env-cmd-10.1.0.tgz#c7f5d3b550c9519f137fdac4dd8fb6866a8c8c4b" - integrity sha512-mMdWTT9XKN7yNth/6N6g2GuKuJTsKMDHlQFUDacb/heQRRWOTIZ42t1rMHnQu4jYxU1ajdTeJM+9eEETlqToMA== - dependencies: - commander "^4.0.0" - cross-spawn "^7.0.0" - - errno@^0.1.1, errno@~0.1.1: - version "0.1.8" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" - integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A== - dependencies: - prr "~1.0.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.18.5, es-abstract@^1.19.0, es-abstract@^1.19.1: - version "1.19.1" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.19.1.tgz#d4885796876916959de78edaa0df456627115ec3" - integrity sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w== - dependencies: - call-bind "^1.0.2" - es-to-primitive "^1.2.1" - function-bind "^1.1.1" - get-intrinsic "^1.1.1" - get-symbol-description "^1.0.0" - has "^1.0.3" - has-symbols "^1.0.2" - internal-slot "^1.0.3" - is-callable "^1.2.4" - is-negative-zero "^2.0.1" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.1" - is-string "^1.0.7" - is-weakref "^1.0.1" - object-inspect "^1.11.0" - object-keys "^1.1.1" - object.assign "^4.1.2" - string.prototype.trimend "^1.0.4" - string.prototype.trimstart "^1.0.4" - unbox-primitive "^1.0.1" - - es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - - es5-ext@^0.10.35, es5-ext@^0.10.50: - version "0.10.58" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.58.tgz#5b97d94236285fb87c8ffc782cf42eb0a25d2ae0" - integrity sha512-LHO+KBBaHGwjy32ibSaMY+ZzjpC4K4I5bPoijICMBL7gXEXfrEUrzssmNP+KigbQEp1dRUnGkry/vUnxOqptLQ== - dependencies: - es6-iterator "^2.0.3" - es6-symbol "^3.1.3" - next-tick "^1.1.0" - - es6-iterator@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - integrity sha1-p96IkUGgWpSwhUQDstCg+/qY87c= - dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - - es6-symbol@^3.1.1, es6-symbol@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.3.tgz#bad5d3c1bcdac28269f4cb331e431c78ac705d18" - integrity sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA== - dependencies: - d "^1.0.1" - ext "^1.1.2" - - escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - - escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= - - escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity 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" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - - escodegen@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" - integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== - dependencies: - esprima "^4.0.1" - estraverse "^5.2.0" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.6.1" - - eslint-config-next@^12.0.8: - version "12.1.0" - resolved "https://registry.yarnpkg.com/eslint-config-next/-/eslint-config-next-12.1.0.tgz#8ace680dc5207e6ab6c915f3989adec122f582e7" - integrity sha512-tBhuUgoDITcdcM7xFvensi9I5WTI4dnvH4ETGRg1U8ZKpXrZsWQFdOKIDzR3RLP5HR3xXrLviaMM4c3zVoE/pA== - dependencies: - "@next/eslint-plugin-next" "12.1.0" - "@rushstack/eslint-patch" "^1.0.8" - "@typescript-eslint/parser" "^5.0.0" - eslint-import-resolver-node "^0.3.4" - eslint-import-resolver-typescript "^2.4.0" - eslint-plugin-import "^2.25.2" - eslint-plugin-jsx-a11y "^6.5.1" - eslint-plugin-react "^7.27.0" - eslint-plugin-react-hooks "^4.3.0" - - eslint-config-prettier@^8.5.0: - version "8.5.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz#5a81680ec934beca02c7b1a61cf8ca34b66feab1" - integrity sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q== - - eslint-import-resolver-node@^0.3.4, eslint-import-resolver-node@^0.3.6: - version "0.3.6" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz#4048b958395da89668252001dbd9eca6b83bacbd" - integrity sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw== - dependencies: - debug "^3.2.7" - resolve "^1.20.0" - - eslint-import-resolver-typescript@^2.4.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.5.0.tgz#07661966b272d14ba97f597b51e1a588f9722f0a" - integrity sha512-qZ6e5CFr+I7K4VVhQu3M/9xGv9/YmwsEXrsm3nimw8vWaVHRDrQRp26BgCypTxBp3vUp4o5aVEJRiy0F2DFddQ== - dependencies: - debug "^4.3.1" - glob "^7.1.7" - is-glob "^4.0.1" - resolve "^1.20.0" - tsconfig-paths "^3.9.0" - - eslint-module-utils@2.7.3, eslint-module-utils@^2.7.2: - version "2.7.3" - resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.7.3.tgz#ad7e3a10552fdd0642e1e55292781bd6e34876ee" - integrity sha512-088JEC7O3lDZM9xGe0RerkOMd0EjFl+Yvd1jPWIkMT5u3H9+HC34mWWPnqPrN13gieT9pBOO+Qt07Nb/6TresQ== - dependencies: - debug "^3.2.7" - find-up "^2.1.0" - - eslint-plugin-import@^2.25.2: - version "2.25.4" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz#322f3f916a4e9e991ac7af32032c25ce313209f1" - integrity sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA== - dependencies: - array-includes "^3.1.4" - array.prototype.flat "^1.2.5" - debug "^2.6.9" - doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.6" - eslint-module-utils "^2.7.2" - has "^1.0.3" - is-core-module "^2.8.0" - is-glob "^4.0.3" - minimatch "^3.0.4" - object.values "^1.1.5" - resolve "^1.20.0" - tsconfig-paths "^3.12.0" - - eslint-plugin-jsx-a11y@^6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.5.1.tgz#cdbf2df901040ca140b6ec14715c988889c2a6d8" - integrity sha512-sVCFKX9fllURnXT2JwLN5Qgo24Ug5NF6dxhkmxsMEUZhXRcGg+X3e1JbJ84YePQKBl5E0ZjAH5Q4rkdcGY99+g== - dependencies: - "@babel/runtime" "^7.16.3" - aria-query "^4.2.2" - array-includes "^3.1.4" - ast-types-flow "^0.0.7" - axe-core "^4.3.5" - axobject-query "^2.2.0" - damerau-levenshtein "^1.0.7" - emoji-regex "^9.2.2" - has "^1.0.3" - jsx-ast-utils "^3.2.1" - language-tags "^1.0.5" - minimatch "^3.0.4" - - eslint-plugin-playwright@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-playwright/-/eslint-plugin-playwright-0.8.0.tgz#7aa3729c7d841d82c5279772000c69b1262f8e43" - integrity sha512-9uJH25m6H3jwU5O7bHD5M8cLx46L72EnIUe3dZqTox6M+WzOFzeUWaDJHHCdLGXZ8XlAU4mbCZnP7uhjKepfRA== - - eslint-plugin-prettier@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz#8b99d1e4b8b24a762472b4567992023619cb98e0" - integrity sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ== - dependencies: - prettier-linter-helpers "^1.0.0" - - eslint-plugin-react-hooks@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz#318dbf312e06fab1c835a4abef00121751ac1172" - integrity sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA== - - eslint-plugin-react@^7.27.0: - version "7.29.3" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.29.3.tgz#f4eab757f2756d25d6d4c2a58a9e20b004791f05" - integrity sha512-MzW6TuCnDOcta67CkpDyRfRsEVx9FNMDV8wZsDqe1luHPdGTrQIUaUXD27Ja3gHsdOIs/cXzNchWGlqm+qRVRg== - dependencies: - array-includes "^3.1.4" - array.prototype.flatmap "^1.2.5" - doctrine "^2.1.0" - estraverse "^5.3.0" - jsx-ast-utils "^2.4.1 || ^3.0.0" - minimatch "^3.1.2" - object.entries "^1.1.5" - object.fromentries "^2.0.5" - object.hasown "^1.1.0" - object.values "^1.1.5" - prop-types "^15.8.1" - resolve "^2.0.0-next.3" - semver "^6.3.0" - string.prototype.matchall "^4.0.6" - - eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== - dependencies: - esrecurse "^4.3.0" - estraverse "^4.1.1" - - eslint-scope@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" - integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== - dependencies: - esrecurse "^4.3.0" - estraverse "^5.2.0" - - eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - - eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - - eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" - integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== - - eslint@^8.10.0: - version "8.11.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.11.0.tgz#88b91cfba1356fc10bb9eb592958457dfe09fb37" - integrity sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA== - dependencies: - "@eslint/eslintrc" "^1.2.1" - "@humanwhocodes/config-array" "^0.9.2" - ajv "^6.10.0" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.3.2" - doctrine "^3.0.0" - escape-string-regexp "^4.0.0" - eslint-scope "^7.1.1" - eslint-utils "^3.0.0" - eslint-visitor-keys "^3.3.0" - espree "^9.3.1" - esquery "^1.4.0" - esutils "^2.0.2" - fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^6.0.1" - globals "^13.6.0" - ignore "^5.2.0" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - js-yaml "^4.1.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash.merge "^4.6.2" - minimatch "^3.0.4" - natural-compare "^1.4.0" - optionator "^0.9.1" - regexpp "^3.2.0" - strip-ansi "^6.0.1" - strip-json-comments "^3.1.0" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - - espree@^9.3.1: - version "9.3.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.1.tgz#8793b4bc27ea4c778c19908e0719e7b8f4115bcd" - integrity sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ== - dependencies: - acorn "^8.7.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^3.3.0" - - esprima@^4.0.0, esprima@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - - esquery@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" - integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== - dependencies: - estraverse "^5.1.0" - - esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - - estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - - estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - - estree-util-attach-comments@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/estree-util-attach-comments/-/estree-util-attach-comments-2.0.0.tgz#2c06d484dfcf841b5946bcb84d5412cbcd544e22" - integrity sha512-kT9YVRvlt2ewPp9BazfIIgXMGsXOEpOm57bK8aa4F3eOEndMml2JAETjWaG3SZYHmC6axSNIzHGY718dYwIuVg== - dependencies: - "@types/estree" "^0.0.46" - - estree-util-build-jsx@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/estree-util-build-jsx/-/estree-util-build-jsx-2.0.0.tgz#4903e2a923ebc791f86e78ec3687d01715dec902" - integrity sha512-d49hPGqBCJF/bF06g1Ywg7zjH1mrrUdPPrixBlKBxcX4WvMYlUUJ8BkrwlzWc8/fm6XqGgk5jilhgeZBDEGwOQ== - dependencies: - "@types/estree-jsx" "^0.0.1" - estree-util-is-identifier-name "^2.0.0" - estree-walker "^3.0.0" - - estree-util-is-identifier-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/estree-util-is-identifier-name/-/estree-util-is-identifier-name-2.0.0.tgz#e2d3d2ae3032c017b2112832bfc5d8ba938c8010" - integrity sha512-aXXZFVMnBBDRP81vS4YtAYJ0hUkgEsXea7lNKWCOeaAquGb1Jm2rcONPB5fpzwgbNxulTvrWuKnp9UElUGAKeQ== - - estree-util-visit@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/estree-util-visit/-/estree-util-visit-1.1.0.tgz#c0ea7942c40ac7889a77b57a11e92f987744bc6f" - integrity sha512-3lXJ4Us9j8TUif9cWcQy81t9p5OLasnDuuhrFiqb+XstmKC1d1LmrQWYsY49/9URcfHE64mPypDBaNK9NwWDPQ== - dependencies: - "@types/estree-jsx" "^0.0.1" - "@types/unist" "^2.0.0" - - estree-walker@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-1.0.1.tgz#31bc5d612c96b704106b477e6dd5d8aa138cb700" - integrity sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg== - - estree-walker@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" - integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== - - estree-walker@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.1.tgz#c2a9fb4a30232f5039b7c030b37ead691932debd" - integrity sha512-woY0RUD87WzMBUiZLx8NsYr23N5BKsOMZHhu2hoNRVh6NXGfoiT1KOL8G3UHlJAnEDGmfa5ubNA/AacfG+Kb0g== - - esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - - etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= - - eth-ens-namehash@2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/eth-ens-namehash/-/eth-ens-namehash-2.0.8.tgz#229ac46eca86d52e0c991e7cb2aef83ff0f68bcf" - integrity sha1-IprEbsqG1S4MmR58sq74P/D2i88= - dependencies: - idna-uts46-hx "^2.3.1" - js-sha3 "^0.5.7" - - eth-lib@0.2.8: - version "0.2.8" - resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.2.8.tgz#b194058bef4b220ad12ea497431d6cb6aa0623c8" - integrity sha512-ArJ7x1WcWOlSpzdoTBX8vkwlkSQ85CjjifSZtV4co64vWxSV8geWfPI9x4SVYu3DSxnX4yWFVTtGL+j9DUFLNw== - dependencies: - bn.js "^4.11.6" - elliptic "^6.4.0" - xhr-request-promise "^0.1.2" - - eth-lib@^0.1.26: - version "0.1.29" - resolved "https://registry.yarnpkg.com/eth-lib/-/eth-lib-0.1.29.tgz#0c11f5060d42da9f931eab6199084734f4dbd1d9" - integrity sha512-bfttrr3/7gG4E02HoWTDUcDDslN003OlOoBxk9virpAZQ1ja/jDgwkWB8QfJF7ojuEowrqy+lzp9VcJG7/k5bQ== - dependencies: - bn.js "^4.11.6" - elliptic "^6.4.0" - nano-json-stream-parser "^0.1.2" - servify "^0.1.12" - ws "^3.0.0" - xhr-request-promise "^0.1.2" - - eth-rpc-errors@^4.0.2: - version "4.0.3" - resolved "https://registry.yarnpkg.com/eth-rpc-errors/-/eth-rpc-errors-4.0.3.tgz#6ddb6190a4bf360afda82790bb7d9d5e724f423a" - integrity sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg== - dependencies: - fast-safe-stringify "^2.0.6" - - ethereum-bloom-filters@^1.0.6: - version "1.0.10" - resolved "https://registry.yarnpkg.com/ethereum-bloom-filters/-/ethereum-bloom-filters-1.0.10.tgz#3ca07f4aed698e75bd134584850260246a5fed8a" - integrity sha512-rxJ5OFN3RwjQxDcFP2Z5+Q9ho4eIdEmSc2ht0fCu8Se9nbXjZ7/031uXoUYJ87KHCOdVeiUuwSnoS7hmYAGVHA== - dependencies: - js-sha3 "^0.8.0" - - ethereum-cryptography@^0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz#8d6143cfc3d74bf79bbd8edecdf29e4ae20dd191" - integrity sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ== - dependencies: - "@types/pbkdf2" "^3.0.0" - "@types/secp256k1" "^4.0.1" - blakejs "^1.1.0" - browserify-aes "^1.2.0" - bs58check "^2.1.2" - create-hash "^1.2.0" - create-hmac "^1.1.7" - hash.js "^1.1.7" - keccak "^3.0.0" - pbkdf2 "^3.0.17" - randombytes "^2.1.0" - safe-buffer "^5.1.2" - scrypt-js "^3.0.0" - secp256k1 "^4.0.1" - setimmediate "^1.0.5" - - ethereumjs-util@^7.0.10, ethereumjs-util@^7.1.0, ethereumjs-util@^7.1.4: - version "7.1.4" - resolved "https://registry.yarnpkg.com/ethereumjs-util/-/ethereumjs-util-7.1.4.tgz#a6885bcdd92045b06f596c7626c3e89ab3312458" - integrity sha512-p6KmuPCX4mZIqsQzXfmSx9Y0l2hqf+VkAiwSisW3UKUFdk8ZkAt+AYaor83z2nSi6CU2zSsXMlD80hAbNEGM0A== - dependencies: - "@types/bn.js" "^5.1.0" - bn.js "^5.1.2" - create-hash "^1.1.2" - ethereum-cryptography "^0.1.3" - rlp "^2.2.4" - - ethjs-unit@0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/ethjs-unit/-/ethjs-unit-0.1.6.tgz#c665921e476e87bce2a9d588a6fe0405b2c41699" - integrity sha1-xmWSHkduh7ziqdWIpv4EBbLEFpk= - dependencies: - bn.js "4.11.6" - number-to-bn "1.7.0" - - event-target-shim@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" - integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== - - eventemitter3@4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.4.tgz#b5463ace635a083d018bdc7c917b4c5f10a85384" - integrity sha512-rlaVLnVxtxvoyLsQQFBx53YmXHDxRIzzTLbdfxqi4yocpSjAxXwkU0cScM5JgSKMqEhrZpnvQ2D9gjylR0AimQ== - - events@^3.1.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" - integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== - - evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" - integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - - exec-sh@^0.3.2: - version "0.3.6" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" - integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w== - - execa@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-0.8.0.tgz#d8d76bbc1b55217ed190fd6dd49d3c774ecfc8da" - integrity sha1-2NdrvBtVIX7RkP1t1J08d07PyNo= - dependencies: - cross-spawn "^5.0.1" - get-stream "^3.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - - execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - - execa@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" - integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== - dependencies: - cross-spawn "^7.0.0" - get-stream "^5.0.0" - human-signals "^1.1.1" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.0" - onetime "^5.1.0" - signal-exit "^3.0.2" - strip-final-newline "^2.0.0" - - execa@^5.0.0, execa@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - - exif-parser@^0.1.12: - version "0.1.12" - resolved "https://registry.yarnpkg.com/exif-parser/-/exif-parser-0.1.12.tgz#58a9d2d72c02c1f6f02a0ef4a9166272b7760922" - integrity sha1-WKnS1ywCwfbwKg70qRZicrd2CSI= - - exit-on-epipe@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/exit-on-epipe/-/exit-on-epipe-1.0.1.tgz#0bdd92e87d5285d267daa8171d0eb06159689692" - integrity sha512-h2z5mrROTxce56S+pnvAV890uu7ls7f1kEvVGJbw1OlFH3/mlJ5bkXu0KRyW94v37zzHPiUd55iLn3DA7TjWpw== - - exit@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= - - expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - - expect@27.2.5: - version "27.2.5" - resolved "https://registry.yarnpkg.com/expect/-/expect-27.2.5.tgz#16154aaa60b4d9a5b0adacfea3e4d6178f4b93fd" - integrity sha512-ZrO0w7bo8BgGoP/bLz+HDCI+0Hfei9jUSZs5yI/Wyn9VkG9w8oJ7rHRgYj+MA7yqqFa0IwHA3flJzZtYugShJA== - dependencies: - "@jest/types" "^27.2.5" - ansi-styles "^5.0.0" - jest-get-type "^27.0.6" - jest-matcher-utils "^27.2.5" - jest-message-util "^27.2.5" - jest-regex-util "^27.0.6" - - expect@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" - integrity sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA== - dependencies: - "@jest/types" "^26.6.2" - ansi-styles "^4.0.0" - jest-get-type "^26.3.0" - jest-matcher-utils "^26.6.2" - jest-message-util "^26.6.2" - jest-regex-util "^26.0.0" - - expect@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/expect/-/expect-27.5.1.tgz#83ce59f1e5bdf5f9d2b94b61d2050db48f3fef74" - integrity sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw== - dependencies: - "@jest/types" "^27.5.1" - jest-get-type "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" - - express@4.17.2: - version "4.17.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.17.2.tgz#c18369f265297319beed4e5558753cc8c1364cb3" - integrity sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg== - dependencies: - accepts "~1.3.7" - array-flatten "1.1.1" - body-parser "1.19.1" - content-disposition "0.5.4" - content-type "~1.0.4" - cookie "0.4.1" - cookie-signature "1.0.6" - debug "2.6.9" - depd "~1.1.2" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "~1.1.2" - fresh "0.5.2" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.7" - qs "6.9.6" - range-parser "~1.2.1" - safe-buffer "5.2.1" - send "0.17.2" - serve-static "1.14.2" - setprototypeof "1.2.0" - statuses "~1.5.0" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - - express@^4.14.0: - version "4.17.3" - resolved "https://registry.yarnpkg.com/express/-/express-4.17.3.tgz#f6c7302194a4fb54271b73a1fe7a06478c8f85a1" - integrity sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg== - dependencies: - accepts "~1.3.8" - array-flatten "1.1.1" - body-parser "1.19.2" - content-disposition "0.5.4" - content-type "~1.0.4" - cookie "0.4.2" - cookie-signature "1.0.6" - debug "2.6.9" - depd "~1.1.2" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "~1.1.2" - fresh "0.5.2" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.7" - qs "6.9.7" - range-parser "~1.2.1" - safe-buffer "5.2.1" - send "0.17.2" - serve-static "1.14.2" - setprototypeof "1.2.0" - statuses "~1.5.0" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - - ext-list@^2.0.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37" - integrity sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA== - dependencies: - mime-db "^1.28.0" - - ext-name@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/ext-name/-/ext-name-5.0.0.tgz#70781981d183ee15d13993c8822045c506c8f0a6" - integrity sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ== - dependencies: - ext-list "^2.0.0" - sort-keys-length "^1.0.0" - - ext@^1.1.2: - version "1.6.0" - resolved "https://registry.yarnpkg.com/ext/-/ext-1.6.0.tgz#3871d50641e874cc172e2b53f919842d19db4c52" - integrity sha512-sdBImtzkq2HpkdRLtlLWDa6w4DX22ijZLKx8BMPUuKe1c5lbN6xwQDQCxSfxBQnHZ13ls/FH0MQZx/q/gr6FQg== - dependencies: - type "^2.5.0" - - extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= - dependencies: - is-extendable "^0.1.0" - - extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - - extend@^3.0.0, extend@^3.0.2, extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - - extension-port-stream@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extension-port-stream/-/extension-port-stream-2.0.1.tgz#d374820c581418c2275d3c4439ade0b82c4cfac6" - integrity sha512-ltrv4Dh/979I04+D4Te6TFygfRSOc5EBzzlHRldWMS8v73V80qWluxH88hqF0qyUsBXTb8NmzlmSipcre6a+rg== - dependencies: - webextension-polyfill-ts "^0.22.0" - - extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - - extract-zip@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" - integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== - dependencies: - debug "^4.1.1" - get-stream "^5.1.0" - yauzl "^2.10.0" - optionalDependencies: - "@types/yauzl" "^2.9.1" - - extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - - extsprintf@^1.2.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" - integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== - - fast-deep-equal@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= - - fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - - fast-diff@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" - integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== - - fast-equals@^1.6.3: - version "1.6.3" - resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-1.6.3.tgz#84839a1ce20627c463e1892f2ae316380c81b459" - integrity sha512-4WKW0AL5+WEqO0zWavAfYGY1qwLsBgE//DN4TTcVEN2UlINgkv9b3vm2iHicoenWKSX9mKWmGOsU/iI5IST7pQ== - - fast-glob@^3.2.11, fast-glob@^3.2.7, fast-glob@^3.2.9: - version "3.2.11" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" - integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - - fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - - fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= - - fast-safe-stringify@^2.0.6: - version "2.1.1" - resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" - integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== - - fast-text-encoding@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz#ec02ac8e01ab8a319af182dae2681213cfe9ce53" - integrity sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig== - - fastq@^1.6.0: - version "1.13.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c" - integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw== - dependencies: - reusify "^1.0.4" - - 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" - - fd-slicer@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" - integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= - dependencies: - pend "~1.2.0" - - file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== - dependencies: - flat-cache "^3.0.4" - - file-type@^11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-11.1.0.tgz#93780f3fed98b599755d846b99a1617a2ad063b8" - integrity sha512-rM0UO7Qm9K7TWTtA6AShI/t7H5BPjDeGVDaNyg9BjHAj3PysKy7+8C8D137R88jnR3rFJZQB/tFgydl5sN5m7g== - - file-type@^3.8.0: - version "3.9.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-3.9.0.tgz#257a078384d1db8087bc449d107d52a52672b9e9" - integrity sha1-JXoHg4TR24CHvESdEH1SpSZyuek= - - file-type@^4.2.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-4.4.0.tgz#1b600e5fca1fbdc6e80c0a70c71c8dba5f7906c5" - integrity sha1-G2AOX8ofvcboDApwxxyNul95BsU= - - file-type@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-5.2.0.tgz#2ddbea7c73ffe36368dfae49dc338c058c2b8ad6" - integrity sha1-LdvqfHP/42No365J3DOMBYwritY= - - file-type@^6.1.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-6.2.0.tgz#e50cd75d356ffed4e306dc4f5bcf52a79903a919" - integrity sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg== - - file-type@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/file-type/-/file-type-9.0.0.tgz#a68d5ad07f486414dfb2c8866f73161946714a18" - integrity sha512-Qe/5NJrgIOlwijpq3B7BEpzPFcgzggOTagZmkXQY4LA6bsXKTUstK7Wp12lEJ/mLKTpvIZxmIuRcLYWT6ov9lw== - - filename-reserved-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz#abf73dfab735d045440abfea2d91f389ebbfa229" - integrity sha1-q/c9+rc10EVECr/qLZHzieu/oik= - - filenamify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/filenamify/-/filenamify-3.0.0.tgz#9603eb688179f8c5d40d828626dcbb92c3a4672c" - integrity sha512-5EFZ//MsvJgXjBAFJ+Bh2YaCTRF/VP1YOmGrgt+KJ4SFRLjI87EIdwLLuT6wQX0I4F9W41xutobzczjsOKlI/g== - dependencies: - filename-reserved-regex "^2.0.0" - strip-outer "^1.0.0" - trim-repeated "^1.0.0" - - fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - - fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - - finalhandler@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" - integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.3" - 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-root@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" - integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== - - find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - - find-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" - integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== - dependencies: - locate-path "^3.0.0" - - find-up@^4.0.0, find-up@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" - integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== - dependencies: - locate-path "^5.0.0" - path-exists "^4.0.0" - - flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== - dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" - - flatted@^3.1.0: - version "3.2.5" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" - integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== - - focus-visible@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/focus-visible/-/focus-visible-5.2.0.tgz#3a9e41fccf587bd25dcc2ef045508284f0a4d6b3" - integrity sha512-Rwix9pBtC1Nuy5wysTmKy+UjbDJpIfg8eHjw0rjZ1mX4GNLz1Bmd16uDpI3Gk1i70Fgcs8Csg2lPm8HULFg9DQ== - - for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= - - foreach@^2.0.5, foreach@~2.0.1: - version "2.0.5" - resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" - integrity sha1-C+4AUBiusmDQo6865ljdATbsG5k= - - forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - - form-data@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" - integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - - form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - - forwarded@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" - integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== - - fraction.js@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" - integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== - - fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= - dependencies: - map-cache "^0.2.2" - - fresh@0.5.2, fresh@^0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= - - from2@^2.1.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" - integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.0" - - fs-constants@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" - integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== - - fs-extra@^4.0.2: - version "4.0.3" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" - integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - - fs-extra@^8.0.1: - version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" - integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== - dependencies: - graceful-fs "^4.2.0" - jsonfile "^4.0.0" - universalify "^0.1.0" - - fs-minipass@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" - integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== - dependencies: - minipass "^2.6.0" - - fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - - fsevents@^2.1.2, fsevents@^2.3.2, fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== - - function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - - functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= - - fwd-stream@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/fwd-stream/-/fwd-stream-1.0.4.tgz#ed281cabed46feecf921ee32dc4c50b372ac7cfa" - integrity sha1-7Sgcq+1G/uz5Ie4y3ExQs3KsfPo= - dependencies: - readable-stream "~1.0.26-4" - - gaxios@^4.0.0: - version "4.3.2" - resolved "https://registry.yarnpkg.com/gaxios/-/gaxios-4.3.2.tgz#845827c2dc25a0213c8ab4155c7a28910f5be83f" - integrity sha512-T+ap6GM6UZ0c4E6yb1y/hy2UB6hTrqhglp3XfmU9qbLCGRYhLVV5aRPpC4EmoG8N8zOnkYCgoBz+ScvGAARY6Q== - dependencies: - abort-controller "^3.0.0" - extend "^3.0.2" - https-proxy-agent "^5.0.0" - is-stream "^2.0.0" - node-fetch "^2.6.1" - - gcp-metadata@^4.2.0: - version "4.3.1" - resolved "https://registry.yarnpkg.com/gcp-metadata/-/gcp-metadata-4.3.1.tgz#fb205fe6a90fef2fd9c85e6ba06e5559ee1eefa9" - integrity sha512-x850LS5N7V1F3UcV7PoupzGsyD6iVwTVvsh3tbXfkctZnBnjW5yu5z1/3k3SehF7TyoTIe78rJs02GMMy+LF+A== - dependencies: - gaxios "^4.0.0" - json-bigint "^1.0.0" - - generate-function@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" - integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ== - dependencies: - is-property "^1.0.2" - - generic-pool@3.8.2: - version "3.8.2" - resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.8.2.tgz#aab4f280adb522fdfbdc5e5b64d718d3683f04e9" - integrity sha512-nGToKy6p3PAbYQ7p1UlWl6vSPwfwU6TMSWK7TTu+WUY4ZjyZQGniGGt2oNVvyNSpyZYSB43zMXVLcBm08MTMkg== - - gensync@^1.0.0-beta.2: - version "1.0.0-beta.2" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" - integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== - - get-caller-file@^2.0.1, get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - - get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== - dependencies: - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.1" - - get-nonce@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/get-nonce/-/get-nonce-1.0.1.tgz#fdf3f0278073820d2ce9426c18f07481b1e0cdf3" - integrity sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q== - - 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@3.0.0, get-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" - integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ= - - get-stream@^2.2.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-2.3.1.tgz#5f38f93f346009666ee0150a054167f91bdd95de" - integrity sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4= - dependencies: - object-assign "^4.0.1" - pinkie-promise "^2.0.0" - - get-stream@^4.0.0, get-stream@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - - get-stream@^5.0.0, get-stream@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" - integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== - dependencies: - pump "^3.0.0" - - get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - - get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" - - get-user-locale@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/get-user-locale/-/get-user-locale-1.4.0.tgz#a2c4b5da46feec9f03c9b07d197b1620490a5370" - integrity sha512-gQo03lP1OArHLKlnoglqrGGl7b04u2EP9Xutmp72cMdtrrSD7ZgIsCsUKZynYWLDkVJW33Cj3pliP7uP0UonHQ== - dependencies: - lodash.once "^4.1.1" - - get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= - - getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" - - gifwrap@^0.9.2: - version "0.9.3" - resolved "https://registry.yarnpkg.com/gifwrap/-/gifwrap-0.9.3.tgz#66d939219bb038d19745abf6024a8ab231786bdb" - integrity sha512-HSLpe3qhAdAoIBbwuTjKnxMGemj80uRpr55IhDv1Xf25h1E0SrKr8nIBFXysKUlYm8ZCkDhAuvX7/hRQnE9rLw== - dependencies: - image-q "^1.1.1" - omggif "^1.0.10" - - github-slugger@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/github-slugger/-/github-slugger-1.4.0.tgz#206eb96cdb22ee56fdc53a28d5a302338463444e" - integrity sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ== - - glob-parent@^5.1.2, glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - - glob-parent@^6.0.1, glob-parent@^6.0.2: - version "6.0.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" - integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== - dependencies: - is-glob "^4.0.3" - - glob@7.1.7: - version "7.1.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" - integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - - glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6, glob@^7.1.7: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - - global@~4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/global/-/global-4.4.0.tgz#3e7b105179006a323ed71aafca3e9c57a5cc6406" - integrity sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w== - dependencies: - min-document "^2.19.0" - process "^0.11.10" - - globals@^11.1.0: - version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" - integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== - - globals@^13.6.0, globals@^13.9.0: - version "13.13.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.13.0.tgz#ac32261060d8070e2719dd6998406e27d2b5727b" - integrity sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A== - dependencies: - type-fest "^0.20.2" - - globby@^11.0.4: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - - goober@^2.1.1: - version "2.1.8" - resolved "https://registry.yarnpkg.com/goober/-/goober-2.1.8.tgz#e592c04d093cb38f77b38cfcb012b7811c85765e" - integrity sha512-S0C85gCzcfFCMSdjD/CxyQMt1rbf2qEg6hmDzxk2FfD7+7Ogk55m8ZFUMtqNaZM4VVX/qaU9AzSORG+Gf4ZpAQ== - - google-auth-library@^7.0.2, google-auth-library@^7.14.0: - version "7.14.0" - resolved "https://registry.yarnpkg.com/google-auth-library/-/google-auth-library-7.14.0.tgz#9d6a20592f7b4d4c463cd3e93934c4b1711d5dc6" - integrity sha512-or8r7qUqGVI3W8lVSdPh0ZpeFyQHeE73g5c0p+bLNTTUFXJ+GSeDQmZRZ2p4H8cF/RJYa4PNvi/A1ar1uVNLFA== - dependencies: - arrify "^2.0.0" - base64-js "^1.3.0" - ecdsa-sig-formatter "^1.0.11" - fast-text-encoding "^1.0.0" - gaxios "^4.0.0" - gcp-metadata "^4.2.0" - gtoken "^5.0.4" - jws "^4.0.0" - lru-cache "^6.0.0" - - google-p12-pem@^3.1.3: - version "3.1.3" - resolved "https://registry.yarnpkg.com/google-p12-pem/-/google-p12-pem-3.1.3.tgz#5497998798ee86c2fc1f4bb1f92b7729baf37537" - integrity sha512-MC0jISvzymxePDVembypNefkAQp+DRP7dBE+zNUPaIjEspIlYg0++OrsNr248V9tPbz6iqtZ7rX1hxWA5B8qBQ== - dependencies: - node-forge "^1.0.0" - - googleapis-common@^5.0.2: - version "5.1.0" - resolved "https://registry.yarnpkg.com/googleapis-common/-/googleapis-common-5.1.0.tgz#845a79471c787e522e03c50d415467140e9e356a" - integrity sha512-RXrif+Gzhq1QAzfjxulbGvAY3FPj8zq/CYcvgjzDbaBNCD6bUl+86I7mUs4DKWHGruuK26ijjR/eDpWIDgNROA== - dependencies: - extend "^3.0.2" - gaxios "^4.0.0" - google-auth-library "^7.14.0" - qs "^6.7.0" - url-template "^2.0.8" - uuid "^8.0.0" - - googleapis@^84.0.0: - version "84.0.0" - resolved "https://registry.yarnpkg.com/googleapis/-/googleapis-84.0.0.tgz#55b534b234c2df1af0b0f33c0394f31ac23a20d0" - integrity sha512-5WWLwmraulw3p55lu0gNpLz2FME1gcuR7QxgmUdAVHMiVN4LEasYjJV9p36gxcf2TMe6bn6+PgQ/63+CvBEgoQ== - dependencies: - google-auth-library "^7.0.2" - googleapis-common "^5.0.2" - - got@9.6.0: - version "9.6.0" - resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" - integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== - dependencies: - "@sindresorhus/is" "^0.14.0" - "@szmarczak/http-timer" "^1.1.2" - cacheable-request "^6.0.0" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^4.1.0" - lowercase-keys "^1.0.1" - mimic-response "^1.0.1" - p-cancelable "^1.0.0" - to-readable-stream "^1.0.0" - url-parse-lax "^3.0.0" - - got@^7.1.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/got/-/got-7.1.0.tgz#05450fd84094e6bbea56f451a43a9c289166385a" - integrity sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw== - dependencies: - decompress-response "^3.2.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - is-plain-obj "^1.1.0" - is-retry-allowed "^1.0.0" - is-stream "^1.0.0" - isurl "^1.0.0-alpha5" - lowercase-keys "^1.0.0" - p-cancelable "^0.3.0" - p-timeout "^1.1.1" - safe-buffer "^5.0.1" - timed-out "^4.0.0" - url-parse-lax "^1.0.0" - url-to-options "^1.0.1" - - got@^8.3.1: - version "8.3.2" - resolved "https://registry.yarnpkg.com/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937" - integrity sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw== - dependencies: - "@sindresorhus/is" "^0.7.0" - cacheable-request "^2.1.1" - decompress-response "^3.3.0" - duplexer3 "^0.1.4" - get-stream "^3.0.0" - into-stream "^3.1.0" - is-retry-allowed "^1.1.0" - isurl "^1.0.0-alpha5" - lowercase-keys "^1.0.0" - mimic-response "^1.0.0" - p-cancelable "^0.4.0" - p-timeout "^2.0.1" - pify "^3.0.0" - safe-buffer "^5.1.1" - timed-out "^4.0.1" - url-parse-lax "^3.0.0" - url-to-options "^1.0.1" - - graceful-fs@^4.1.10, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: - version "4.2.9" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" - integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== - - grapheme-splitter@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" - integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== - - gray-matter@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/gray-matter/-/gray-matter-4.0.3.tgz#e893c064825de73ea1f5f7d88c7a9f7274288798" - integrity sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q== - dependencies: - js-yaml "^3.13.1" - kind-of "^6.0.2" - section-matter "^1.0.0" - strip-bom-string "^1.0.0" - - growly@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" - integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= - - gtoken@^5.0.4: - version "5.3.2" - resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-5.3.2.tgz#deb7dc876abe002178e0515e383382ea9446d58f" - integrity sha512-gkvEKREW7dXWF8NV8pVrKfW7WqReAmjjkMBh6lNCCGOM4ucS0r0YyXXl0r/9Yj8wcW/32ISkfc8h5mPTDbtifQ== - dependencies: - gaxios "^4.0.0" - google-p12-pem "^3.1.3" - jws "^4.0.0" - - gzip-size@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462" - integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q== - dependencies: - duplexer "^0.1.2" - - handlebars@^4.7.7: - version "4.7.7" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" - integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== - dependencies: - minimist "^1.2.5" - neo-async "^2.6.0" - source-map "^0.6.1" - wordwrap "^1.0.0" - optionalDependencies: - uglify-js "^3.1.4" - - har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= - - har-validator@~5.1.3: - version "5.1.5" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" - integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== - dependencies: - ajv "^6.12.3" - har-schema "^2.0.0" - - has-bigints@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" - integrity sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA== - - has-flag@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" - integrity sha1-6CB68cx7MNRGzHC3NLXovhj4jVE= - - has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - - has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - - has-symbol-support-x@^1.4.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz#1409f98bc00247da45da67cee0a36f282ff26455" - integrity sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw== - - has-symbols@^1.0.1, has-symbols@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - - has-to-string-tag-x@^1.2.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz#a045ab383d7b4b2012a00148ab0aa5f290044d4d" - integrity sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw== - dependencies: - has-symbol-support-x "^1.4.1" - - has-tostringtag@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.0.tgz#7e133818a7d394734f941e73c3d3f9291e658b25" - integrity sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ== - dependencies: - has-symbols "^1.0.2" - - has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - - has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - - has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= - - has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - - has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - - hash-base@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.1.0.tgz#55c381d9e06e1d2997a883b4a3fddfe7f0d3af33" - integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== - dependencies: - inherits "^2.0.4" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - - hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - - hast-util-is-element@^2.0.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/hast-util-is-element/-/hast-util-is-element-2.1.2.tgz#fc0b0dc7cef3895e839b8d66979d57b0338c68f3" - integrity sha512-thjnlGAnwP8ef/GSO1Q8BfVk2gundnc2peGQqEg2kUt/IqesiGg/5mSwN2fE7nLzy61pg88NG6xV+UrGOrx9EA== - dependencies: - "@types/hast" "^2.0.0" - "@types/unist" "^2.0.0" - - hast-util-sanitize@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/hast-util-sanitize/-/hast-util-sanitize-4.0.0.tgz#71a02ca2e50d04b852a5500846418070ca364f60" - integrity sha512-pw56+69jq+QSr/coADNvWTmBPDy+XsmwaF5KnUys4/wM1jt/fZdl7GPxhXXXYdXnz3Gj3qMkbUCH2uKjvX0MgQ== - dependencies: - "@types/hast" "^2.0.0" - - hast-util-to-estree@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/hast-util-to-estree/-/hast-util-to-estree-2.0.2.tgz#79c5bf588915610b3f0d47ca83a74dc0269c7dc2" - integrity sha512-UQrZVeBj6A9od0lpFvqHKNSH9zvDrNoyWKbveu1a2oSCXEDUI+3bnd6BoiQLPnLrcXXn/jzJ6y9hmJTTlvf8lQ== - dependencies: - "@types/estree-jsx" "^0.0.1" - "@types/hast" "^2.0.0" - "@types/unist" "^2.0.0" - comma-separated-tokens "^2.0.0" - estree-util-attach-comments "^2.0.0" - estree-util-is-identifier-name "^2.0.0" - hast-util-whitespace "^2.0.0" - mdast-util-mdx-expression "^1.0.0" - mdast-util-mdxjs-esm "^1.0.0" - property-information "^6.0.0" - space-separated-tokens "^2.0.0" - style-to-object "^0.3.0" - unist-util-position "^4.0.0" - zwitch "^2.0.0" - - hast-util-to-html@^8.0.0: - version "8.0.3" - resolved "https://registry.yarnpkg.com/hast-util-to-html/-/hast-util-to-html-8.0.3.tgz#4e37580872e143ea9ce0dba87918b19e4ea997e3" - integrity sha512-/D/E5ymdPYhHpPkuTHOUkSatxr4w1ZKrZsG0Zv/3C2SRVT0JFJG53VS45AMrBtYk0wp5A7ksEhiC8QaOZM95+A== - dependencies: - "@types/hast" "^2.0.0" - ccount "^2.0.0" - comma-separated-tokens "^2.0.0" - hast-util-is-element "^2.0.0" - hast-util-whitespace "^2.0.0" - html-void-elements "^2.0.0" - property-information "^6.0.0" - space-separated-tokens "^2.0.0" - stringify-entities "^4.0.2" - unist-util-is "^5.0.0" - - hast-util-whitespace@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-2.0.0.tgz#4fc1086467cc1ef5ba20673cb6b03cec3a970f1c" - integrity sha512-Pkw+xBHuV6xFeJprJe2BBEoDV+AvQySaz3pPDRUs5PNZEMQjpXJJueqrpcHIXxnWTcAGi/UOCgVShlkY6kLoqg== - - highlight.js@^10.7.1: - version "10.7.3" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" - integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== - - history@^4.9.0: - version "4.10.1" - resolved "https://registry.yarnpkg.com/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3" - integrity sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew== - dependencies: - "@babel/runtime" "^7.1.2" - loose-envify "^1.2.0" - resolve-pathname "^3.0.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - value-equal "^1.0.1" - - hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - - hoist-non-react-statics@^3.1.0, hoist-non-react-statics@^3.2.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45" - integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== - dependencies: - react-is "^16.7.0" - - hosted-git-info@^2.1.4: - version "2.8.9" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" - integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== - - html-encoding-sniffer@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" - integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== - dependencies: - whatwg-encoding "^1.0.5" - - html-escaper@^2.0.0, html-escaper@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" - integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== - - html-parse-stringify@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2" - integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg== - dependencies: - void-elements "3.1.0" - - html-void-elements@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/html-void-elements/-/html-void-elements-2.0.1.tgz#29459b8b05c200b6c5ee98743c41b979d577549f" - integrity sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A== - - http-cache-semantics@3.8.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" - integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== - - http-cache-semantics@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" - integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== - - http-errors@1.6.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.2.tgz#0a002cc85707192a7e7946ceedc11155f60ec736" - integrity sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY= - dependencies: - depd "1.1.1" - inherits "2.0.3" - setprototypeof "1.0.3" - statuses ">= 1.3.1 < 2" - - http-errors@1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" - integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== - dependencies: - depd "~1.1.2" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.1" - - http-https@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/http-https/-/http-https-1.0.0.tgz#2f908dd5f1db4068c058cd6e6d4ce392c913389b" - integrity sha1-L5CN1fHbQGjAWM1ubUzjkskTOJs= - - http-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - - http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - - https-proxy-agent@5.0.0, https-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" - integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== - dependencies: - agent-base "6" - debug "4" - - human-signals@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" - integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== - - human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== - - husky@^7.0.1, husky@^7.0.4: - version "7.0.4" - resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.4.tgz#242048245dc49c8fb1bf0cc7cfb98dd722531535" - integrity sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ== - - i18next-fs-backend@^1.0.7: - version "1.1.4" - resolved "https://registry.yarnpkg.com/i18next-fs-backend/-/i18next-fs-backend-1.1.4.tgz#d0e9b9ed2fa7a0f11002d82b9fa69c3c3d6482da" - integrity sha512-/MfAGMP0jHonV966uFf9PkWWuDjPYLIcsipnSO3NxpNtAgRUKLTwvm85fEmsF6hGeu0zbZiCQ3W74jwO6K9uXA== - - i18next@^20.1.0: - version "20.6.1" - resolved "https://registry.yarnpkg.com/i18next/-/i18next-20.6.1.tgz#535e5f6e5baeb685c7d25df70db63bf3cc0aa345" - integrity sha512-yCMYTMEJ9ihCwEQQ3phLo7I/Pwycf8uAx+sRHwwk5U9Aui/IZYgQRyMqXafQOw5QQ7DM1Z+WyEXWIqSuJHhG2A== - dependencies: - "@babel/runtime" "^7.12.0" - - ical.js@^1.4.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/ical.js/-/ical.js-1.5.0.tgz#23213accd1d8f7248d01705acb06270a70d20662" - integrity sha512-7ZxMkogUkkaCx810yp0ZGKvq1ZpRgJeornPttpoxe6nYZ3NLesZe1wWMXDdwTkj/b5NtXT+Y16Aakph/ao98ZQ== - - iconv-lite@0.4.19: - version "0.4.19" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" - integrity sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ== - - iconv-lite@0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - - iconv-lite@^0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" - integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - - ics@^2.31.0: - version "2.35.0" - resolved "https://registry.yarnpkg.com/ics/-/ics-2.35.0.tgz#9cf3d7bcc9526f78d838b119613adb2a3baf19b8" - integrity sha512-uxHoiu9VnE/1RUIWoUqn9GVswUzrejHFa5Gk20gGySw+2FO8xzgJe7GLFk+hzmevHViG/6zANLhjVY6kFWctKQ== - dependencies: - nanoid "^3.1.23" - yup "^0.32.9" - - idb-wrapper@^1.5.0: - version "1.7.2" - resolved "https://registry.yarnpkg.com/idb-wrapper/-/idb-wrapper-1.7.2.tgz#8251afd5e77fe95568b1c16152eb44b396767ea2" - integrity sha512-zfNREywMuf0NzDo9mVsL0yegjsirJxHpKHvWcyRozIqQy89g0a3U+oBPOCN4cc0oCiOuYgZHimzaW/R46G1Mpg== - - idna-uts46-hx@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/idna-uts46-hx/-/idna-uts46-hx-2.3.1.tgz#a1dc5c4df37eee522bf66d969cc980e00e8711f9" - integrity sha512-PWoF9Keq6laYdIRwwCdhTPl60xRqAloYNMQLiyUnG42VjT53oW07BXIRM+NK7eQjzXjAk2gUvX9caRxlnF9TAA== - dependencies: - punycode "2.1.0" - - ieee754@^1.1.13, ieee754@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - - iframe-resizer-react@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/iframe-resizer-react/-/iframe-resizer-react-1.1.0.tgz#5009e019b7a5c7f1c009bff5bcdf0dbf33557465" - integrity sha512-FrytSq91AIJaDgE+6uK/Vdd6IR8CrwLoZ6eGmL2qQMPTzF0xlSV2jaSzRRUh5V2fttD7vzl21jvBl97bV40eBw== - dependencies: - iframe-resizer "^4.3.0" - warning "^4.0.3" - - iframe-resizer@^4.3.0: - version "4.3.2" - resolved "https://registry.yarnpkg.com/iframe-resizer/-/iframe-resizer-4.3.2.tgz#42dd88345d18b9e377b6044dddb98c664ab0ce6b" - integrity sha512-gOWo2hmdPjMQsQ+zTKbses08mDfDEMh4NneGQNP4qwePYujY1lguqP6gnbeJkf154gojWlBhIltlgnMfYjGHWA== - - ignore@^5.1.8, ignore@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" - integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== - - image-q@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/image-q/-/image-q-1.1.1.tgz#fc84099664460b90ca862d9300b6bfbbbfbf8056" - integrity sha1-/IQJlmRGC5DKhi2TALa/u7+/gFY= - - import-fresh@^3.0.0, import-fresh@^3.1.0, import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - - import-local@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" - integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== - dependencies: - pkg-dir "^4.2.0" - resolve-cwd "^3.0.0" - - imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= - - indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== - - indexof@~0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" - integrity sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10= - - inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - - inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - - inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - - inline-style-parser@0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1" - integrity sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q== - - input-format@^0.3.7: - version "0.3.7" - resolved "https://registry.yarnpkg.com/input-format/-/input-format-0.3.7.tgz#08d63fc629985d604d1910e1d1a220b7a521bdc3" - integrity sha512-hgwiCjV7MnhFvX4Hwrvk7hB2a2rcB2CQb7Ex7GlK1ISbEXuLtflwBUnadFSA1rVNDPFh9yWBaJJ4/o1XkzhPIg== - dependencies: - prop-types "^15.7.2" - - internal-slot@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.3.tgz#7347e307deeea2faac2ac6205d4bc7d34967f59c" - integrity sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA== - dependencies: - get-intrinsic "^1.1.0" - has "^1.0.3" - side-channel "^1.0.4" - - intersection-observer@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.12.0.tgz#6c84628f67ce8698e5f9ccf857d97718745837aa" - integrity sha512-2Vkz8z46Dv401zTWudDGwO7KiGHNDkMv417T5ItcNYfmvHR/1qCTVBO9vwH8zZmQ0WkA/1ARwpysR9bsnop4NQ== - - intl-messageformat@9.11.4: - version "9.11.4" - resolved "https://registry.yarnpkg.com/intl-messageformat/-/intl-messageformat-9.11.4.tgz#0f9030bc6d10e6a48592142f88e646d88f05f1f2" - integrity sha512-77TSkNubIy/hsapz6LQpyR6OADcxhWdhSaboPb5flMaALCVkPvAIxr48AlPqaMl4r1anNcvR9rpLWVdwUY1IKg== - dependencies: - "@formatjs/ecma402-abstract" "1.11.3" - "@formatjs/fast-memoize" "1.2.1" - "@formatjs/icu-messageformat-parser" "2.0.18" - tslib "^2.1.0" - - into-stream@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/into-stream/-/into-stream-3.1.0.tgz#96fb0a936c12babd6ff1752a17d05616abd094c6" - integrity sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY= - dependencies: - from2 "^2.1.1" - p-is-promise "^1.1.0" - - invariant@^2.2.4: - version "2.2.4" - resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - - ip@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" - integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= - - ipaddr.js@1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== - - ipaddr.js@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.0.1.tgz#eca256a7a877e917aeb368b0a7497ddf42ef81c0" - integrity sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng== - - is-accessor-descriptor@^0.1.6: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" - integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= - dependencies: - kind-of "^3.0.2" - - is-accessor-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" - integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== - dependencies: - kind-of "^6.0.0" - - is-alphabetical@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" - integrity sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg== - - is-alphabetical@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-2.0.1.tgz#01072053ea7c1036df3c7d19a6daaec7f19e789b" - integrity sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ== - - is-alphanumerical@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz#7eb9a2431f855f6b1ef1a78e326df515696c4dbf" - integrity sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A== - dependencies: - is-alphabetical "^1.0.0" - is-decimal "^1.0.0" - - is-alphanumerical@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz#7c03fbe96e3e931113e57f964b0a368cc2dfd875" - integrity sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw== - dependencies: - is-alphabetical "^2.0.0" - is-decimal "^2.0.0" - - is-arguments@^1.0.4: - version "1.1.1" - resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" - integrity sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - - is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= - - is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== - dependencies: - has-bigints "^1.0.1" - - is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - - is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - - is-buffer@^1.1.5: - version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" - integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== - - is-buffer@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.5.tgz#ebc252e400d22ff8d77fa09888821a24a658c191" - integrity sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ== - - is-callable@^1.1.4, is-callable@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.4.tgz#47301d58dd0259407865547853df6d61fe471945" - integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== - - is-ci@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" - integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== - dependencies: - ci-info "^2.0.0" - - is-core-module@^2.2.0, is-core-module@^2.8.0, is-core-module@^2.8.1: - version "2.8.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.8.1.tgz#f59fdfca701d5879d0a6b100a40aa1560ce27211" - integrity sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA== - dependencies: - has "^1.0.3" - - is-data-descriptor@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" - integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= - dependencies: - kind-of "^3.0.2" - - is-data-descriptor@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" - integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== - dependencies: - kind-of "^6.0.0" - - is-date-object@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== - dependencies: - has-tostringtag "^1.0.0" - - is-decimal@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-1.0.4.tgz#65a3a5958a1c5b63a706e1b333d7cd9f630d3fa5" - integrity sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw== - - is-decimal@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-decimal/-/is-decimal-2.0.1.tgz#9469d2dc190d0214fd87d78b78caecc0cc14eef7" - integrity sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A== - - is-descriptor@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" - integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== - dependencies: - is-accessor-descriptor "^0.1.6" - is-data-descriptor "^0.1.4" - kind-of "^5.0.0" - - is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" - integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== - dependencies: - is-accessor-descriptor "^1.0.0" - is-data-descriptor "^1.0.0" - kind-of "^6.0.2" - - is-docker@^2.0.0, is-docker@^2.1.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" - integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== - - is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= - - is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - - is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= - - is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - - is-fullwidth-code-point@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" - integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== - - is-function@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.2.tgz#4f097f30abf6efadac9833b17ca5dc03f8144e08" - integrity sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ== - - is-generator-fn@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" - integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== - - is-generator-function@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" - integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== - dependencies: - has-tostringtag "^1.0.0" - - is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - - is-hex-prefixed@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz#7d8d37e6ad77e5d127148913c573e082d777f554" - integrity sha1-fY035q135dEnFIkTxXPggtd39VQ= - - is-hexadecimal@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" - integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== - - is-hexadecimal@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz#86b5bf668fca307498d319dfc03289d781a90027" - integrity sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg== - - is-natural-number@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-natural-number/-/is-natural-number-4.0.1.tgz#ab9d76e1db4ced51e35de0c72ebecf09f734cde8" - integrity sha1-q5124dtM7VHjXeDHLr7PCfc0zeg= - - is-negative-zero@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== - - is-number-object@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.6.tgz#6a7aaf838c7f0686a50b4553f7e54a96494e89f0" - integrity sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g== - dependencies: - has-tostringtag "^1.0.0" - - is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= - dependencies: - kind-of "^3.0.2" - - is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - - is-object@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf" - integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA== - - is-object@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/is-object/-/is-object-0.1.2.tgz#00efbc08816c33cfc4ac8251d132e10dc65098d7" - integrity sha1-AO+8CIFsM8/ErIJR0TLhDcZQmNc= - - is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= - - is-plain-obj@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" - integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== - - is-plain-obj@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.0.0.tgz#06c0999fd7574edf5a906ba5644ad0feb3a84d22" - integrity sha512-NXRbBtUdBioI73y/HmOhogw/U5msYPC9DAtGkJXeFcFWSFZw0mCUsPxk/snTuJHzNKA8kLBK4rH97RMB1BfCXw== - - is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - - is-potential-custom-element-name@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" - integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== - - is-property@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - integrity sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ= - - is-reference@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-3.0.0.tgz#b1380c03d96ddf7089709781e3208fceb0c92cd6" - integrity sha512-Eo1W3wUoHWoCoVM4GVl/a+K0IgiqE5aIo4kJABFyMum1ZORlPkC+UC357sSQUL5w5QCE5kCC9upl75b7+7CY/Q== - dependencies: - "@types/estree" "*" - - is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - - is-retry-allowed@^1.0.0, is-retry-allowed@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4" - integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg== - - is-shared-array-buffer@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz#97b0c85fbdacb59c9c446fe653b82cf2b5b7cfe6" - integrity sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA== - - is-stream@1.1.0, is-stream@^1.0.0, is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= - - 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-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - - is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - - is-typed-array@^1.1.3, is-typed-array@^1.1.7: - version "1.1.8" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.8.tgz#cbaa6585dc7db43318bc5b89523ea384a6f65e79" - integrity sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-abstract "^1.18.5" - foreach "^2.0.5" - has-tostringtag "^1.0.0" - - is-typedarray@^1.0.0, is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - - is-weakref@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== - dependencies: - call-bind "^1.0.2" - - is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - - is-wsl@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== - dependencies: - is-docker "^2.0.0" - - is@~0.2.6: - version "0.2.7" - resolved "https://registry.yarnpkg.com/is/-/is-0.2.7.tgz#3b34a2c48f359972f35042849193ae7264b63562" - integrity sha1-OzSixI81mXLzUEKEkZOucmS2NWI= - - isarray@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= - - isarray@1.0.0, isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" - integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= - - isbuffer@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/isbuffer/-/isbuffer-0.0.0.tgz#38c146d9df528b8bf9b0701c3d43cf12df3fc39b" - integrity sha1-OMFG2d9Si4v5sHAcPUPPEt8/w5s= - - isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - - isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= - dependencies: - isarray "1.0.0" - - isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= - - isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - - istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" - integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== - - istanbul-lib-instrument@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" - integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== - dependencies: - "@babel/core" "^7.7.5" - "@istanbuljs/schema" "^0.1.2" - istanbul-lib-coverage "^3.0.0" - semver "^6.3.0" - - istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz#7b49198b657b27a730b8e9cb601f1e1bff24c59a" - integrity sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q== - 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.0.2, istanbul-reports@^3.1.3: - version "3.1.4" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.4.tgz#1b6f068ecbc6c331040aab5741991273e609e40c" - integrity sha512-r1/DshN4KSE7xWEknZLLLLDn5CJybV3nw01VTkp6D5jzLuELlcbudfj/eSQFvrKsJuTVCGnePO7ho82Nw9zzfw== - dependencies: - html-escaper "^2.0.0" - istanbul-lib-report "^3.0.0" - - isurl@^1.0.0-alpha5: - version "1.0.0" - resolved "https://registry.yarnpkg.com/isurl/-/isurl-1.0.0.tgz#b27f4f49f3cdaa3ea44a0a5b7f3462e6edc39d67" - integrity sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w== - dependencies: - has-to-string-tag-x "^1.2.0" - is-object "^1.0.1" - - javascript-natural-sort@0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz#f9e2303d4507f6d74355a73664d1440fb5a0ef59" - integrity sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k= - - jest-changed-files@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.6.2.tgz#f6198479e1cc66f22f9ae1e22acaa0b429c042d0" - integrity sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ== - dependencies: - "@jest/types" "^26.6.2" - execa "^4.0.0" - throat "^5.0.0" - - jest-changed-files@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.5.1.tgz#a348aed00ec9bf671cc58a66fcbe7c3dfd6a68f5" - integrity sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw== - dependencies: - "@jest/types" "^27.5.1" - execa "^5.0.0" - throat "^6.0.1" - - jest-circus@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.5.1.tgz#37a5a4459b7bf4406e53d637b49d22c65d125ecc" - integrity sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - dedent "^0.7.0" - expect "^27.5.1" - is-generator-fn "^2.0.0" - jest-each "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" - jest-runtime "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" - pretty-format "^27.5.1" - slash "^3.0.0" - stack-utils "^2.0.3" - throat "^6.0.1" - - jest-cli@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.6.3.tgz#43117cfef24bc4cd691a174a8796a532e135e92a" - integrity sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg== - dependencies: - "@jest/core" "^26.6.3" - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" - chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.4" - import-local "^3.0.2" - is-ci "^2.0.0" - jest-config "^26.6.3" - jest-util "^26.6.2" - jest-validate "^26.6.2" - prompts "^2.0.1" - yargs "^15.4.1" - - jest-cli@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.5.1.tgz#278794a6e6458ea8029547e6c6cbf673bd30b145" - integrity sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw== - dependencies: - "@jest/core" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" - chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.9" - import-local "^3.0.2" - jest-config "^27.5.1" - jest-util "^27.5.1" - jest-validate "^27.5.1" - prompts "^2.0.1" - yargs "^16.2.0" - - jest-config@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.6.3.tgz#64f41444eef9eb03dc51d5c53b75c8c71f645349" - integrity sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg== - dependencies: - "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^26.6.3" - "@jest/types" "^26.6.2" - babel-jest "^26.6.3" - chalk "^4.0.0" - deepmerge "^4.2.2" - glob "^7.1.1" - graceful-fs "^4.2.4" - jest-environment-jsdom "^26.6.2" - jest-environment-node "^26.6.2" - jest-get-type "^26.3.0" - jest-jasmine2 "^26.6.3" - jest-regex-util "^26.0.0" - jest-resolve "^26.6.2" - jest-util "^26.6.2" - jest-validate "^26.6.2" - micromatch "^4.0.2" - pretty-format "^26.6.2" - - jest-config@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.5.1.tgz#5c387de33dca3f99ad6357ddeccd91bf3a0e4a41" - integrity sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA== - dependencies: - "@babel/core" "^7.8.0" - "@jest/test-sequencer" "^27.5.1" - "@jest/types" "^27.5.1" - babel-jest "^27.5.1" - chalk "^4.0.0" - ci-info "^3.2.0" - deepmerge "^4.2.2" - glob "^7.1.1" - graceful-fs "^4.2.9" - jest-circus "^27.5.1" - jest-environment-jsdom "^27.5.1" - jest-environment-node "^27.5.1" - jest-get-type "^27.5.1" - jest-jasmine2 "^27.5.1" - jest-regex-util "^27.5.1" - jest-resolve "^27.5.1" - jest-runner "^27.5.1" - jest-util "^27.5.1" - jest-validate "^27.5.1" - micromatch "^4.0.4" - parse-json "^5.2.0" - pretty-format "^27.5.1" - slash "^3.0.0" - strip-json-comments "^3.1.1" - - jest-diff@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" - integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== - dependencies: - chalk "^4.0.0" - diff-sequences "^26.6.2" - jest-get-type "^26.3.0" - pretty-format "^26.6.2" - - jest-diff@^27.2.5, jest-diff@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def" - integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw== - dependencies: - chalk "^4.0.0" - diff-sequences "^27.5.1" - jest-get-type "^27.5.1" - pretty-format "^27.5.1" - - jest-docblock@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" - integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w== - dependencies: - detect-newline "^3.0.0" - - jest-docblock@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.5.1.tgz#14092f364a42c6108d42c33c8cf30e058e25f6c0" - integrity sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ== - dependencies: - detect-newline "^3.0.0" - - jest-each@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.6.2.tgz#02526438a77a67401c8a6382dfe5999952c167cb" - integrity sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A== - dependencies: - "@jest/types" "^26.6.2" - chalk "^4.0.0" - jest-get-type "^26.3.0" - jest-util "^26.6.2" - pretty-format "^26.6.2" - - jest-each@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.5.1.tgz#5bc87016f45ed9507fed6e4702a5b468a5b2c44e" - integrity sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ== - dependencies: - "@jest/types" "^27.5.1" - chalk "^4.0.0" - jest-get-type "^27.5.1" - jest-util "^27.5.1" - pretty-format "^27.5.1" - - jest-environment-jsdom@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz#78d09fe9cf019a357009b9b7e1f101d23bd1da3e" - integrity sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q== - dependencies: - "@jest/environment" "^26.6.2" - "@jest/fake-timers" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - jest-mock "^26.6.2" - jest-util "^26.6.2" - jsdom "^16.4.0" - - jest-environment-jsdom@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz#ea9ccd1fc610209655a77898f86b2b559516a546" - integrity sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/fake-timers" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - jest-mock "^27.5.1" - jest-util "^27.5.1" - jsdom "^16.6.0" - - jest-environment-node@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.6.2.tgz#824e4c7fb4944646356f11ac75b229b0035f2b0c" - integrity sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag== - dependencies: - "@jest/environment" "^26.6.2" - "@jest/fake-timers" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - jest-mock "^26.6.2" - jest-util "^26.6.2" - - jest-environment-node@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.5.1.tgz#dedc2cfe52fab6b8f5714b4808aefa85357a365e" - integrity sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/fake-timers" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - jest-mock "^27.5.1" - jest-util "^27.5.1" - - jest-get-type@^26.3.0: - version "26.3.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" - integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== - - jest-get-type@^27.0.6, jest-get-type@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" - integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== - - jest-haste-map@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" - integrity sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w== - dependencies: - "@jest/types" "^26.6.2" - "@types/graceful-fs" "^4.1.2" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.4" - jest-regex-util "^26.0.0" - jest-serializer "^26.6.2" - jest-util "^26.6.2" - jest-worker "^26.6.2" - micromatch "^4.0.2" - sane "^4.0.3" - walker "^1.0.7" - optionalDependencies: - fsevents "^2.1.2" - - jest-haste-map@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.1.tgz#9fd8bd7e7b4fa502d9c6164c5640512b4e811e7f" - integrity sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng== - dependencies: - "@jest/types" "^27.5.1" - "@types/graceful-fs" "^4.1.2" - "@types/node" "*" - anymatch "^3.0.3" - fb-watchman "^2.0.0" - graceful-fs "^4.2.9" - jest-regex-util "^27.5.1" - jest-serializer "^27.5.1" - jest-util "^27.5.1" - jest-worker "^27.5.1" - micromatch "^4.0.4" - walker "^1.0.7" - optionalDependencies: - fsevents "^2.3.2" - - jest-jasmine2@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz#adc3cf915deacb5212c93b9f3547cd12958f2edd" - integrity sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg== - dependencies: - "@babel/traverse" "^7.1.0" - "@jest/environment" "^26.6.2" - "@jest/source-map" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - expect "^26.6.2" - is-generator-fn "^2.0.0" - jest-each "^26.6.2" - jest-matcher-utils "^26.6.2" - jest-message-util "^26.6.2" - jest-runtime "^26.6.3" - jest-snapshot "^26.6.2" - jest-util "^26.6.2" - pretty-format "^26.6.2" - throat "^5.0.0" - - jest-jasmine2@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz#a037b0034ef49a9f3d71c4375a796f3b230d1ac4" - integrity sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/source-map" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - expect "^27.5.1" - is-generator-fn "^2.0.0" - jest-each "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" - jest-runtime "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" - pretty-format "^27.5.1" - throat "^6.0.1" - - jest-leak-detector@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz#7717cf118b92238f2eba65054c8a0c9c653a91af" - integrity sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg== - dependencies: - jest-get-type "^26.3.0" - pretty-format "^26.6.2" - - jest-leak-detector@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz#6ec9d54c3579dd6e3e66d70e3498adf80fde3fb8" - integrity sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ== - dependencies: - jest-get-type "^27.5.1" - pretty-format "^27.5.1" - - jest-matcher-utils@27.2.5: - version "27.2.5" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.2.5.tgz#4684faaa8eb32bf15e6edaead6834031897e2980" - integrity sha512-qNR/kh6bz0Dyv3m68Ck2g1fLW5KlSOUNcFQh87VXHZwWc/gY6XwnKofx76Qytz3x5LDWT09/2+yXndTkaG4aWg== - dependencies: - chalk "^4.0.0" - jest-diff "^27.2.5" - jest-get-type "^27.0.6" - pretty-format "^27.2.5" - - jest-matcher-utils@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz#8e6fd6e863c8b2d31ac6472eeb237bc595e53e7a" - integrity sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw== - dependencies: - chalk "^4.0.0" - jest-diff "^26.6.2" - jest-get-type "^26.3.0" - pretty-format "^26.6.2" - - jest-matcher-utils@^27.0.0, jest-matcher-utils@^27.2.5, jest-matcher-utils@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab" - integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw== - dependencies: - chalk "^4.0.0" - jest-diff "^27.5.1" - jest-get-type "^27.5.1" - pretty-format "^27.5.1" - - jest-message-util@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07" - integrity sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA== - dependencies: - "@babel/code-frame" "^7.0.0" - "@jest/types" "^26.6.2" - "@types/stack-utils" "^2.0.0" - chalk "^4.0.0" - graceful-fs "^4.2.4" - micromatch "^4.0.2" - pretty-format "^26.6.2" - slash "^3.0.0" - stack-utils "^2.0.2" - - jest-message-util@^27.2.5, jest-message-util@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf" - integrity sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g== - dependencies: - "@babel/code-frame" "^7.12.13" - "@jest/types" "^27.5.1" - "@types/stack-utils" "^2.0.0" - chalk "^4.0.0" - graceful-fs "^4.2.9" - micromatch "^4.0.4" - pretty-format "^27.5.1" - slash "^3.0.0" - stack-utils "^2.0.3" - - jest-mock@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.6.2.tgz#d6cb712b041ed47fe0d9b6fc3474bc6543feb302" - integrity sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew== - dependencies: - "@jest/types" "^26.6.2" - "@types/node" "*" - - jest-mock@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.5.1.tgz#19948336d49ef4d9c52021d34ac7b5f36ff967d6" - integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og== - dependencies: - "@jest/types" "^27.5.1" - "@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@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" - integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== - - jest-regex-util@^27.0.6, jest-regex-util@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95" - integrity sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg== - - jest-resolve-dependencies@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz#6680859ee5d22ee5dcd961fe4871f59f4c784fb6" - integrity sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg== - dependencies: - "@jest/types" "^26.6.2" - jest-regex-util "^26.0.0" - jest-snapshot "^26.6.2" - - jest-resolve-dependencies@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz#d811ecc8305e731cc86dd79741ee98fed06f1da8" - integrity sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg== - dependencies: - "@jest/types" "^27.5.1" - jest-regex-util "^27.5.1" - jest-snapshot "^27.5.1" - - jest-resolve@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.6.2.tgz#a3ab1517217f469b504f1b56603c5bb541fbb507" - integrity sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ== - dependencies: - "@jest/types" "^26.6.2" - chalk "^4.0.0" - graceful-fs "^4.2.4" - jest-pnp-resolver "^1.2.2" - jest-util "^26.6.2" - read-pkg-up "^7.0.1" - resolve "^1.18.1" - slash "^3.0.0" - - jest-resolve@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.5.1.tgz#a2f1c5a0796ec18fe9eb1536ac3814c23617b384" - integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw== - dependencies: - "@jest/types" "^27.5.1" - chalk "^4.0.0" - graceful-fs "^4.2.9" - jest-haste-map "^27.5.1" - jest-pnp-resolver "^1.2.2" - jest-util "^27.5.1" - jest-validate "^27.5.1" - resolve "^1.20.0" - resolve.exports "^1.1.0" - slash "^3.0.0" - - jest-runner@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.6.3.tgz#2d1fed3d46e10f233fd1dbd3bfaa3fe8924be159" - integrity sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ== - dependencies: - "@jest/console" "^26.6.2" - "@jest/environment" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - chalk "^4.0.0" - emittery "^0.7.1" - exit "^0.1.2" - graceful-fs "^4.2.4" - jest-config "^26.6.3" - jest-docblock "^26.0.0" - jest-haste-map "^26.6.2" - jest-leak-detector "^26.6.2" - jest-message-util "^26.6.2" - jest-resolve "^26.6.2" - jest-runtime "^26.6.3" - jest-util "^26.6.2" - jest-worker "^26.6.2" - source-map-support "^0.5.6" - throat "^5.0.0" - - jest-runner@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.5.1.tgz#071b27c1fa30d90540805c5645a0ec167c7b62e5" - integrity sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ== - dependencies: - "@jest/console" "^27.5.1" - "@jest/environment" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - emittery "^0.8.1" - graceful-fs "^4.2.9" - jest-docblock "^27.5.1" - jest-environment-jsdom "^27.5.1" - jest-environment-node "^27.5.1" - jest-haste-map "^27.5.1" - jest-leak-detector "^27.5.1" - jest-message-util "^27.5.1" - jest-resolve "^27.5.1" - jest-runtime "^27.5.1" - jest-util "^27.5.1" - jest-worker "^27.5.1" - source-map-support "^0.5.6" - throat "^6.0.1" - - jest-runtime@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.6.3.tgz#4f64efbcfac398331b74b4b3c82d27d401b8fa2b" - integrity sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw== - dependencies: - "@jest/console" "^26.6.2" - "@jest/environment" "^26.6.2" - "@jest/fake-timers" "^26.6.2" - "@jest/globals" "^26.6.2" - "@jest/source-map" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/yargs" "^15.0.0" - chalk "^4.0.0" - cjs-module-lexer "^0.6.0" - collect-v8-coverage "^1.0.0" - exit "^0.1.2" - glob "^7.1.3" - graceful-fs "^4.2.4" - jest-config "^26.6.3" - jest-haste-map "^26.6.2" - jest-message-util "^26.6.2" - jest-mock "^26.6.2" - jest-regex-util "^26.0.0" - jest-resolve "^26.6.2" - jest-snapshot "^26.6.2" - jest-util "^26.6.2" - jest-validate "^26.6.2" - slash "^3.0.0" - strip-bom "^4.0.0" - yargs "^15.4.1" - - jest-runtime@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.5.1.tgz#4896003d7a334f7e8e4a53ba93fb9bcd3db0a1af" - integrity sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/fake-timers" "^27.5.1" - "@jest/globals" "^27.5.1" - "@jest/source-map" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - 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 "^27.5.1" - jest-message-util "^27.5.1" - jest-mock "^27.5.1" - jest-regex-util "^27.5.1" - jest-resolve "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" - slash "^3.0.0" - strip-bom "^4.0.0" - - jest-serializer@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" - integrity sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g== - dependencies: - "@types/node" "*" - graceful-fs "^4.2.4" - - jest-serializer@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.1.tgz#81438410a30ea66fd57ff730835123dea1fb1f64" - integrity sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w== - dependencies: - "@types/node" "*" - graceful-fs "^4.2.9" - - jest-snapshot@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.6.2.tgz#f3b0af1acb223316850bd14e1beea9837fb39c84" - integrity sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og== - dependencies: - "@babel/types" "^7.0.0" - "@jest/types" "^26.6.2" - "@types/babel__traverse" "^7.0.4" - "@types/prettier" "^2.0.0" - chalk "^4.0.0" - expect "^26.6.2" - graceful-fs "^4.2.4" - jest-diff "^26.6.2" - jest-get-type "^26.3.0" - jest-haste-map "^26.6.2" - jest-matcher-utils "^26.6.2" - jest-message-util "^26.6.2" - jest-resolve "^26.6.2" - natural-compare "^1.4.0" - pretty-format "^26.6.2" - semver "^7.3.2" - - jest-snapshot@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.5.1.tgz#b668d50d23d38054a51b42c4039cab59ae6eb6a1" - integrity sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA== - dependencies: - "@babel/core" "^7.7.2" - "@babel/generator" "^7.7.2" - "@babel/plugin-syntax-typescript" "^7.7.2" - "@babel/traverse" "^7.7.2" - "@babel/types" "^7.0.0" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/babel__traverse" "^7.0.4" - "@types/prettier" "^2.1.5" - babel-preset-current-node-syntax "^1.0.0" - chalk "^4.0.0" - expect "^27.5.1" - graceful-fs "^4.2.9" - jest-diff "^27.5.1" - jest-get-type "^27.5.1" - jest-haste-map "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" - jest-util "^27.5.1" - natural-compare "^1.4.0" - pretty-format "^27.5.1" - semver "^7.3.2" - - jest-util@^26.1.0, jest-util@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" - integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== - dependencies: - "@jest/types" "^26.6.2" - "@types/node" "*" - chalk "^4.0.0" - graceful-fs "^4.2.4" - is-ci "^2.0.0" - micromatch "^4.0.2" - - jest-util@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9" - integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw== - dependencies: - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - ci-info "^3.2.0" - graceful-fs "^4.2.9" - picomatch "^2.2.3" - - jest-validate@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec" - integrity sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ== - dependencies: - "@jest/types" "^26.6.2" - camelcase "^6.0.0" - chalk "^4.0.0" - jest-get-type "^26.3.0" - leven "^3.1.0" - pretty-format "^26.6.2" - - jest-validate@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.5.1.tgz#9197d54dc0bdb52260b8db40b46ae668e04df067" - integrity sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ== - dependencies: - "@jest/types" "^27.5.1" - camelcase "^6.2.0" - chalk "^4.0.0" - jest-get-type "^27.5.1" - leven "^3.1.0" - pretty-format "^27.5.1" - - jest-watcher@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.6.2.tgz#a5b683b8f9d68dbcb1d7dae32172d2cca0592975" - integrity sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ== - dependencies: - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - jest-util "^26.6.2" - string-length "^4.0.1" - - jest-watcher@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.5.1.tgz#71bd85fb9bde3a2c2ec4dc353437971c43c642a2" - integrity sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw== - dependencies: - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - ansi-escapes "^4.2.1" - chalk "^4.0.0" - jest-util "^27.5.1" - string-length "^4.0.1" - - jest-worker@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" - integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^7.0.0" - - jest-worker@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" - integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^8.0.0" - - jest@^26.0.0: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef" - integrity sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q== - dependencies: - "@jest/core" "^26.6.3" - import-local "^3.0.2" - jest-cli "^26.6.3" - - jest@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest/-/jest-27.5.1.tgz#dadf33ba70a779be7a6fc33015843b51494f63fc" - integrity sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ== - dependencies: - "@jest/core" "^27.5.1" - import-local "^3.0.2" - jest-cli "^27.5.1" - - jimp@^0.16.1: - version "0.16.1" - resolved "https://registry.yarnpkg.com/jimp/-/jimp-0.16.1.tgz#192f851a30e5ca11112a3d0aa53137659a78ca7a" - integrity sha512-+EKVxbR36Td7Hfd23wKGIeEyHbxShZDX6L8uJkgVW3ESA9GiTEPK08tG1XI2r/0w5Ch0HyJF5kPqF9K7EmGjaw== - dependencies: - "@babel/runtime" "^7.7.2" - "@jimp/custom" "^0.16.1" - "@jimp/plugins" "^0.16.1" - "@jimp/types" "^0.16.1" - regenerator-runtime "^0.13.3" - - jose@^4.1.4, jose@^4.3.7: - version "4.6.0" - resolved "https://registry.yarnpkg.com/jose/-/jose-4.6.0.tgz#f3ff007ddcbce462c091d3d41b7af2e35dec348c" - integrity sha512-0hNAkhMBNi4soKSAX4zYOFV+aqJlEz/4j4fregvasJzEVtjDChvWqRjPvHwLqr5hx28Ayr6bsOs1Kuj87V0O8w== - - jpeg-js@0.4.2: - version "0.4.2" - resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.2.tgz#8b345b1ae4abde64c2da2fe67ea216a114ac279d" - integrity sha512-+az2gi/hvex7eLTMTlbRLOhH6P6WFdk2ITI8HJsaH2VqYO0I594zXSYEP+tf4FW+8Cy68ScDXoAsQdyQanv3sw== - - jpeg-js@0.4.3: - version "0.4.3" - resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.3.tgz#6158e09f1983ad773813704be80680550eff977b" - integrity sha512-ru1HWKek8octvUHFHvE5ZzQ1yAsJmIvRdGWvSoKV52XKyuyYA437QWDttXT8eZXDSbuMpHlLzPDZUPd6idIz+Q== - - js-sha3@0.8.0, js-sha3@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" - integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== - - js-sha3@^0.5.7: - version "0.5.7" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.5.7.tgz#0d4ffd8002d5333aabaf4a23eed2f6374c9f28e7" - integrity sha1-DU/9gALVMzqrr0oj7tL2N0yfKOc= - - "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - - js-yaml@^3.13.1: - 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.0.0, js-yaml@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - - jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - - jsdom@^16.4.0, jsdom@^16.6.0: - version "16.7.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" - integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== - dependencies: - abab "^2.0.5" - acorn "^8.2.4" - acorn-globals "^6.0.0" - cssom "^0.4.4" - cssstyle "^2.3.0" - data-urls "^2.0.0" - decimal.js "^10.2.1" - domexception "^2.0.1" - escodegen "^2.0.0" - form-data "^3.0.0" - html-encoding-sniffer "^2.0.1" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - is-potential-custom-element-name "^1.0.1" - nwsapi "^2.2.0" - parse5 "6.0.1" - saxes "^5.0.1" - symbol-tree "^3.2.4" - tough-cookie "^4.0.0" - w3c-hr-time "^1.0.2" - w3c-xmlserializer "^2.0.0" - webidl-conversions "^6.1.0" - whatwg-encoding "^1.0.5" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.5.0" - ws "^7.4.6" - xml-name-validator "^3.0.0" - - jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - - jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= - - json-bigint@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/json-bigint/-/json-bigint-1.0.0.tgz#ae547823ac0cad8398667f8cd9ef4730f5b01ff1" - integrity sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ== - dependencies: - bignumber.js "^9.0.0" - - json-buffer@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" - integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= - - json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== - - json-parse-even-better-errors@^2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" - integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== - - json-rpc-engine@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/json-rpc-engine/-/json-rpc-engine-6.1.0.tgz#bf5ff7d029e1c1bf20cb6c0e9f348dcd8be5a393" - integrity sha512-NEdLrtrq1jUZyfjkr9OCz9EzCNhnRyWtt1PAnvnhwy6e8XETS0Dtc+ZNCO2gvuAoKsIn2+vCSowXTYE4CkgnAQ== - dependencies: - "@metamask/safe-event-emitter" "^2.0.0" - eth-rpc-errors "^4.0.2" - - json-rpc-middleware-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/json-rpc-middleware-stream/-/json-rpc-middleware-stream-3.0.0.tgz#8540331d884f36b9e0ad31054cc68ac6b5a89b52" - integrity sha512-JmZmlehE0xF3swwORpLHny/GvW3MZxCsb2uFNBrn8TOqMqivzCfz232NSDLLOtIQlrPlgyEjiYpyzyOPFOzClw== - dependencies: - "@metamask/safe-event-emitter" "^2.0.0" - readable-stream "^2.3.3" - - json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - - json-schema@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" - integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== - - json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" - integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE= - - json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - - json5@2.2.0, json5@2.x, json5@^2.1.2: - version "2.2.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3" - integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA== - dependencies: - minimist "^1.2.5" - - json5@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" - integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE= - - json5@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" - integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== - dependencies: - minimist "^1.2.0" - - jsonfile@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" - integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= - optionalDependencies: - graceful-fs "^4.1.6" - - jsonfile@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-5.0.0.tgz#e6b718f73da420d612823996fdf14a03f6ff6922" - integrity sha512-NQRZ5CRo74MhMMC3/3r5g2k4fjodJ/wh8MxjFbCViWKFjxrnudWSY5vomh+23ZaXzAS7J3fBZIR2dV6WbmfM0w== - dependencies: - universalify "^0.1.2" - optionalDependencies: - graceful-fs "^4.1.6" - - jsprim@^1.2.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" - integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.4.0" - verror "1.10.0" - - "jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz#720b97bfe7d901b927d87c3773637ae8ea48781b" - integrity sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA== - dependencies: - array-includes "^3.1.3" - object.assign "^4.1.2" - - jwa@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/jwa/-/jwa-2.0.0.tgz#a7e9c3f29dae94027ebcaf49975c9345593410fc" - integrity sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA== - dependencies: - buffer-equal-constant-time "1.0.1" - ecdsa-sig-formatter "1.0.11" - safe-buffer "^5.0.1" - - jws@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/jws/-/jws-4.0.0.tgz#2d4e8cf6a318ffaa12615e9dec7e86e6c97310f4" - integrity sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg== - dependencies: - jwa "^2.0.0" - safe-buffer "^5.0.1" - - keccak@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/keccak/-/keccak-3.0.2.tgz#4c2c6e8c54e04f2670ee49fa734eb9da152206e0" - integrity sha512-PyKKjkH53wDMLGrvmRGSNWgmSxZOUqbnXwKL9tmgbFYA1iAYqW21kfR7mZXV0MlESiefxQQE9X9fTa3X+2MPDQ== - dependencies: - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - readable-stream "^3.6.0" - - keyv@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.0.0.tgz#44923ba39e68b12a7cec7df6c3268c031f2ef373" - integrity sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA== - dependencies: - json-buffer "3.0.0" - - keyv@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" - integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== - dependencies: - json-buffer "3.0.0" - - kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= - dependencies: - is-buffer "^1.1.5" - - kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= - dependencies: - is-buffer "^1.1.5" - - kind-of@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" - integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== - - kind-of@^6.0.0, kind-of@^6.0.2: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - - kleur@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" - integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== - - kleur@^4.0.3: - version "4.1.4" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.4.tgz#8c202987d7e577766d039a8cd461934c01cda04d" - integrity sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA== - - language-subtag-registry@~0.3.2: - version "0.3.21" - resolved "https://registry.yarnpkg.com/language-subtag-registry/-/language-subtag-registry-0.3.21.tgz#04ac218bea46f04cb039084602c6da9e788dd45a" - integrity sha512-L0IqwlIXjilBVVYKFT37X9Ih11Um5NEl9cbJIuU/SwP/zEEAbBPOnEeeuxVMf45ydWQRDQN3Nqc96OgbH1K+Pg== - - language-tags@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/language-tags/-/language-tags-1.0.5.tgz#d321dbc4da30ba8bf3024e040fa5c14661f9193a" - integrity sha1-0yHbxNowuovzAk4ED6XBRmH5GTo= - dependencies: - language-subtag-registry "~0.3.2" - - level-blobs@^0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/level-blobs/-/level-blobs-0.1.7.tgz#9ab9b97bb99f1edbf9f78a3433e21ed56386bdaf" - integrity sha1-mrm5e7mfHtv594o0M+Ie1WOGva8= - dependencies: - level-peek "1.0.6" - once "^1.3.0" - readable-stream "^1.0.26-4" - - level-filesystem@^1.0.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/level-filesystem/-/level-filesystem-1.2.0.tgz#a00aca9919c4a4dfafdca6a8108d225aadff63b3" - integrity sha1-oArKmRnEpN+v3KaoEI0iWq3/Y7M= - dependencies: - concat-stream "^1.4.4" - errno "^0.1.1" - fwd-stream "^1.0.4" - level-blobs "^0.1.7" - level-peek "^1.0.6" - level-sublevel "^5.2.0" - octal "^1.0.0" - once "^1.3.0" - xtend "^2.2.0" - - level-fix-range@2.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/level-fix-range/-/level-fix-range-2.0.0.tgz#c417d62159442151a19d9a2367868f1724c2d548" - integrity sha1-xBfWIVlEIVGhnZojZ4aPFyTC1Ug= - dependencies: - clone "~0.1.9" - - level-fix-range@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/level-fix-range/-/level-fix-range-1.0.2.tgz#bf15b915ae36d8470c821e883ddf79cd16420828" - integrity sha1-vxW5Fa422EcMgh6IPd95zRZCCCg= - - "level-hooks@>=4.4.0 <5": - version "4.5.0" - resolved "https://registry.yarnpkg.com/level-hooks/-/level-hooks-4.5.0.tgz#1b9ae61922930f3305d1a61fc4d83c8102c0dd93" - integrity sha1-G5rmGSKTDzMF0aYfxNg8gQLA3ZM= - dependencies: - string-range "~1.2" - - level-js@^2.1.3: - version "2.2.4" - resolved "https://registry.yarnpkg.com/level-js/-/level-js-2.2.4.tgz#bc055f4180635d4489b561c9486fa370e8c11697" - integrity sha1-vAVfQYBjXUSJtWHJSG+jcOjBFpc= - dependencies: - abstract-leveldown "~0.12.0" - idb-wrapper "^1.5.0" - isbuffer "~0.0.0" - ltgt "^2.1.2" - typedarray-to-buffer "~1.0.0" - xtend "~2.1.2" - - level-peek@1.0.6, level-peek@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/level-peek/-/level-peek-1.0.6.tgz#bec51c72a82ee464d336434c7c876c3fcbcce77f" - integrity sha1-vsUccqgu5GTTNkNMfIdsP8vM538= - dependencies: - level-fix-range "~1.0.2" - - level-sublevel@^5.2.0: - version "5.2.3" - resolved "https://registry.yarnpkg.com/level-sublevel/-/level-sublevel-5.2.3.tgz#744c12c72d2e72be78dde3b9b5cd84d62191413a" - integrity sha1-dEwSxy0ucr543eO5tc2E1iGRQTo= - dependencies: - level-fix-range "2.0" - level-hooks ">=4.4.0 <5" - string-range "~1.2.1" - xtend "~2.0.4" - - levelup@^0.18.2: - version "0.18.6" - resolved "https://registry.yarnpkg.com/levelup/-/levelup-0.18.6.tgz#e6a01cb089616c8ecc0291c2a9bd3f0c44e3e5eb" - integrity sha1-5qAcsIlhbI7MApHCqb0/DETj5es= - dependencies: - bl "~0.8.1" - deferred-leveldown "~0.2.0" - errno "~0.1.1" - prr "~0.0.0" - readable-stream "~1.0.26" - semver "~2.3.1" - xtend "~3.0.0" - - leven@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" - integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== - - levn@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - - levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - - libphonenumber-js@^1.9.47: - version "1.9.49" - resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.9.49.tgz#d431703cd699be2ccced5b95f26182a7c50a9227" - integrity sha512-/wEOIONcVboFky+lWlCaF7glm1FhBz11M5PHeCApA+xDdVfmhKjHktHS8KjyGxouV5CSXIr4f3GvLSpJa4qMSg== - - lilconfig@2.0.4, lilconfig@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.4.tgz#f4507d043d7058b380b6a8f5cb7bcd4b34cee082" - integrity sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA== - - 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@^12.3.5: - version "12.3.5" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-12.3.5.tgz#8048ce048c3cac12f57200a06344a54dc91c8fa9" - integrity sha512-oOH36RUs1It7b9U/C7Nl/a0sLfoIBcMB8ramiB3nuJ6brBqzsWiUAFSR5DQ3yyP/OR7XKMpijtgKl2DV1lQ3lA== - dependencies: - cli-truncate "^3.1.0" - colorette "^2.0.16" - commander "^8.3.0" - debug "^4.3.3" - execa "^5.1.1" - lilconfig "2.0.4" - listr2 "^4.0.1" - micromatch "^4.0.4" - normalize-path "^3.0.0" - object-inspect "^1.12.0" - string-argv "^0.3.1" - supports-color "^9.2.1" - yaml "^1.10.2" - - listr2@^4.0.1: - version "4.0.5" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-4.0.5.tgz#9dcc50221583e8b4c71c43f9c7dfd0ef546b75d5" - integrity sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA== - dependencies: - cli-truncate "^2.1.0" - colorette "^2.0.16" - log-update "^4.0.0" - p-map "^4.0.0" - rfdc "^1.3.0" - rxjs "^7.5.5" - through "^2.3.8" - wrap-ansi "^7.0.0" - - load-bmfont@^1.3.1, load-bmfont@^1.4.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/load-bmfont/-/load-bmfont-1.4.1.tgz#c0f5f4711a1e2ccff725a7b6078087ccfcddd3e9" - integrity sha512-8UyQoYmdRDy81Brz6aLAUhfZLwr5zV0L3taTQ4hju7m6biuwiWiJXjPhBJxbUQJA8PrkvJ/7Enqmwk2sM14soA== - dependencies: - buffer-equal "0.0.1" - mime "^1.3.4" - parse-bmfont-ascii "^1.0.3" - parse-bmfont-binary "^1.0.5" - parse-bmfont-xml "^1.1.4" - phin "^2.9.1" - xhr "^2.0.1" - xtend "^4.0.0" - - load-json-file@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" - integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= - dependencies: - graceful-fs "^4.1.2" - parse-json "^4.0.0" - pify "^3.0.0" - strip-bom "^3.0.0" - - loader-utils@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.2.tgz#d6e3b4fb81870721ae4e0868ab11dd638368c129" - integrity sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A== - dependencies: - big.js "^5.2.2" - emojis-list "^3.0.0" - json5 "^2.1.2" - - locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - - locate-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" - integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== - dependencies: - p-locate "^3.0.0" - path-exists "^3.0.0" - - locate-path@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" - integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== - dependencies: - p-locate "^4.1.0" - - lodash-es@^4.17.21: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" - integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== - - lodash.castarray@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.castarray/-/lodash.castarray-4.4.0.tgz#c02513515e309daddd4c24c60cfddcf5976d9115" - integrity sha1-wCUTUV4wna3dTCTGDP3c9ZdtkRU= - - lodash.clonedeep@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" - integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= - - lodash.debounce@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= - - lodash.isequal@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" - integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA= - - lodash.isplainobject@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" - integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= - - lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - - lodash.once@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" - integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= - - lodash@4.17.21, lodash@4.x, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - - log-update@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" - integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== - dependencies: - ansi-escapes "^4.3.0" - cli-cursor "^3.1.0" - slice-ansi "^4.0.0" - wrap-ansi "^6.2.0" - - long@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" - integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== - - longest-streak@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-2.0.4.tgz#b8599957da5b5dab64dee3fe316fa774597d90e4" - integrity sha512-vM6rUVCVUJJt33bnmHiZEvr7wPT78ztX7rojL+LW51bHtLh6HTjx84LA5W4+oa6aKEJA7jJu5LR6vQRBpA5DVg== - - longest-streak@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/longest-streak/-/longest-streak-3.0.1.tgz#c97315b7afa0e7d9525db9a5a2953651432bdc5d" - integrity sha512-cHlYSUpL2s7Fb3394mYxwTYj8niTaNHUCLr0qdiCXQfSjfuA7CKofpX2uSwEfFDQ0EB7JcnMnm+GjbqqoinYYg== - - loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3.1, loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - - lowercase-keys@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.0.tgz#4e3366b39e7f5457e35f1324bdf6f88d0bfc7306" - integrity sha1-TjNms55/VFfjXxMkvfb4jQv8cwY= - - lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" - integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== - - lowercase-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" - integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== - - lru-cache@^4.0.1, lru-cache@^4.1.3: - version "4.1.5" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" - integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - - lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - - ltgt@^2.1.2: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ltgt/-/ltgt-2.2.1.tgz#f35ca91c493f7b73da0e07495304f17b31f87ee5" - integrity sha1-81ypHEk/e3PaDgdJUwTxezH4fuU= - - magic-string@^0.25.7: - version "0.25.9" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c" - integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ== - dependencies: - sourcemap-codec "^1.4.8" - - make-dir@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" - integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== - dependencies: - pify "^3.0.0" - - make-dir@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" - integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== - dependencies: - pify "^4.0.1" - semver "^5.6.0" - - make-dir@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - - make-error@1.x, make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - - make-event-props@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/make-event-props/-/make-event-props-1.3.0.tgz#2434cb390d58bcf40898d009ef5b1f936de9671b" - integrity sha512-oWiDZMcVB1/A487251hEWza1xzgCzl6MXxe9aF24l5Bt9N9UEbqTqKumEfuuLhmlhRZYnc+suVvW4vUs8bwO7Q== - - makeerror@1.0.12: - version "1.0.12" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" - integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== - dependencies: - tmpl "1.0.5" - - map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= - - map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= - dependencies: - object-visit "^1.0.0" - - markdown-extensions@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/markdown-extensions/-/markdown-extensions-1.1.1.tgz#fea03b539faeaee9b4ef02a3769b455b189f7fc3" - integrity sha512-WWC0ZuMzCyDHYCasEGs4IPvLyTGftYwh6wIEOULOF0HXcqZlhwRzrK0w2VUlxWA98xnvb/jszw4ZSkJ6ADpM6Q== - - markdown-table@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-2.0.0.tgz#194a90ced26d31fe753d8b9434430214c011865b" - integrity sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A== - dependencies: - repeat-string "^1.0.0" - - match-sorter@^4.2.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-4.2.1.tgz#575b4b3737185ba9518b67612b66877ea0b37358" - integrity sha512-s+3h9TiZU9U1pWhIERHf8/f4LmBN6IXaRgo2CI17+XGByGS1GvG5VvXK9pcGyCjGe3WM3mSYRC3ipGrd5UEVgw== - dependencies: - "@babel/runtime" "^7.10.5" - remove-accents "0.4.2" - - match-sorter@^6.0.2: - version "6.3.1" - resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.1.tgz#98cc37fda756093424ddf3cbc62bfe9c75b92bda" - integrity sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw== - dependencies: - "@babel/runtime" "^7.12.5" - remove-accents "0.4.2" - - md5.js@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" - integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - - mdast-util-definitions@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/mdast-util-definitions/-/mdast-util-definitions-5.1.0.tgz#b6d10ef00a3c4cf191e8d9a5fa58d7f4a366f817" - integrity sha512-5hcR7FL2EuZ4q6lLMUK5w4lHT2H3vqL9quPvYZ/Ku5iifrirfMHiGdhxdXMUbUkDmz5I+TYMd7nbaxUhbQkfpQ== - dependencies: - "@types/mdast" "^3.0.0" - "@types/unist" "^2.0.0" - unist-util-visit "^3.0.0" - - mdast-util-find-and-replace@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/mdast-util-find-and-replace/-/mdast-util-find-and-replace-1.1.1.tgz#b7db1e873f96f66588c321f1363069abf607d1b5" - integrity sha512-9cKl33Y21lyckGzpSmEQnIDjEfeeWelN5s1kUW1LwdB0Fkuq2u+4GdqcGEygYxJE8GVqCl0741bYXHgamfWAZA== - dependencies: - escape-string-regexp "^4.0.0" - unist-util-is "^4.0.0" - unist-util-visit-parents "^3.0.0" - - mdast-util-from-markdown@^0.8.0: - version "0.8.5" - resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-0.8.5.tgz#d1ef2ca42bc377ecb0463a987910dae89bd9a28c" - integrity sha512-2hkTXtYYnr+NubD/g6KGBS/0mFmBcifAsI0yIWRiRo0PjVs6SSOSOdtzbp6kSGnShDN6G5aWZpKQ2lWRy27mWQ== - dependencies: - "@types/mdast" "^3.0.0" - mdast-util-to-string "^2.0.0" - micromark "~2.11.0" - parse-entities "^2.0.0" - unist-util-stringify-position "^2.0.0" - - mdast-util-from-markdown@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mdast-util-from-markdown/-/mdast-util-from-markdown-1.2.0.tgz#84df2924ccc6c995dec1e2368b2b208ad0a76268" - integrity sha512-iZJyyvKD1+K7QX1b5jXdE7Sc5dtoTry1vzV28UZZe8Z1xVnB/czKntJ7ZAkG0tANqRnBF6p3p7GpU1y19DTf2Q== - dependencies: - "@types/mdast" "^3.0.0" - "@types/unist" "^2.0.0" - decode-named-character-reference "^1.0.0" - mdast-util-to-string "^3.1.0" - micromark "^3.0.0" - micromark-util-decode-numeric-character-reference "^1.0.0" - micromark-util-decode-string "^1.0.0" - micromark-util-normalize-identifier "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - unist-util-stringify-position "^3.0.0" - uvu "^0.5.0" - - mdast-util-gfm-autolink-literal@^0.1.0: - version "0.1.3" - resolved "https://registry.yarnpkg.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-0.1.3.tgz#9c4ff399c5ddd2ece40bd3b13e5447d84e385fb7" - integrity sha512-GjmLjWrXg1wqMIO9+ZsRik/s7PLwTaeCHVB7vRxUwLntZc8mzmTsLVr6HW1yLokcnhfURsn5zmSVdi3/xWWu1A== - dependencies: - ccount "^1.0.0" - mdast-util-find-and-replace "^1.1.0" - micromark "^2.11.3" - - mdast-util-gfm-strikethrough@^0.2.0: - version "0.2.3" - resolved "https://registry.yarnpkg.com/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-0.2.3.tgz#45eea337b7fff0755a291844fbea79996c322890" - integrity sha512-5OQLXpt6qdbttcDG/UxYY7Yjj3e8P7X16LzvpX8pIQPYJ/C2Z1qFGMmcw+1PZMUM3Z8wt8NRfYTvCni93mgsgA== - dependencies: - mdast-util-to-markdown "^0.6.0" - - mdast-util-gfm-table@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/mdast-util-gfm-table/-/mdast-util-gfm-table-0.1.6.tgz#af05aeadc8e5ee004eeddfb324b2ad8c029b6ecf" - integrity sha512-j4yDxQ66AJSBwGkbpFEp9uG/LS1tZV3P33fN1gkyRB2LoRL+RR3f76m0HPHaby6F4Z5xr9Fv1URmATlRRUIpRQ== - dependencies: - markdown-table "^2.0.0" - mdast-util-to-markdown "~0.6.0" - - mdast-util-gfm-task-list-item@^0.1.0: - version "0.1.6" - resolved "https://registry.yarnpkg.com/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-0.1.6.tgz#70c885e6b9f543ddd7e6b41f9703ee55b084af10" - integrity sha512-/d51FFIfPsSmCIRNp7E6pozM9z1GYPIkSy1urQ8s/o4TC22BZ7DqfHFWiqBD23bc7J3vV1Fc9O4QIHBlfuit8A== - dependencies: - mdast-util-to-markdown "~0.6.0" - - mdast-util-gfm@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/mdast-util-gfm/-/mdast-util-gfm-0.1.2.tgz#8ecddafe57d266540f6881f5c57ff19725bd351c" - integrity sha512-NNkhDx/qYcuOWB7xHUGWZYVXvjPFFd6afg6/e2g+SV4r9q5XUcCbV4Wfa3DLYIiD+xAEZc6K4MGaE/m0KDcPwQ== - dependencies: - mdast-util-gfm-autolink-literal "^0.1.0" - mdast-util-gfm-strikethrough "^0.2.0" - mdast-util-gfm-table "^0.1.0" - mdast-util-gfm-task-list-item "^0.1.0" - mdast-util-to-markdown "^0.6.1" - - mdast-util-mdx-expression@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mdast-util-mdx-expression/-/mdast-util-mdx-expression-1.2.0.tgz#3e927afe27943956dc5d1c64cb949652062f71ff" - integrity sha512-wb36oi09XxqO9RVqgfD+xo8a7xaNgS+01+k3v0GKW0X0bYbeBmUZz22Z/IJ8SuphVlG+DNgNo9VoEaUJ3PKfJQ== - dependencies: - "@types/estree-jsx" "^0.0.1" - "@types/hast" "^2.0.0" - "@types/mdast" "^3.0.0" - mdast-util-from-markdown "^1.0.0" - mdast-util-to-markdown "^1.0.0" - - mdast-util-mdx-jsx@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-2.0.1.tgz#03d003c8b0b4bd94ab092d876c0f92d2b0c83b0b" - integrity sha512-oPC7/smPBf7vxnvIYH5y3fPo2lw1rdrswFfSb4i0GTAXRUQv7JUU/t/hbp07dgGdUFTSDOHm5DNamhNg/s2Hrg== - dependencies: - "@types/estree-jsx" "^0.0.1" - "@types/hast" "^2.0.0" - "@types/mdast" "^3.0.0" - ccount "^2.0.0" - mdast-util-to-markdown "^1.3.0" - parse-entities "^4.0.0" - stringify-entities "^4.0.0" - unist-util-remove-position "^4.0.0" - unist-util-stringify-position "^3.0.0" - vfile-message "^3.0.0" - - mdast-util-mdx@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mdast-util-mdx/-/mdast-util-mdx-2.0.0.tgz#dd4f6c993cf27da32725e50a04874f595b7b63fb" - integrity sha512-M09lW0CcBT1VrJUaF/PYxemxxHa7SLDHdSn94Q9FhxjCQfuW7nMAWKWimTmA3OyDMSTH981NN1csW1X+HPSluw== - dependencies: - mdast-util-mdx-expression "^1.0.0" - mdast-util-mdx-jsx "^2.0.0" - mdast-util-mdxjs-esm "^1.0.0" - - mdast-util-mdxjs-esm@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-1.2.0.tgz#eca8b985f091c2d65a72c19d2740cefbc209aa63" - integrity sha512-IPpX9GBzAIbIRCjbyeLDpMhACFb0wxTIujuR3YElB8LWbducUdMgRJuqs/Vg8xQ1bIAMm7lw8L+YNtua0xKXRw== - dependencies: - "@types/estree-jsx" "^0.0.1" - "@types/hast" "^2.0.0" - "@types/mdast" "^3.0.0" - mdast-util-from-markdown "^1.0.0" - mdast-util-to-markdown "^1.0.0" - - mdast-util-to-hast@^11.0.0: - version "11.3.0" - resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-11.3.0.tgz#ea9220617a710e80aa5cc3ac7cc9d4bb0440ae7a" - integrity sha512-4o3Cli3hXPmm1LhB+6rqhfsIUBjnKFlIUZvudaermXB+4/KONdd/W4saWWkC+LBLbPMqhFSSTSRgafHsT5fVJw== - dependencies: - "@types/hast" "^2.0.0" - "@types/mdast" "^3.0.0" - "@types/mdurl" "^1.0.0" - mdast-util-definitions "^5.0.0" - mdurl "^1.0.0" - unist-builder "^3.0.0" - unist-util-generated "^2.0.0" - unist-util-position "^4.0.0" - unist-util-visit "^4.0.0" - - mdast-util-to-hast@^12.1.0: - version "12.1.1" - resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-12.1.1.tgz#89a2bb405eaf3b05eb8bf45157678f35eef5dbca" - integrity sha512-qE09zD6ylVP14jV4mjLIhDBOrpFdShHZcEsYvvKGABlr9mGbV7mTlRWdoFxL/EYSTNDiC9GZXy7y8Shgb9Dtzw== - dependencies: - "@types/hast" "^2.0.0" - "@types/mdast" "^3.0.0" - "@types/mdurl" "^1.0.0" - mdast-util-definitions "^5.0.0" - mdurl "^1.0.0" - micromark-util-sanitize-uri "^1.0.0" - unist-builder "^3.0.0" - unist-util-generated "^2.0.0" - unist-util-position "^4.0.0" - unist-util-visit "^4.0.0" - - mdast-util-to-markdown@^0.6.0, mdast-util-to-markdown@^0.6.1, mdast-util-to-markdown@~0.6.0: - version "0.6.5" - resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.5.tgz#b33f67ca820d69e6cc527a93d4039249b504bebe" - integrity sha512-XeV9sDE7ZlOQvs45C9UKMtfTcctcaj/pGwH8YLbMHoMOXNNCn2LsqVQOqrF1+/NU8lKDAqozme9SCXWyo9oAcQ== - dependencies: - "@types/unist" "^2.0.0" - longest-streak "^2.0.0" - mdast-util-to-string "^2.0.0" - parse-entities "^2.0.0" - repeat-string "^1.0.0" - zwitch "^1.0.0" - - mdast-util-to-markdown@^1.0.0, mdast-util-to-markdown@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-1.3.0.tgz#38b6cdc8dc417de642a469c4fc2abdf8c931bd1e" - integrity sha512-6tUSs4r+KK4JGTTiQ7FfHmVOaDrLQJPmpjD6wPMlHGUVXoG9Vjc3jIeP+uyBWRf8clwB2blM+W7+KrlMYQnftA== - dependencies: - "@types/mdast" "^3.0.0" - "@types/unist" "^2.0.0" - longest-streak "^3.0.0" - mdast-util-to-string "^3.0.0" - micromark-util-decode-string "^1.0.0" - unist-util-visit "^4.0.0" - zwitch "^2.0.0" - - mdast-util-to-string@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz#b8cfe6a713e1091cb5b728fc48885a4767f8b97b" - integrity sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w== - - mdast-util-to-string@^3.0.0, mdast-util-to-string@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-3.1.0.tgz#56c506d065fbf769515235e577b5a261552d56e9" - integrity sha512-n4Vypz/DZgwo0iMHLQL49dJzlp7YtAJP+N07MZHpjPf/5XJuHUWstviF4Mn2jEiR/GNmtnRRqnwsXExk3igfFA== - - mdurl@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" - integrity sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4= - - media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= - - "memoize-one@>=3.1.1 <6", memoize-one@^5.0.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" - integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== - - memory-pager@^1.0.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" - integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== - - memorystream@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2" - integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI= - - merge-class-names@^1.1.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/merge-class-names/-/merge-class-names-1.4.2.tgz#78d6d95ab259e7e647252a7988fd25a27d5a8835" - integrity sha512-bOl98VzwCGi25Gcn3xKxnR5p/WrhWFQB59MS/aGENcmUc6iSm96yrFDF0XSNurX9qN4LbJm0R9kfvsQ17i8zCw== - - merge-descriptors@1.0.1, merge-descriptors@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= - - merge-refs@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/merge-refs/-/merge-refs-1.0.0.tgz#388348bce22e623782c6df9d3c4fc55888276120" - integrity sha512-WZ4S5wqD9FCR9hxkLgvcHJCBxzXzy3VVE6p8W2OzxRzB+hLRlcadGE2bW9xp2KSzk10rvp4y+pwwKO6JQVguMg== - - merge-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" - integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== - - merge2@^1.3.0, merge2@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - - methods@^1.1.2, methods@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= - - micro@9.3.4, micro@^9.3.4: - version "9.3.4" - resolved "https://registry.yarnpkg.com/micro/-/micro-9.3.4.tgz#745a494e53c8916f64fb6a729f8cbf2a506b35ad" - integrity sha512-smz9naZwTG7qaFnEZ2vn248YZq9XR+XoOH3auieZbkhDL4xLOxiE+KqG8qqnBeKfXA9c1uEFGCxPN1D+nT6N7w== - dependencies: - arg "4.1.0" - content-type "1.0.4" - is-stream "1.1.0" - raw-body "2.3.2" - - micromark-core-commonmark@^1.0.0, micromark-core-commonmark@^1.0.1: - version "1.0.6" - resolved "https://registry.yarnpkg.com/micromark-core-commonmark/-/micromark-core-commonmark-1.0.6.tgz#edff4c72e5993d93724a3c206970f5a15b0585ad" - integrity sha512-K+PkJTxqjFfSNkfAhp4GB+cZPfQd6dxtTXnf+RjZOV7T4EEXnvgzOcnp+eSTmpGk9d1S9sL6/lqrgSNn/s0HZA== - dependencies: - decode-named-character-reference "^1.0.0" - micromark-factory-destination "^1.0.0" - micromark-factory-label "^1.0.0" - micromark-factory-space "^1.0.0" - micromark-factory-title "^1.0.0" - micromark-factory-whitespace "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-chunked "^1.0.0" - micromark-util-classify-character "^1.0.0" - micromark-util-html-tag-name "^1.0.0" - micromark-util-normalize-identifier "^1.0.0" - micromark-util-resolve-all "^1.0.0" - micromark-util-subtokenize "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.1" - uvu "^0.5.0" - - micromark-extension-gfm-autolink-literal@~0.5.0: - version "0.5.7" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-0.5.7.tgz#53866c1f0c7ef940ae7ca1f72c6faef8fed9f204" - integrity sha512-ePiDGH0/lhcngCe8FtH4ARFoxKTUelMp4L7Gg2pujYD5CSMb9PbblnyL+AAMud/SNMyusbS2XDSiPIRcQoNFAw== - dependencies: - micromark "~2.11.3" - - micromark-extension-gfm-strikethrough@~0.6.5: - version "0.6.5" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-0.6.5.tgz#96cb83356ff87bf31670eefb7ad7bba73e6514d1" - integrity sha512-PpOKlgokpQRwUesRwWEp+fHjGGkZEejj83k9gU5iXCbDG+XBA92BqnRKYJdfqfkrRcZRgGuPuXb7DaK/DmxOhw== - dependencies: - micromark "~2.11.0" - - micromark-extension-gfm-table@~0.4.0: - version "0.4.3" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-table/-/micromark-extension-gfm-table-0.4.3.tgz#4d49f1ce0ca84996c853880b9446698947f1802b" - integrity sha512-hVGvESPq0fk6ALWtomcwmgLvH8ZSVpcPjzi0AjPclB9FsVRgMtGZkUcpE0zgjOCFAznKepF4z3hX8z6e3HODdA== - dependencies: - micromark "~2.11.0" - - micromark-extension-gfm-tagfilter@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-0.3.0.tgz#d9f26a65adee984c9ccdd7e182220493562841ad" - integrity sha512-9GU0xBatryXifL//FJH+tAZ6i240xQuFrSL7mYi8f4oZSbc+NvXjkrHemeYP0+L4ZUT+Ptz3b95zhUZnMtoi/Q== - - micromark-extension-gfm-task-list-item@~0.3.0: - version "0.3.3" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-0.3.3.tgz#d90c755f2533ed55a718129cee11257f136283b8" - integrity sha512-0zvM5iSLKrc/NQl84pZSjGo66aTGd57C1idmlWmE87lkMcXrTxg1uXa/nXomxJytoje9trP0NDLvw4bZ/Z/XCQ== - dependencies: - micromark "~2.11.0" - - micromark-extension-gfm@^0.3.0: - version "0.3.3" - resolved "https://registry.yarnpkg.com/micromark-extension-gfm/-/micromark-extension-gfm-0.3.3.tgz#36d1a4c089ca8bdfd978c9bd2bf1a0cb24e2acfe" - integrity sha512-oVN4zv5/tAIA+l3GbMi7lWeYpJ14oQyJ3uEim20ktYFAcfX1x3LNlFGGlmrZHt7u9YlKExmyJdDGaTt6cMSR/A== - dependencies: - micromark "~2.11.0" - micromark-extension-gfm-autolink-literal "~0.5.0" - micromark-extension-gfm-strikethrough "~0.6.5" - micromark-extension-gfm-table "~0.4.0" - micromark-extension-gfm-tagfilter "~0.3.0" - micromark-extension-gfm-task-list-item "~0.3.0" - - micromark-extension-mdx-expression@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-1.0.3.tgz#cd3843573921bf55afcfff4ae0cd2e857a16dcfa" - integrity sha512-TjYtjEMszWze51NJCZmhv7MEBcgYRgb3tJeMAJ+HQCAaZHHRBaDCccqQzGizR/H4ODefP44wRTgOn2vE5I6nZA== - dependencies: - micromark-factory-mdx-expression "^1.0.0" - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-events-to-acorn "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - - micromark-extension-mdx-jsx@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-1.0.3.tgz#9f196be5f65eb09d2a49b237a7b3398bba2999be" - integrity sha512-VfA369RdqUISF0qGgv2FfV7gGjHDfn9+Qfiv5hEwpyr1xscRj/CiVRkU7rywGFCO7JwJ5L0e7CJz60lY52+qOA== - dependencies: - "@types/acorn" "^4.0.0" - estree-util-is-identifier-name "^2.0.0" - micromark-factory-mdx-expression "^1.0.0" - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - vfile-message "^3.0.0" - - micromark-extension-mdx-md@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-extension-mdx-md/-/micromark-extension-mdx-md-1.0.0.tgz#382f5df9ee3706dd120b51782a211f31f4760d22" - integrity sha512-xaRAMoSkKdqZXDAoSgp20Azm0aRQKGOl0RrS81yGu8Hr/JhMsBmfs4wR7m9kgVUIO36cMUQjNyiyDKPrsv8gOw== - dependencies: - micromark-util-types "^1.0.0" - - micromark-extension-mdxjs-esm@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-1.0.2.tgz#df0c48743a0b1988119489c68314160b7942ffa6" - integrity sha512-bIaxblNIM+CCaJvp3L/V+168l79iuNmxEiTU6i3vB0YuDW+rumV64BFMxvhfRDxaJxQE1zD5vTPdyLBbW4efGA== - dependencies: - micromark-core-commonmark "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-events-to-acorn "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - unist-util-position-from-estree "^1.1.0" - uvu "^0.5.0" - vfile-message "^3.0.0" - - micromark-extension-mdxjs@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-extension-mdxjs/-/micromark-extension-mdxjs-1.0.0.tgz#772644e12fc8299a33e50f59c5aa15727f6689dd" - integrity sha512-TZZRZgeHvtgm+IhtgC2+uDMR7h8eTKF0QUX9YsgoL9+bADBpBY6SiLvWqnBlLbCEevITmTqmEuY3FoxMKVs1rQ== - dependencies: - acorn "^8.0.0" - acorn-jsx "^5.0.0" - micromark-extension-mdx-expression "^1.0.0" - micromark-extension-mdx-jsx "^1.0.0" - micromark-extension-mdx-md "^1.0.0" - micromark-extension-mdxjs-esm "^1.0.0" - micromark-util-combine-extensions "^1.0.0" - micromark-util-types "^1.0.0" - - micromark-factory-destination@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-destination/-/micromark-factory-destination-1.0.0.tgz#fef1cb59ad4997c496f887b6977aa3034a5a277e" - integrity sha512-eUBA7Rs1/xtTVun9TmV3gjfPz2wEwgK5R5xcbIM5ZYAtvGF6JkyaDsj0agx8urXnO31tEO6Ug83iVH3tdedLnw== - dependencies: - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - - micromark-factory-label@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/micromark-factory-label/-/micromark-factory-label-1.0.2.tgz#6be2551fa8d13542fcbbac478258fb7a20047137" - integrity sha512-CTIwxlOnU7dEshXDQ+dsr2n+yxpP0+fn271pu0bwDIS8uqfFcumXpj5mLn3hSC8iw2MUr6Gx8EcKng1dD7i6hg== - dependencies: - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - - micromark-factory-mdx-expression@^1.0.0: - version "1.0.6" - resolved "https://registry.yarnpkg.com/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-1.0.6.tgz#917e17d16e6e9c2551f3a862e6a9ebdd22056476" - integrity sha512-WRQIc78FV7KrCfjsEf/sETopbYjElh3xAmNpLkd1ODPqxEngP42eVRGbiPEQWpRV27LzqW+XVTvQAMIIRLPnNA== - dependencies: - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-events-to-acorn "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - unist-util-position-from-estree "^1.0.0" - uvu "^0.5.0" - vfile-message "^3.0.0" - - micromark-factory-space@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-space/-/micromark-factory-space-1.0.0.tgz#cebff49968f2b9616c0fcb239e96685cb9497633" - integrity sha512-qUmqs4kj9a5yBnk3JMLyjtWYN6Mzfcx8uJfi5XAveBniDevmZasdGBba5b4QsvRcAkmvGo5ACmSUmyGiKTLZew== - dependencies: - micromark-util-character "^1.0.0" - micromark-util-types "^1.0.0" - - micromark-factory-title@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/micromark-factory-title/-/micromark-factory-title-1.0.2.tgz#7e09287c3748ff1693930f176e1c4a328382494f" - integrity sha512-zily+Nr4yFqgMGRKLpTVsNl5L4PMu485fGFDOQJQBl2NFpjGte1e86zC0da93wf97jrc4+2G2GQudFMHn3IX+A== - dependencies: - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - - micromark-factory-whitespace@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-factory-whitespace/-/micromark-factory-whitespace-1.0.0.tgz#e991e043ad376c1ba52f4e49858ce0794678621c" - integrity sha512-Qx7uEyahU1lt1RnsECBiuEbfr9INjQTGa6Err+gF3g0Tx4YEviPbqqGKNv/NrBaE7dVHdn1bVZKM/n5I/Bak7A== - dependencies: - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - - micromark-util-character@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/micromark-util-character/-/micromark-util-character-1.1.0.tgz#d97c54d5742a0d9611a68ca0cd4124331f264d86" - integrity sha512-agJ5B3unGNJ9rJvADMJ5ZiYjBRyDpzKAOk01Kpi1TKhlT1APx3XZk6eN7RtSz1erbWHC2L8T3xLZ81wdtGRZzg== - dependencies: - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - - micromark-util-chunked@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-chunked/-/micromark-util-chunked-1.0.0.tgz#5b40d83f3d53b84c4c6bce30ed4257e9a4c79d06" - integrity sha512-5e8xTis5tEZKgesfbQMKRCyzvffRRUX+lK/y+DvsMFdabAicPkkZV6gO+FEWi9RfuKKoxxPwNL+dFF0SMImc1g== - dependencies: - micromark-util-symbol "^1.0.0" - - micromark-util-classify-character@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-classify-character/-/micromark-util-classify-character-1.0.0.tgz#cbd7b447cb79ee6997dd274a46fc4eb806460a20" - integrity sha512-F8oW2KKrQRb3vS5ud5HIqBVkCqQi224Nm55o5wYLzY/9PwHGXC01tr3d7+TqHHz6zrKQ72Okwtvm/xQm6OVNZA== - dependencies: - micromark-util-character "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - - micromark-util-combine-extensions@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-combine-extensions/-/micromark-util-combine-extensions-1.0.0.tgz#91418e1e74fb893e3628b8d496085639124ff3d5" - integrity sha512-J8H058vFBdo/6+AsjHp2NF7AJ02SZtWaVUjsayNFeAiydTxUwViQPxN0Hf8dp4FmCQi0UUFovFsEyRSUmFH3MA== - dependencies: - micromark-util-chunked "^1.0.0" - micromark-util-types "^1.0.0" - - micromark-util-decode-numeric-character-reference@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-1.0.0.tgz#dcc85f13b5bd93ff8d2868c3dba28039d490b946" - integrity sha512-OzO9AI5VUtrTD7KSdagf4MWgHMtET17Ua1fIpXTpuhclCqD8egFWo85GxSGvxgkGS74bEahvtM0WP0HjvV0e4w== - dependencies: - micromark-util-symbol "^1.0.0" - - micromark-util-decode-string@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/micromark-util-decode-string/-/micromark-util-decode-string-1.0.2.tgz#942252ab7a76dec2dbf089cc32505ee2bc3acf02" - integrity sha512-DLT5Ho02qr6QWVNYbRZ3RYOSSWWFuH3tJexd3dgN1odEuPNxCngTCXJum7+ViRAd9BbdxCvMToPOD/IvVhzG6Q== - dependencies: - decode-named-character-reference "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-decode-numeric-character-reference "^1.0.0" - micromark-util-symbol "^1.0.0" - - micromark-util-encode@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/micromark-util-encode/-/micromark-util-encode-1.0.1.tgz#2c1c22d3800870ad770ece5686ebca5920353383" - integrity sha512-U2s5YdnAYexjKDel31SVMPbfi+eF8y1U4pfiRW/Y8EFVCy/vgxk/2wWTxzcqE71LHtCuCzlBDRU2a5CQ5j+mQA== - - micromark-util-events-to-acorn@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-1.0.4.tgz#07d26cd675dbca8c38b8d9aff2d4cdc91c9997aa" - integrity sha512-dpo8ecREK5s/KMph7jJ46RLM6g7N21CMc9LAJQbDLdbQnTpijigkSJPTIfLXZ+h5wdXlcsQ+b6ufAE9v76AdgA== - dependencies: - "@types/acorn" "^4.0.0" - "@types/estree" "^0.0.50" - estree-util-visit "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - vfile-message "^3.0.0" - - micromark-util-html-tag-name@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-html-tag-name/-/micromark-util-html-tag-name-1.0.0.tgz#75737e92fef50af0c6212bd309bc5cb8dbd489ed" - integrity sha512-NenEKIshW2ZI/ERv9HtFNsrn3llSPZtY337LID/24WeLqMzeZhBEE6BQ0vS2ZBjshm5n40chKtJ3qjAbVV8S0g== - - micromark-util-normalize-identifier@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-1.0.0.tgz#4a3539cb8db954bbec5203952bfe8cedadae7828" - integrity sha512-yg+zrL14bBTFrQ7n35CmByWUTFsgst5JhA4gJYoty4Dqzj4Z4Fr/DHekSS5aLfH9bdlfnSvKAWsAgJhIbogyBg== - dependencies: - micromark-util-symbol "^1.0.0" - - micromark-util-resolve-all@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-resolve-all/-/micromark-util-resolve-all-1.0.0.tgz#a7c363f49a0162e931960c44f3127ab58f031d88" - integrity sha512-CB/AGk98u50k42kvgaMM94wzBqozSzDDaonKU7P7jwQIuH2RU0TeBqGYJz2WY1UdihhjweivStrJ2JdkdEmcfw== - dependencies: - micromark-util-types "^1.0.0" - - micromark-util-sanitize-uri@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-1.0.0.tgz#27dc875397cd15102274c6c6da5585d34d4f12b2" - integrity sha512-cCxvBKlmac4rxCGx6ejlIviRaMKZc0fWm5HdCHEeDWRSkn44l6NdYVRyU+0nT1XC72EQJMZV8IPHF+jTr56lAg== - dependencies: - micromark-util-character "^1.0.0" - micromark-util-encode "^1.0.0" - micromark-util-symbol "^1.0.0" - - micromark-util-subtokenize@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/micromark-util-subtokenize/-/micromark-util-subtokenize-1.0.2.tgz#ff6f1af6ac836f8bfdbf9b02f40431760ad89105" - integrity sha512-d90uqCnXp/cy4G881Ub4psE57Sf8YD0pim9QdjCRNjfas2M1u6Lbt+XZK9gnHL2XFhnozZiEdCa9CNfXSfQ6xA== - dependencies: - micromark-util-chunked "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.0" - uvu "^0.5.0" - - micromark-util-symbol@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/micromark-util-symbol/-/micromark-util-symbol-1.0.1.tgz#b90344db62042ce454f351cf0bebcc0a6da4920e" - integrity sha512-oKDEMK2u5qqAptasDAwWDXq0tG9AssVwAx3E9bBF3t/shRIGsWIRG+cGafs2p/SnDSOecnt6hZPCE2o6lHfFmQ== - - micromark-util-types@^1.0.0, micromark-util-types@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/micromark-util-types/-/micromark-util-types-1.0.2.tgz#f4220fdb319205812f99c40f8c87a9be83eded20" - integrity sha512-DCfg/T8fcrhrRKTPjRrw/5LLvdGV7BHySf/1LOZx7TzWZdYRjogNtyNq885z3nNallwr3QUKARjqvHqX1/7t+w== - - micromark@^2.11.3, micromark@~2.11.0, micromark@~2.11.3: - version "2.11.4" - resolved "https://registry.yarnpkg.com/micromark/-/micromark-2.11.4.tgz#d13436138eea826383e822449c9a5c50ee44665a" - integrity sha512-+WoovN/ppKolQOFIAajxi7Lu9kInbPxFuTBVEavFcL8eAfVstoc5MocPmqBeAdBOJV00uaVjegzH4+MA0DN/uA== - dependencies: - debug "^4.0.0" - parse-entities "^2.0.0" - - micromark@^3.0.0: - version "3.0.10" - resolved "https://registry.yarnpkg.com/micromark/-/micromark-3.0.10.tgz#1eac156f0399d42736458a14b0ca2d86190b457c" - integrity sha512-ryTDy6UUunOXy2HPjelppgJ2sNfcPz1pLlMdA6Rz9jPzhLikWXv/irpWV/I2jd68Uhmny7hHxAlAhk4+vWggpg== - dependencies: - "@types/debug" "^4.0.0" - debug "^4.0.0" - decode-named-character-reference "^1.0.0" - micromark-core-commonmark "^1.0.1" - micromark-factory-space "^1.0.0" - micromark-util-character "^1.0.0" - micromark-util-chunked "^1.0.0" - micromark-util-combine-extensions "^1.0.0" - micromark-util-decode-numeric-character-reference "^1.0.0" - micromark-util-encode "^1.0.0" - micromark-util-normalize-identifier "^1.0.0" - micromark-util-resolve-all "^1.0.0" - micromark-util-sanitize-uri "^1.0.0" - micromark-util-subtokenize "^1.0.0" - micromark-util-symbol "^1.0.0" - micromark-util-types "^1.0.1" - uvu "^0.5.0" - - micromatch@^3.1.4: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - - micromatch@^4.0.2, micromatch@^4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" - integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== - dependencies: - braces "^3.0.1" - picomatch "^2.2.3" - - microseconds@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/microseconds/-/microseconds-0.2.0.tgz#233b25f50c62a65d861f978a4a4f8ec18797dc39" - integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA== - - miller-rabin@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" - integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - - mime-db@1.52.0, mime-db@^1.28.0: - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - - mime-types@^2.1.12, mime-types@^2.1.16, mime-types@~2.1.19, mime-types@~2.1.24, mime-types@~2.1.34: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - - mime@1.6.0, mime@^1.3.4: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - - mime@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-3.0.0.tgz#b374550dca3a0c18443b0c950a6a58f1931cf7a7" - integrity sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A== - - mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - - mimic-response@^1.0.0, mimic-response@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" - integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== - - min-document@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" - integrity sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU= - dependencies: - dom-walk "^0.1.0" - - mini-create-react-context@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz#072171561bfdc922da08a60c2197a497cc2d1d5e" - integrity sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ== - dependencies: - "@babel/runtime" "^7.12.1" - tiny-warning "^1.0.3" - - mini-svg-data-uri@^1.2.3: - version "1.4.4" - resolved "https://registry.yarnpkg.com/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz#8ab0aabcdf8c29ad5693ca595af19dd2ead09939" - integrity sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg== - - minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - - minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - - minimatch@3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - - minimatch@^3.0.4, minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - - minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== - - minipass@^2.6.0, minipass@^2.9.0: - version "2.9.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" - integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== - dependencies: - safe-buffer "^5.1.2" - yallist "^3.0.0" - - minizlib@^1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" - integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== - dependencies: - minipass "^2.9.0" - - mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - - mkdirp-promise@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz#e9b8f68e552c68a9c1713b84883f7a1dd039b8a1" - integrity sha1-6bj2jlUsaKnBcTuEiD96HdA5uKE= - dependencies: - mkdirp "*" - - mkdirp@*, mkdirp@1.x, mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - - mkdirp@^0.5.1, mkdirp@^0.5.5: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - - mock-fs@^4.1.0: - version "4.14.0" - resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.14.0.tgz#ce5124d2c601421255985e6e94da80a7357b1b18" - integrity sha512-qYvlv/exQ4+svI3UOvPUpLDF0OMX5euvUH0Ny4N5QyRyhNdgAgUrVH3iUINSzEPLvx0kbo/Bp28GJKIqvE7URw== - - mockdate@^3.0.5: - version "3.0.5" - resolved "https://registry.yarnpkg.com/mockdate/-/mockdate-3.0.5.tgz#789be686deb3149e7df2b663d2bc4392bc3284fb" - integrity sha512-iniQP4rj1FhBdBYS/+eQv7j1tadJ9lJtdzgOpvsOHng/GbcDh2Fhdeq+ZRldrPYdXvCyfFUmFeEwEGXZB5I/AQ== - - module-alias@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/module-alias/-/module-alias-2.2.2.tgz#151cdcecc24e25739ff0aa6e51e1c5716974c0e0" - integrity sha512-A/78XjoX2EmNvppVWEhM2oGk3x4lLxnkEA4jTbaK97QKSDjkIoOsKQlfylt/d3kKKi596Qy3NP5XrXJ6fZIC9Q== - - mongodb-connection-string-url@^2.3.2: - version "2.5.2" - resolved "https://registry.yarnpkg.com/mongodb-connection-string-url/-/mongodb-connection-string-url-2.5.2.tgz#f075c8d529e8d3916386018b8a396aed4f16e5ed" - integrity sha512-tWDyIG8cQlI5k3skB6ywaEA5F9f5OntrKKsT/Lteub2zgwSUlhqEN2inGgBTm8bpYJf8QYBdA/5naz65XDpczA== - dependencies: - "@types/whatwg-url" "^8.2.1" - whatwg-url "^11.0.0" - - mongodb@4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-4.3.0.tgz#beac457cf57ea1b5c76ec67b8bbd6a63254bbc7c" - integrity sha512-ovq9ZD9wEvab+LsaQOiwtne1Sy2egaHW8K/H5M18Tv+V5PgTRi+qdmxDGlbm94TSL3h56m6amstptu115Nzgow== - dependencies: - bson "^4.6.1" - denque "^2.0.1" - mongodb-connection-string-url "^2.3.2" - socks "^2.6.1" - optionalDependencies: - saslprep "^1.0.3" - - mri@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" - integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== - - mrmime@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-1.0.0.tgz#14d387f0585a5233d291baba339b063752a2398b" - integrity sha512-a70zx7zFfVO7XpnQ2IX1Myh9yY4UYvfld/dikWRnsXxbyvMcfz+u6UfgNAtH+k2QqtJuzVpv6eLTx1G2+WKZbQ== - - ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - - ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - - ms@2.1.3, ms@^2.1.1: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - - multibase@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.7.0.tgz#1adfc1c50abe05eefeb5091ac0c2728d6b84581b" - integrity sha512-TW8q03O0f6PNFTQDvh3xxH03c8CjGaaYrjkl9UQPG6rz53TQzzxJVCIWVjzcbN/Q5Y53Zd0IBQBMVktVgNx4Fg== - dependencies: - base-x "^3.0.8" - buffer "^5.5.0" - - multibase@~0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/multibase/-/multibase-0.6.1.tgz#b76df6298536cc17b9f6a6db53ec88f85f8cc12b" - integrity sha512-pFfAwyTjbbQgNc3G7D48JkJxWtoJoBMaR4xQUOuB8RnCgRqaYmWNFeJTTvrJ2w51bjLq2zTby6Rqj9TQ9elSUw== - dependencies: - base-x "^3.0.8" - buffer "^5.5.0" - - multicodec@^0.5.5: - version "0.5.7" - resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-0.5.7.tgz#1fb3f9dd866a10a55d226e194abba2dcc1ee9ffd" - integrity sha512-PscoRxm3f+88fAtELwUnZxGDkduE2HD9Q6GHUOywQLjOGT/HAdhjLDYNZ1e7VR0s0TP0EwZ16LNUTFpoBGivOA== - dependencies: - varint "^5.0.0" - - multicodec@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/multicodec/-/multicodec-1.0.4.tgz#46ac064657c40380c28367c90304d8ed175a714f" - integrity sha512-NDd7FeS3QamVtbgfvu5h7fd1IlbaC4EQ0/pgU4zqE2vdHCmBGsUa0TiM8/TdSeG6BMPC92OOCf8F1ocE/Wkrrg== - dependencies: - buffer "^5.6.0" - varint "^5.0.0" - - multihashes@^0.4.15, multihashes@~0.4.15: - version "0.4.21" - resolved "https://registry.yarnpkg.com/multihashes/-/multihashes-0.4.21.tgz#dc02d525579f334a7909ade8a122dabb58ccfcb5" - integrity sha512-uVSvmeCWf36pU2nB4/1kzYZjsXD9vofZKpgudqkceYY5g2aZZXJ5r9lxuzoRLl1OAp28XljXsEJ/X/85ZsKmKw== - dependencies: - buffer "^5.5.0" - multibase "^0.7.0" - varint "^5.0.0" - - mysql2@2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/mysql2/-/mysql2-2.3.3.tgz#944f3deca4b16629052ff8614fbf89d5552545a0" - integrity sha512-wxJUev6LgMSgACDkb/InIFxDprRa6T95+VEoR+xPvtngtccNH2dGjEB/fVZ8yg1gWv1510c9CvXuJHi5zUm0ZA== - dependencies: - denque "^2.0.1" - generate-function "^2.3.1" - iconv-lite "^0.6.3" - long "^4.0.0" - lru-cache "^6.0.0" - named-placeholders "^1.1.2" - seq-queue "^0.0.5" - sqlstring "^2.3.2" - - mz@^2.4.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" - integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== - dependencies: - any-promise "^1.0.0" - object-assign "^4.0.1" - thenify-all "^1.0.0" - - named-placeholders@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/named-placeholders/-/named-placeholders-1.1.2.tgz#ceb1fbff50b6b33492b5cf214ccf5e39cef3d0e8" - integrity sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA== - dependencies: - lru-cache "^4.1.3" - - nano-json-stream-parser@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/nano-json-stream-parser/-/nano-json-stream-parser-0.1.2.tgz#0cc8f6d0e2b622b479c40d499c46d64b755c6f5f" - integrity sha1-DMj20OK2IrR5xA1JnEbWS3Vcb18= - - nano-time@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef" - integrity sha1-sFVPaa2J4i0JB/ehKwmTpdlhN+8= - dependencies: - big-integer "^1.6.16" - - nanoclone@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/nanoclone/-/nanoclone-0.2.1.tgz#dd4090f8f1a110d26bb32c49ed2f5b9235209ed4" - integrity sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA== - - nanoid@^3.1.23, nanoid@^3.1.30, nanoid@^3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" - integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== - - nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - - natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" - integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= - - negotiator@0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" - integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== - - neo-async@^2.6.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" - integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== - - next-api-middleware@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/next-api-middleware/-/next-api-middleware-1.0.1.tgz#8dd76abeace9e10c6be29c9c9486a84cb649cc12" - integrity sha512-t8UbZ9UUPFB7nklrHdAusn7MfoVSHtnWlRV1R0hirvLRHPDnzidTnw1Mu99Kqvc1bVC0rQSUX5kf0j/4nmEtfA== - dependencies: - debug "^4.3.2" - - next-auth@^4.0.6: - version "4.3.0" - resolved "https://registry.yarnpkg.com/next-auth/-/next-auth-4.3.0.tgz#93274254f9e6263c3c3edf7169a92fb13a700619" - integrity sha512-QcXY0EkIoCHDJ/G5n5H1wG7c/E5WlnyTsA+N4un9ys+RF26Vv/kzIuzjSrVQ/no0PkIwQti6E+ZjpqXJCBykTA== - dependencies: - "@babel/runtime" "^7.16.3" - "@panva/hkdf" "^1.0.1" - cookie "^0.4.1" - jose "^4.3.7" - oauth "^0.9.15" - openid-client "^5.1.0" - preact "^10.6.3" - preact-render-to-string "^5.1.19" - uuid "^8.3.2" - - next-i18next@^8.9.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/next-i18next/-/next-i18next-8.10.0.tgz#94440d796d7c3d16a74218ac72df296daf13aaa3" - integrity sha512-nY3tw+uU6lzZq7YfqRr0lFBiz15txIeYBX5R6rVeAK8wWFsCRJpZ6lTm02DMC+MfD1G6LmtpR6bmOOaBD3TR9A== - dependencies: - "@babel/runtime" "^7.13.17" - "@types/hoist-non-react-statics" "^3.3.1" - core-js "^3" - hoist-non-react-statics "^3.2.0" - i18next "^20.1.0" - i18next-fs-backend "^1.0.7" - react-i18next "^11.8.13" - - next-plausible@^2.1.2: - version "2.2.0" - resolved "https://registry.yarnpkg.com/next-plausible/-/next-plausible-2.2.0.tgz#f825842f97bce0062bdaf897328c4908d7ce0a78" - integrity sha512-pIhs5MikL6ZMJvB7sxkM49xN06W1A6d6RYta5vrqwQmF2/oXoCG+IPoaPzyODZ/vo7f2/NMAOaUm5QM0dKqMdA== - - next-seo@^4.26.0: - version "4.29.0" - resolved "https://registry.yarnpkg.com/next-seo/-/next-seo-4.29.0.tgz#d281e95ba47914117cc99e9e468599f0547d9b9b" - integrity sha512-xmwzcz4uHaYJ8glbuhs6FSBQ7z3irmdPYdJJ5saWm72Uy3o+mPKGaPCXQetTCE6/xxVnpoDV4yFtFlEjUcljSg== - - next-themes@^0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/next-themes/-/next-themes-0.0.8.tgz#2a1748317085afbc2509e2c32bd04af4f0f6cb7d" - integrity sha512-dyrh+/bZW4hkecFEg2rfwOLLzU2UnE7KfiwcV0mIwkPrO+1n1WvwkC8nabgKA5Eoi8stkYfjmA72FxTaWEOHtg== - - next-tick@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" - integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== - - next-transpile-modules@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/next-transpile-modules/-/next-transpile-modules-8.0.0.tgz#56375cdc25ae5d23a834195f277fc2737b26cb97" - integrity sha512-Q2f2yB0zMJ8KJbIYAeZoIxG6cSfVk813zr6B5HzsLMBVcJ3FaF8lKr7WG66n0KlHCwjLSmf/6EkgI6QQVWHrDw== - dependencies: - enhanced-resolve "^5.7.0" - escalade "^3.1.1" - - next-transpile-modules@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/next-transpile-modules/-/next-transpile-modules-9.0.0.tgz#133b1742af082e61cc76b02a0f12ffd40ce2bf90" - integrity sha512-VCNFOazIAnXn1hvgYYSTYMnoWgKgwlYh4lm1pKbSfiB3kj5ZYLcKVhfh3jkPOg1cnd9DP+pte9yCUocdPEUBTQ== - dependencies: - enhanced-resolve "^5.7.0" - escalade "^3.1.1" - - next-validations@^0.1.11: - version "0.1.11" - resolved "https://registry.yarnpkg.com/next-validations/-/next-validations-0.1.11.tgz#fcc62dea5be8f9793d410de175f96e3fc1dac54d" - integrity sha512-rdyRgZ3f3jwhLigdi9MC5R74BvRpB3cewa8LVnMHDiDRnSThvX0CdZ5KHK4t/SgrIGaVXiXOQ59KtvBqjcm5pA== - - next@^12.1.0: - version "12.1.0" - resolved "https://registry.yarnpkg.com/next/-/next-12.1.0.tgz#c33d753b644be92fc58e06e5a214f143da61dd5d" - integrity sha512-s885kWvnIlxsUFHq9UGyIyLiuD0G3BUC/xrH0CEnH5lHEWkwQcHOORgbDF0hbrW9vr/7am4ETfX4A7M6DjrE7Q== - dependencies: - "@next/env" "12.1.0" - caniuse-lite "^1.0.30001283" - postcss "8.4.5" - styled-jsx "5.0.0" - use-subscription "1.5.1" - optionalDependencies: - "@next/swc-android-arm64" "12.1.0" - "@next/swc-darwin-arm64" "12.1.0" - "@next/swc-darwin-x64" "12.1.0" - "@next/swc-linux-arm-gnueabihf" "12.1.0" - "@next/swc-linux-arm64-gnu" "12.1.0" - "@next/swc-linux-arm64-musl" "12.1.0" - "@next/swc-linux-x64-gnu" "12.1.0" - "@next/swc-linux-x64-musl" "12.1.0" - "@next/swc-win32-arm64-msvc" "12.1.0" - "@next/swc-win32-ia32-msvc" "12.1.0" - "@next/swc-win32-x64-msvc" "12.1.0" - - nextra-theme-docs@^1.2.2: - version "1.2.6" - resolved "https://registry.yarnpkg.com/nextra-theme-docs/-/nextra-theme-docs-1.2.6.tgz#e6d5d8788534ae62d589db96df65f1a6e8b60bcc" - integrity sha512-6tSq74EEw/lfZXfrN9TXr8UFov1mddW+yXnwQB57XRF9hBVq3WtVl6lJT7Xe9q0S0s9lkEeGviHtq+NRpONcQQ== - dependencies: - "@mdx-js/react" "^1.6.16" - "@reach/skip-nav" "^0.11.2" - classnames "^2.2.6" - focus-visible "^5.1.0" - github-slugger "^1.3.0" - grapheme-splitter "^1.0.4" - intersection-observer "^0.12.0" - match-sorter "^4.2.0" - next-themes "^0.0.8" - parse-git-url "^1.0.1" - prism-react-renderer "^1.1.1" - react-innertext "^1.1.5" - title "^3.4.2" - - nextra@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/nextra/-/nextra-1.1.0.tgz#94df0d975537f3e538d91a9b61101a4bc3e93fc8" - integrity sha512-WxD1c05gs4cyPHWvqOei9ofIQkLjtzQaDQo8+56f5ss7yJ6ZyI7Ohx7nyyjm6yTo1fO8gfj3v1l/AZmLnjh4FA== - dependencies: - "@mdx-js/loader" "^2.0.0-next.9" - download "^8.0.0" - graceful-fs "^4.2.6" - gray-matter "^4.0.3" - loader-utils "^2.0.0" - remark "^13.0.0" - remark-gfm "^1.0.0" - slash "^3.0.0" - strip-markdown "^4.0.0" - - nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - - node-addon-api@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" - integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== - - node-fetch@2.6.7, node-fetch@^2.6.1: - version "2.6.7" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== - dependencies: - whatwg-url "^5.0.0" - - node-forge@^1.0.0: - version "1.2.1" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.2.1.tgz#82794919071ef2eb5c509293325cec8afd0fd53c" - integrity sha512-Fcvtbb+zBcZXbTTVwqGA5W+MKBj56UjVRevvchv5XrcyXbmNdesfZL37nlcWOfpgHhgmxApw3tQbTr4CqNmX4w== - - node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" - integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q== - - node-int64@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" - integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= - - node-mocks-http@^1.11.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/node-mocks-http/-/node-mocks-http-1.11.0.tgz#defc0febf6b935f08245397d47534a8de592996e" - integrity sha512-jS/WzSOcKbOeGrcgKbenZeNhxUNnP36Yw11+hL4TTxQXErGfqYZ+MaYNNvhaTiGIJlzNSqgQkk9j8dSu1YWSuw== - dependencies: - accepts "^1.3.7" - content-disposition "^0.5.3" - depd "^1.1.0" - fresh "^0.5.2" - merge-descriptors "^1.0.1" - methods "^1.1.2" - mime "^1.3.4" - parseurl "^1.3.3" - range-parser "^1.2.0" - type-is "^1.6.18" - - node-notifier@^8.0.0: - version "8.0.2" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.2.tgz#f3167a38ef0d2c8a866a83e318c1ba0efeb702c5" - integrity sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg== - dependencies: - growly "^1.3.0" - is-wsl "^2.2.0" - semver "^7.3.2" - shellwords "^0.1.1" - uuid "^8.3.0" - which "^2.0.2" - - node-releases@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.2.tgz#7139fe71e2f4f11b47d4d2986aaf8c48699e0c01" - integrity sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg== - - nodemailer@^6.7.2: - version "6.7.2" - resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.7.2.tgz#44b2ad5f7ed71b7067f7a21c4fedabaec62b85e0" - integrity sha512-Dz7zVwlef4k5R71fdmxwR8Q39fiboGbu3xgswkzGwczUfjp873rVxt1O46+Fh0j1ORnAC6L9+heI8uUpO6DT7Q== - - normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - - normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= - dependencies: - remove-trailing-separator "^1.0.1" - - normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - - normalize-range@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" - integrity sha1-LRDAa9/TEuqXd2laTShDlFa3WUI= - - normalize-url@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-2.0.1.tgz#835a9da1551fa26f70e92329069a23aa6574d7e6" - integrity sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw== - dependencies: - prepend-http "^2.0.0" - query-string "^5.0.1" - sort-keys "^2.0.0" - - normalize-url@^4.1.0: - version "4.5.1" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" - integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== - - normalize-wheel@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/normalize-wheel/-/normalize-wheel-1.0.1.tgz#aec886affdb045070d856447df62ecf86146ec45" - integrity sha1-rsiGr/2wRQcNhWRH32Ls+GFG7EU= - - npm-run-all@^4.1.5: - version "4.1.5" - resolved "https://registry.yarnpkg.com/npm-run-all/-/npm-run-all-4.1.5.tgz#04476202a15ee0e2e214080861bff12a51d98fba" - integrity sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ== - dependencies: - ansi-styles "^3.2.1" - chalk "^2.4.1" - cross-spawn "^6.0.5" - memorystream "^0.3.1" - minimatch "^3.0.4" - pidtree "^0.3.0" - read-pkg "^3.0.0" - shell-quote "^1.6.1" - string.prototype.padend "^3.0.0" - - npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= - dependencies: - path-key "^2.0.0" - - npm-run-path@^4.0.0, npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - - number-to-bn@1.7.0: - version "1.7.0" - resolved "https://registry.yarnpkg.com/number-to-bn/-/number-to-bn-1.7.0.tgz#bb3623592f7e5f9e0030b1977bd41a0c53fe1ea0" - integrity sha1-uzYjWS9+X54AMLGXe9QaDFP+HqA= - dependencies: - bn.js "4.11.6" - strip-hex-prefix "1.0.0" - - nwsapi@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" - integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== - - oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - - oauth@^0.9.15: - version "0.9.15" - resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1" - integrity sha1-vR/vr2hslrdUda7VGWQS/2DPucE= - - object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - - object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - - object-hash@^2.0.1, object-hash@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-2.2.0.tgz#5ad518581eefc443bd763472b8ff2e9c2c0d54a5" - integrity sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw== - - object-inspect@^1.11.0, object-inspect@^1.12.0, object-inspect@^1.9.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.0.tgz#6e2c120e868fd1fd18cb4f18c31741d0d6e776f0" - integrity sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g== - - object-keys@^1.0.12, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - - object-keys@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.2.0.tgz#cddec02998b091be42bf1035ae32e49f1cb6ea67" - integrity sha1-zd7AKZiwkb5CvxA1rjLknxy26mc= - dependencies: - foreach "~2.0.1" - indexof "~0.0.1" - is "~0.2.6" - - object-keys@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" - integrity sha1-KKaq50KN0sOpLz2V8hM13SBOAzY= - - object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= - dependencies: - isobject "^3.0.0" - - object.assign@^4.1.0, object.assign@^4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" - integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== - dependencies: - call-bind "^1.0.0" - define-properties "^1.1.3" - has-symbols "^1.0.1" - object-keys "^1.1.1" - - object.entries@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.5.tgz#e1acdd17c4de2cd96d5a08487cfb9db84d881861" - integrity sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - - object.fromentries@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.5.tgz#7b37b205109c21e741e605727fe8b0ad5fa08251" - integrity sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - - object.hasown@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/object.hasown/-/object.hasown-1.1.0.tgz#7232ed266f34d197d15cac5880232f7a4790afe5" - integrity sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg== - dependencies: - define-properties "^1.1.3" - es-abstract "^1.19.1" - - object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= - dependencies: - isobject "^3.0.1" - - object.values@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.5.tgz#959f63e3ce9ef108720333082131e4a459b716ac" - integrity sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - - oblivious-set@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.0.0.tgz#c8316f2c2fb6ff7b11b6158db3234c49f733c566" - integrity sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw== - - oboe@2.1.5: - version "2.1.5" - resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.5.tgz#5554284c543a2266d7a38f17e073821fbde393cd" - integrity sha1-VVQoTFQ6ImbXo48X4HOCH73jk80= - dependencies: - http-https "^1.0.0" - - octal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/octal/-/octal-1.0.0.tgz#63e7162a68efbeb9e213588d58e989d1e5c4530b" - integrity sha1-Y+cWKmjvvrniE1iNWOmJ0eXEUws= - - oidc-token-hash@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/oidc-token-hash/-/oidc-token-hash-5.0.1.tgz#ae6beec3ec20f0fd885e5400d175191d6e2f10c6" - integrity sha512-EvoOtz6FIEBzE+9q253HsLCVRiK/0doEJ2HCvvqMQb3dHZrP3WlJKYtJ55CRTw4jmYomzH4wkPuCj/I3ZvpKxQ== - - omggif@^1.0.10, omggif@^1.0.9: - version "1.0.10" - resolved "https://registry.yarnpkg.com/omggif/-/omggif-1.0.10.tgz#ddaaf90d4a42f532e9e7cb3a95ecdd47f17c7b19" - integrity sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw== - - on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= - dependencies: - ee-first "1.1.1" - - once@^1.3.0, once@^1.3.1, once@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - - onetime@^5.1.0, onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - - open@8.4.0: - version "8.4.0" - resolved "https://registry.yarnpkg.com/open/-/open-8.4.0.tgz#345321ae18f8138f82565a910fdc6b39e8c244f8" - integrity sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q== - dependencies: - define-lazy-prop "^2.0.0" - is-docker "^2.1.1" - is-wsl "^2.2.0" - - opener@^1.5.2: - version "1.5.2" - resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" - integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== - - openid-client@^5.1.0: - version "5.1.4" - resolved "https://registry.yarnpkg.com/openid-client/-/openid-client-5.1.4.tgz#1d7c44da8fcf5861c585a2f7ffe4ffe152f2abd5" - integrity sha512-36/PZY3rDgiIFj2uCL9a1fILPmIwu3HksoWO4mukgXe74ZOsEisJMMqTMfmPNw6j/7kO0mBc2xqy4eYRrB8xPA== - dependencies: - jose "^4.1.4" - lru-cache "^6.0.0" - object-hash "^2.0.1" - oidc-token-hash "^5.0.1" - - optionator@^0.8.1: - version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.6" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - word-wrap "~1.2.3" - - optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== - dependencies: - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - word-wrap "^1.2.3" - - otplib@^12.0.1: - version "12.0.1" - resolved "https://registry.yarnpkg.com/otplib/-/otplib-12.0.1.tgz#c1d3060ab7aadf041ed2960302f27095777d1f73" - integrity sha512-xDGvUOQjop7RDgxTQ+o4pOol0/3xSZzawTiPKRrHnQWAy0WjhNs/5HdIDJCrqC4MBynmjXgULc6YfioaxZeFgg== - dependencies: - "@otplib/core" "^12.0.1" - "@otplib/preset-default" "^12.0.1" - "@otplib/preset-v11" "^12.0.1" - - p-cancelable@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.3.0.tgz#b9e123800bcebb7ac13a479be195b507b98d30fa" - integrity sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw== - - p-cancelable@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" - integrity sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ== - - p-cancelable@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" - integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== - - p-each-series@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a" - integrity sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA== - - p-event@^2.1.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/p-event/-/p-event-2.3.1.tgz#596279ef169ab2c3e0cae88c1cfbb08079993ef6" - integrity sha512-NQCqOFhbpVTMX4qMe8PF8lbGtzZ+LCiN7pcNrb/413Na7+TRoe1xkKUzuWa/YEJdGQ0FvKtj35EEbDoVPO2kbA== - dependencies: - p-timeout "^2.0.1" - - p-finally@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" - integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= - - p-is-promise@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-1.1.0.tgz#9c9456989e9f6588017b0434d56097675c3da05e" - integrity sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4= - - p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - - p-limit@^2.0.0, p-limit@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" - integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== - dependencies: - p-try "^2.0.0" - - p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - - p-locate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" - integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== - dependencies: - p-limit "^2.0.0" - - p-locate@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" - integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== - dependencies: - p-limit "^2.2.0" - - p-map@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" - integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== - dependencies: - aggregate-error "^3.0.0" - - p-timeout@^1.1.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-1.2.1.tgz#5eb3b353b7fce99f101a1038880bb054ebbea386" - integrity sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y= - dependencies: - p-finally "^1.0.0" - - p-timeout@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" - integrity sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA== - dependencies: - p-finally "^1.0.0" - - p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - - p-try@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" - integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== - - packet-reader@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-1.0.0.tgz#9238e5480dedabacfe1fe3f2771063f164157d74" - integrity sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ== - - pako@^1.0.5: - version "1.0.11" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf" - integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== - - parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - - parenthesis@^3.1.8: - version "3.1.8" - resolved "https://registry.yarnpkg.com/parenthesis/-/parenthesis-3.1.8.tgz#3457fccb8f05db27572b841dad9d2630b912f125" - integrity sha512-KF/U8tk54BgQewkJPvB4s/US3VQY68BRDpH638+7O/n58TpnwiwnOtGIOsT2/i+M78s61BBpeC83STB88d8sqw== - - parse-asn1@^5.0.0, parse-asn1@^5.1.5: - version "5.1.6" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.6.tgz#385080a3ec13cb62a62d39409cb3e88844cdaed4" - integrity sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw== - dependencies: - asn1.js "^5.2.0" - browserify-aes "^1.0.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - safe-buffer "^5.1.1" - - parse-bmfont-ascii@^1.0.3: - version "1.0.6" - resolved "https://registry.yarnpkg.com/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz#11ac3c3ff58f7c2020ab22769079108d4dfa0285" - integrity sha1-Eaw8P/WPfCAgqyJ2kHkQjU36AoU= - - parse-bmfont-binary@^1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz#d038b476d3e9dd9db1e11a0b0e53a22792b69006" - integrity sha1-0Di0dtPp3Z2x4RoLDlOiJ5K2kAY= - - parse-bmfont-xml@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/parse-bmfont-xml/-/parse-bmfont-xml-1.1.4.tgz#015319797e3e12f9e739c4d513872cd2fa35f389" - integrity sha512-bjnliEOmGv3y1aMEfREMBJ9tfL3WR0i0CKPj61DnSLaoxWR3nLrsQrEbCId/8rF4NyRF0cCqisSVXyQYWM+mCQ== - dependencies: - xml-parse-from-string "^1.0.0" - xml2js "^0.4.5" - - parse-entities@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-2.0.0.tgz#53c6eb5b9314a1f4ec99fa0fdf7ce01ecda0cbe8" - integrity sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ== - dependencies: - character-entities "^1.0.0" - character-entities-legacy "^1.0.0" - character-reference-invalid "^1.0.0" - is-alphanumerical "^1.0.0" - is-decimal "^1.0.0" - is-hexadecimal "^1.0.0" - - parse-entities@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-4.0.0.tgz#f67c856d4e3fe19b1a445c3fabe78dcdc1053eeb" - integrity sha512-5nk9Fn03x3rEhGaX1FU6IDwG/k+GxLXlFAkgrbM1asuAFl3BhdQWvASaIsmwWypRNcZKHPYnIuOSfIWEyEQnPQ== - dependencies: - "@types/unist" "^2.0.0" - character-entities "^2.0.0" - character-entities-legacy "^3.0.0" - character-reference-invalid "^2.0.0" - decode-named-character-reference "^1.0.0" - is-alphanumerical "^2.0.0" - is-decimal "^2.0.0" - is-hexadecimal "^2.0.0" - - parse-git-url@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parse-git-url/-/parse-git-url-1.0.1.tgz#92bdaf615a7e24d32bea3bf955ee90a9050aeb57" - integrity sha512-Zukjztu09UXpXV/Q+4vgwyVPzUBkUvDjlqHlpG+swv/zYzed/5Igw/33rIEJxFDRc5LxvEqYDVDzhBfnOLWDYw== - - parse-headers@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/parse-headers/-/parse-headers-2.0.5.tgz#069793f9356a54008571eb7f9761153e6c770da9" - integrity sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA== - - parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - - parse-json@^5.0.0, parse-json@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" - integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== - dependencies: - "@babel/code-frame" "^7.0.0" - error-ex "^1.3.1" - json-parse-even-better-errors "^2.3.0" - lines-and-columns "^1.1.6" - - parse5-htmlparser2-tree-adapter@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" - integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA== - dependencies: - parse5 "^6.0.1" - - parse5@6.0.1, parse5@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" - integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== - - parse5@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" - integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== - - parseurl@^1.3.3, parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - - pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= - - path-browserify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" - integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== - - path-exists@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" - 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.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - - path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= - - path-key@^3.0.0, path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - - path-parse@^1.0.6, path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - - path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= - - path-to-regexp@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" - integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== - dependencies: - isarray "0.0.1" - - path-type@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" - integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== - dependencies: - pify "^3.0.0" - - path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - - pbkdf2@^3.0.17, pbkdf2@^3.0.3: - version "3.1.2" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075" - integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - - pend@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= - - performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - - periscopic@^3.0.0: - version "3.0.4" - resolved "https://registry.yarnpkg.com/periscopic/-/periscopic-3.0.4.tgz#b3fbed0d1bc844976b977173ca2cd4a0ef4fa8d1" - integrity sha512-SFx68DxCv0Iyo6APZuw/AKewkkThGwssmU0QWtTlvov3VAtPX+QJ4CadwSaz8nrT5jPIuxdvJWB4PnD2KNDxQg== - dependencies: - estree-walker "^3.0.0" - is-reference "^3.0.0" - - pg-connection-string@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.5.0.tgz#538cadd0f7e603fc09a12590f3b8a452c2c0cf34" - integrity sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ== - - pg-int8@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" - integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== - - pg-pool@^3.4.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.5.1.tgz#f499ce76f9bf5097488b3b83b19861f28e4ed905" - integrity sha512-6iCR0wVrro6OOHFsyavV+i6KYL4lVNyYAB9RD18w66xSzN+d8b66HiwuP30Gp1SH5O9T82fckkzsRjlrhD0ioQ== - - pg-protocol@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.5.0.tgz#b5dd452257314565e2d54ab3c132adc46565a6a0" - integrity sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ== - - pg-types@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" - integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== - dependencies: - pg-int8 "1.0.1" - postgres-array "~2.0.0" - postgres-bytea "~1.0.0" - postgres-date "~1.0.4" - postgres-interval "^1.1.0" - - pg@8.7.1: - version "8.7.1" - resolved "https://registry.yarnpkg.com/pg/-/pg-8.7.1.tgz#9ea9d1ec225980c36f94e181d009ab9f4ce4c471" - integrity sha512-7bdYcv7V6U3KAtWjpQJJBww0UEsWuh4yQ/EjNf2HeO/NnvKjpvhEIe/A/TleP6wtmSKnUnghs5A9jUoK6iDdkA== - dependencies: - buffer-writer "2.0.0" - packet-reader "1.0.0" - pg-connection-string "^2.5.0" - pg-pool "^3.4.1" - pg-protocol "^1.5.0" - pg-types "^2.1.0" - pgpass "1.x" - - pgpass@1.x: - version "1.0.5" - resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.5.tgz#9b873e4a564bb10fa7a7dbd55312728d422a223d" - integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug== - dependencies: - split2 "^4.1.0" - - phenomenon@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/phenomenon/-/phenomenon-1.6.0.tgz#7b5b7647d0b48152cc0846994da3d92e8f6da677" - integrity sha512-7h9/fjPD3qNlgggzm88cY58l9sudZ6Ey+UmZsizfhtawO6E3srZQXywaNm2lBwT72TbpHYRPy7ytIHeBUD/G0A== - - phin@^2.9.1: - version "2.9.3" - resolved "https://registry.yarnpkg.com/phin/-/phin-2.9.3.tgz#f9b6ac10a035636fb65dfc576aaaa17b8743125c" - integrity sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA== - - picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== - - picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.2.3: - version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - - pidtree@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a" - integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA== - - pify@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - - pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - - pify@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" - integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== - - pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= - dependencies: - pinkie "^2.0.0" - - pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= - - pirates@4.0.4: - version "4.0.4" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.4.tgz#07df81e61028e402735cdd49db701e4885b4e6e6" - integrity sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw== - - pirates@^4.0.1, pirates@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.5.tgz#feec352ea5c3268fb23a37c702ab1699f35a5f3b" - integrity sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ== - - pixelmatch@5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-5.2.1.tgz#9e4e4f4aa59648208a31310306a5bed5522b0d65" - integrity sha512-WjcAdYSnKrrdDdqTcVEY7aB7UhhwjYQKYhHiBXdJef0MOaQeYpUdQ+iVyBLa5YBKS8MPVPPMX7rpOByISLpeEQ== - dependencies: - pngjs "^4.0.1" - - pixelmatch@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/pixelmatch/-/pixelmatch-4.0.2.tgz#8f47dcec5011b477b67db03c243bc1f3085e8854" - integrity sha1-j0fc7FARtHe2fbA8JDvB8wheiFQ= - dependencies: - pngjs "^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" - - playwright-core@1.19.2: - version "1.19.2" - resolved "https://registry.yarnpkg.com/playwright-core/-/playwright-core-1.19.2.tgz#90b9209554f174c649abf495952fcb4335437218" - integrity sha512-OsL3sJZIo1UxKNWSP7zW7sk3FyUGG06YRHxHeBw51eIOxTCQRx5t+hXd0cvXashN2CHnd3hIZTs2aKa/im4hZQ== - dependencies: - commander "8.3.0" - debug "4.3.3" - extract-zip "2.0.1" - https-proxy-agent "5.0.0" - jpeg-js "0.4.3" - mime "3.0.0" - pngjs "6.0.0" - progress "2.0.3" - proper-lockfile "4.1.2" - proxy-from-env "1.1.0" - rimraf "3.0.2" - socks-proxy-agent "6.1.1" - stack-utils "2.0.5" - ws "8.4.2" - yauzl "2.10.0" - yazl "2.5.1" - - pngjs@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-6.0.0.tgz#ca9e5d2aa48db0228a52c419c3308e87720da821" - integrity sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg== - - pngjs@^3.0.0, pngjs@^3.3.3: - version "3.4.0" - resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f" - integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w== - - pngjs@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-4.0.1.tgz#f803869bb2fc1bfe1bf99aa4ec21c108117cfdbe" - integrity sha512-rf5+2/ioHeQxR6IxuYNYGFytUyG3lma/WW1nsmjeHlWwtb2aByla6dkVc8pmJ9nplzkTA0q2xx7mMWrOTqT4Gg== - - pngjs@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-5.0.0.tgz#e79dd2b215767fd9c04561c01236df960bce7fbb" - integrity sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw== - - posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= - - postcss-js@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-js/-/postcss-js-4.0.0.tgz#31db79889531b80dc7bc9b0ad283e418dce0ac00" - integrity sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ== - dependencies: - camelcase-css "^2.0.1" - - postcss-load-config@^3.1.0: - version "3.1.3" - resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.3.tgz#21935b2c43b9a86e6581a576ca7ee1bde2bd1d23" - integrity sha512-5EYgaM9auHGtO//ljHH+v/aC/TQ5LHXtL7bQajNAUBKUVKiYE8rYpFms7+V26D9FncaGe2zwCoPQsFKb5zF/Hw== - dependencies: - lilconfig "^2.0.4" - yaml "^1.10.2" - - postcss-nested@5.0.6: - version "5.0.6" - resolved "https://registry.yarnpkg.com/postcss-nested/-/postcss-nested-5.0.6.tgz#466343f7fc8d3d46af3e7dba3fcd47d052a945bc" - integrity sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA== - dependencies: - postcss-selector-parser "^6.0.6" - - postcss-selector-parser@^6.0.6, postcss-selector-parser@^6.0.9: - version "6.0.9" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz#ee71c3b9ff63d9cd130838876c13a2ec1a992b2f" - integrity sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ== - dependencies: - cssesc "^3.0.0" - util-deprecate "^1.0.2" - - postcss-value-parser@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" - integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== - - postcss@8.4.5: - version "8.4.5" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95" - integrity sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg== - dependencies: - nanoid "^3.1.30" - picocolors "^1.0.0" - source-map-js "^1.0.1" - - postcss@^8.3.6: - version "8.4.12" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.12.tgz#1e7de78733b28970fa4743f7da6f3763648b1905" - integrity sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg== - dependencies: - nanoid "^3.3.1" - picocolors "^1.0.0" - source-map-js "^1.0.2" - - postcss@^8.4.4, postcss@^8.4.6: - version "8.4.11" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.11.tgz#a06229f23820b4ddd46500a3e38dbca1598a8e8d" - integrity sha512-D+jFLnT0ilGfy4CVBGbC+XE68HkVpT8+CUkDrcSpgxmo4RKco2uaZ4kIoyVGEm+m8KN/+Vwgs8MtpNbQ3/ma9w== - dependencies: - nanoid "^3.3.1" - picocolors "^1.0.0" - source-map-js "^1.0.2" - - postgres-array@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" - integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== - - postgres-bytea@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" - integrity sha1-AntTPAqokOJtFy1Hz5zOzFIazTU= - - postgres-date@~1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" - integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== - - postgres-interval@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" - integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== - dependencies: - xtend "^4.0.0" - - preact-render-to-string@^5.1.19: - version "5.1.20" - resolved "https://registry.yarnpkg.com/preact-render-to-string/-/preact-render-to-string-5.1.20.tgz#9e61a478e8514e5c4140282c7c43d9747a6d32a9" - integrity sha512-ivh2oOGzth0o7XqbatWUQ81WQGoJwSqDKP5z917SoqTWYCAr7dlBzMv3SAMTAu3Gr5g47BJwrvyO44H2Y10ubg== - dependencies: - pretty-format "^3.8.0" - - preact@^10.6.3: - version "10.6.6" - resolved "https://registry.yarnpkg.com/preact/-/preact-10.6.6.tgz#f1899bc8dab7c0788b858481532cb3b5d764a520" - integrity sha512-dgxpTFV2vs4vizwKohYKkk7g7rmp1wOOcfd4Tz3IB3Wi+ivZzsn/SpeKJhRENSE+n8sUfsAl4S3HiCVT923ABw== - - prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - - prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= - - prepend-http@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" - integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw= - - prepend-http@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" - integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= - - prettier-linter-helpers@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" - integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== - dependencies: - fast-diff "^1.1.2" - - prettier-plugin-tailwindcss@^0.1.8: - version "0.1.8" - resolved "https://registry.yarnpkg.com/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.1.8.tgz#ba0f606ed91959ede670303d905b99106e9e6293" - integrity sha512-hwarSBCswAXa+kqYtaAkFr3Vop9o04WOyZs0qo3NyvW8L7f1rif61wRyq0+ArmVThOuRBcJF5hjGXYk86cwemg== - - prettier@^2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.5.1.tgz#fff75fa9d519c54cf0fce328c1017d94546bc56a" - integrity sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg== - - pretty-format@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" - integrity sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg== - dependencies: - "@jest/types" "^26.6.2" - ansi-regex "^5.0.0" - ansi-styles "^4.0.0" - react-is "^17.0.1" - - pretty-format@^27.0.0, pretty-format@^27.2.5, pretty-format@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" - integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== - dependencies: - ansi-regex "^5.0.1" - ansi-styles "^5.0.0" - react-is "^17.0.1" - - pretty-format@^3.8.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-3.8.0.tgz#bfbed56d5e9a776645f4b1ff7aa1a3ac4fa3c385" - integrity sha1-v77VbV6ad2ZF9LH/eqGjrE+jw4U= - - printj@~1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/printj/-/printj-1.3.1.tgz#9af6b1d55647a1587ac44f4c1654a4b95b8e12cb" - integrity sha512-GA3TdL8szPK4AQ2YnOe/b+Y1jUFwmmGMMK/qbY7VcE3Z7FU8JstbKiKRzO6CIiAKPhTO8m01NoQ0V5f3jc4OGg== - - prism-react-renderer@^1.1.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/prism-react-renderer/-/prism-react-renderer-1.3.1.tgz#88fc9d0df6bed06ca2b9097421349f8c2f24e30d" - integrity sha512-xUeDMEz074d0zc5y6rxiMp/dlC7C+5IDDlaEUlcBOFE2wddz7hz5PNupb087mPwTt7T9BrFmewObfCBuf/LKwQ== - - prisma@3.10.0: - version "3.10.0" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.10.0.tgz#872d87afbeb1cbcaa77c3d6a63c125e0d704b04d" - integrity sha512-dAld12vtwdz9Rz01nOjmnXe+vHana5PSog8t0XGgLemKsUVsaupYpr74AHaS3s78SaTS5s2HOghnJF+jn91ZrA== - dependencies: - "@prisma/engines" "3.10.0-50.73e60b76d394f8d37d8ebd1f8918c79029f0db86" - - process-es6@^0.11.2: - version "0.11.6" - resolved "https://registry.yarnpkg.com/process-es6/-/process-es6-0.11.6.tgz#c6bb389f9a951f82bd4eb169600105bd2ff9c778" - integrity sha1-xrs4n5qVH4K9TrFpYAEFvS/5x3g= - - process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - - process@^0.11.10: - version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" - integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= - - progress@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - - prompts@^2.0.1: - version "2.4.2" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" - integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== - dependencies: - kleur "^3.0.3" - sisteransi "^1.0.5" - - prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: - version "15.8.1" - resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" - integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.13.1" - - proper-lockfile@4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/proper-lockfile/-/proper-lockfile-4.1.2.tgz#c8b9de2af6b2f1601067f98e01ac66baa223141f" - integrity sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA== - dependencies: - graceful-fs "^4.2.4" - retry "^0.12.0" - signal-exit "^3.0.2" - - property-expr@^2.0.4: - version "2.0.5" - resolved "https://registry.yarnpkg.com/property-expr/-/property-expr-2.0.5.tgz#278bdb15308ae16af3e3b9640024524f4dc02cb4" - integrity sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA== - - property-information@^6.0.0: - version "6.1.1" - resolved "https://registry.yarnpkg.com/property-information/-/property-information-6.1.1.tgz#5ca85510a3019726cb9afed4197b7b8ac5926a22" - integrity sha512-hrzC564QIl0r0vy4l6MvRLhafmUowhO/O3KgVSoXIbbA2Sz4j8HGpJc6T2cubRVwMwpdiG/vKGfhT4IixmKN9w== - - proxy-addr@~2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" - integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== - dependencies: - forwarded "0.2.0" - ipaddr.js "1.9.1" - - proxy-from-env@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" - integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== - - prr@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" - integrity sha1-GoS4WQgyVQFBGFPQCB7j+obikmo= - - prr@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" - integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= - - pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= - - psl@^1.1.28, psl@^1.1.33: - version "1.8.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" - integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== - - public-encrypt@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" - integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - safe-buffer "^5.1.2" - - pump@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - - punycode@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.0.tgz#5f863edc89b96db09074bad7947bf09056ca4e7d" - integrity sha1-X4Y+3Im5bbCQdLrXlHvwkFbKTn0= - - punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - - pvtsutils@^1.2.1, pvtsutils@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/pvtsutils/-/pvtsutils-1.2.2.tgz#62ef6bc0513cbc255ee02574dedeaa41272d6101" - integrity sha512-OALo5ZEdqiI127i64+CXwkCOyFHUA+tCQgaUO/MvRDFXWPr53f2sx28ECNztUEzuyu5xvuuD1EB/szg9mwJoGA== - dependencies: - tslib "^2.3.1" - - pvutils@latest: - version "1.1.3" - resolved "https://registry.yarnpkg.com/pvutils/-/pvutils-1.1.3.tgz#f35fc1d27e7cd3dfbd39c0826d173e806a03f5a3" - integrity sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ== - - qrcode@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/qrcode/-/qrcode-1.5.0.tgz#95abb8a91fdafd86f8190f2836abbfc500c72d1b" - integrity sha512-9MgRpgVc+/+47dFvQeD6U2s0Z92EsKzcHogtum4QB+UNd025WOJSHvn/hjk9xmzj7Stj95CyUAs31mrjxliEsQ== - dependencies: - dijkstrajs "^1.0.1" - encode-utf8 "^1.0.3" - pngjs "^5.0.0" - yargs "^15.3.1" - - qs@6.9.6: - version "6.9.6" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.6.tgz#26ed3c8243a431b2924aca84cc90471f35d5a0ee" - integrity sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ== - - qs@6.9.7: - version "6.9.7" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe" - integrity sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw== - - qs@^6.6.0, qs@^6.7.0: - version "6.10.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.10.3.tgz#d6cde1b2ffca87b5aa57889816c5f81535e22e8e" - integrity sha512-wr7M2E0OFRfIfJZjKGieI8lBKb7fRCH4Fv5KNPEs7gJ8jadvotdsS08PzOKR7opXhZ/Xkjtt3WF9g38drmyRqQ== - dependencies: - side-channel "^1.0.4" - - qs@~6.5.2: - version "6.5.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" - integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== - - query-string@^5.0.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/query-string/-/query-string-5.1.1.tgz#a78c012b71c17e05f2e3fa2319dd330682efb3cb" - integrity sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw== - dependencies: - decode-uri-component "^0.2.0" - object-assign "^4.1.0" - strict-uri-encode "^1.0.0" - - queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - - quick-lru@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-5.1.1.tgz#366493e6b3e42a3a6885e2e99d18f80fb7a8c932" - integrity sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA== - - rambda@7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/rambda/-/rambda-7.0.1.tgz#691fac4e0ca291af303e95e2b6d357293e01923a" - integrity sha512-u4isl3leprMj337gTNc7YOfxa9p0RKlK1RXgHQvCnxjlqy95tWKLCFh+7vZ3kE4bhSX7z2TxaorFDYo20FtHJw== - - randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - - randomfill@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" - integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== - dependencies: - randombytes "^2.0.5" - safe-buffer "^5.1.0" - - range-parser@^1.2.0, range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - - raw-body@2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.2.tgz#bcd60c77d3eb93cde0050295c3f379389bc88f89" - integrity sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k= - dependencies: - bytes "3.0.0" - http-errors "1.6.2" - iconv-lite "0.4.19" - unpipe "1.0.0" - - raw-body@2.4.2: - version "2.4.2" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.2.tgz#baf3e9c21eebced59dd6533ac872b71f7b61cb32" - integrity sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ== - dependencies: - bytes "3.1.1" - http-errors "1.8.1" - iconv-lite "0.4.24" - unpipe "1.0.0" - - raw-body@2.4.3: - version "2.4.3" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.3.tgz#8f80305d11c2a0a545c2d9d89d7a0286fcead43c" - integrity sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g== - dependencies: - bytes "3.1.2" - http-errors "1.8.1" - iconv-lite "0.4.24" - unpipe "1.0.0" - - react-calendar@^3.3.1: - version "3.7.0" - resolved "https://registry.yarnpkg.com/react-calendar/-/react-calendar-3.7.0.tgz#951d56e91afb33b1c1e019cb790349fbffcc6894" - integrity sha512-zkK95zWLWLC6w3O7p3SHx/FJXEyyD2UMd4jr3CrKD+G73N+G5vEwrXxYQCNivIPoFNBjqoyYYGlkHA+TBDPLCw== - dependencies: - "@wojtekmaj/date-utils" "^1.0.2" - get-user-locale "^1.2.0" - merge-class-names "^1.1.1" - prop-types "^15.6.0" - - react-colorful@^5.5.1: - version "5.5.1" - resolved "https://registry.yarnpkg.com/react-colorful/-/react-colorful-5.5.1.tgz#29d9c4e496f2ca784dd2bb5053a3a4340cfaf784" - integrity sha512-M1TJH2X3RXEt12sWkpa6hLc/bbYS0H6F4rIqjQZ+RxNBstpY67d9TrFXtqdZwhpmBXcCwEi7stKqFue3ZRkiOg== - - react-confetti@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/react-confetti/-/react-confetti-6.0.1.tgz#d4f57b5a021dd908a6243b8f63b6009b00818d10" - integrity sha512-ZpOTBrqSNhWE4rRXCZ6E6U+wGd7iYHF5MGrqwikoiBpgBq9Akdu0DcLW+FdFnLjyZYC+VfAiV2KeFgYRMyMrkA== - dependencies: - tween-functions "^1.2.0" - - react-date-picker@^8.3.6, react-date-picker@^8.4.0: - version "8.4.0" - resolved "https://registry.yarnpkg.com/react-date-picker/-/react-date-picker-8.4.0.tgz#2d166bbaa59b08ec8686f671fde553458d19f8c8" - integrity sha512-zocntugDUyiHmV2Nq1qnsk4kDQuhBLUsDTz7akfIEJ0jVX925w0K5Ai5oZzWFNQOzXL/ITxafmDMuSbzlpBt/A== - dependencies: - "@types/react-calendar" "^3.0.0" - "@wojtekmaj/date-utils" "^1.0.3" - get-user-locale "^1.2.0" - make-event-props "^1.1.0" - merge-class-names "^1.1.1" - merge-refs "^1.0.0" - prop-types "^15.6.0" - react-calendar "^3.3.1" - react-fit "^1.4.0" - update-input-width "^1.2.2" - - react-digit-input@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/react-digit-input/-/react-digit-input-2.1.0.tgz#8b0be6d3ea247fd361855483f21d0aafba341196" - integrity sha512-pGv0CtSmu3Mf4cD79LoYtJI7Wq4dpPiLiY1wvKsNaR+X2sJyk1ETiIxjq6G8i+XJqNXExM6vuytzDqblkkSaFw== - - react-dom@17.0.2, react-dom@^17.0.2: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" - integrity sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - scheduler "^0.20.2" - - react-easy-crop@^3.5.2: - version "3.5.3" - resolved "https://registry.yarnpkg.com/react-easy-crop/-/react-easy-crop-3.5.3.tgz#7481b6e484a8b6ac308373f0b173aad4f1d10239" - integrity sha512-ApTbh+lzKAvKqYW81ihd5J6ZTNN3vPDwi6ncFuUrHPI4bko2DlYOESkRm+0NYoW0H8YLaD7bxox+Z3EvIzAbUA== - dependencies: - normalize-wheel "^1.0.1" - tslib "2.0.1" - - react-fit@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/react-fit/-/react-fit-1.4.0.tgz#6b6e3c75215561cc3cfb9854a6811b4347628666" - integrity sha512-cf9sFKbr1rlTB9fNIKE5Uy4NCMUOqrX2mdJ69V4RtmV4KubPdtnbIP1tEar16GXaToCRr7I7c9d2wkTNk9TV5g== - dependencies: - detect-element-overflow "^1.2.0" - prop-types "^15.6.0" - tiny-warning "^1.0.0" - - react-hook-form@^7.16.2, react-hook-form@^7.20.4: - version "7.28.0" - resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.28.0.tgz#40f385da1f31a3c26bb7491d7d77c111b6ad6909" - integrity sha512-mmLpT86BkMGPr0r6ca8zxV0WH4Y1FW5MKs7Rq1+uHLVeeg5pSWbF5Z/qLCnM5vPVblHNM6lRBRRotnfEAf0ALA== - - react-hot-toast@^2.1.0, react-hot-toast@^2.1.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/react-hot-toast/-/react-hot-toast-2.2.0.tgz#ab6f4caed4214b9534f94bb8cfaaf21b051e62b9" - integrity sha512-248rXw13uhf/6TNDVzagX+y7R8J183rp7MwUMNkcrBRyHj/jWOggfXTGlM8zAOuh701WyVW+eUaWG2LeSufX9g== - dependencies: - goober "^2.1.1" - - react-i18next@^11.8.13: - version "11.15.7" - resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.15.7.tgz#f14c5fbf17c568fe356a848a7ef13420c323b87c" - integrity sha512-zSWZ+21LhaG4T155GcvLdepG1j/qJqD9hUGztVtD1MGBc4/l9ft/LMbUX7oKXdVVLyKWjUhUFoDNAwB2402BIQ== - dependencies: - "@babel/runtime" "^7.14.5" - html-escaper "^2.0.2" - html-parse-stringify "^3.0.1" - - react-innertext@^1.1.5: - version "1.1.5" - resolved "https://registry.yarnpkg.com/react-innertext/-/react-innertext-1.1.5.tgz#8147ac54db3f7067d95f49e2d2c05a720d27d8d0" - integrity sha512-PWAqdqhxhHIv80dT9znP2KvS+hfkbRovFp4zFYHFFlOoQLRiawIic81gKb3U1wEyJZgMwgs3JoLtwryASRWP3Q== - - react-intl@^5.22.0: - version "5.24.7" - resolved "https://registry.yarnpkg.com/react-intl/-/react-intl-5.24.7.tgz#a57084543ff8e58ed2d2bc2f1d3b8add3a2f0e3b" - integrity sha512-URPLwISsEmnzft33honGEb87LcK0QtwkZXCNsXcDYTnrYC8ZyeJRTcPYvuXC3mrN6+DxnW52RfHC416zNxfyIg== - dependencies: - "@formatjs/ecma402-abstract" "1.11.3" - "@formatjs/icu-messageformat-parser" "2.0.18" - "@formatjs/intl" "2.1.0" - "@formatjs/intl-displaynames" "5.4.2" - "@formatjs/intl-listformat" "6.5.2" - "@types/hoist-non-react-statics" "^3.3.1" - "@types/react" "16 || 17" - hoist-non-react-statics "^3.3.2" - intl-messageformat "9.11.4" - tslib "^2.1.0" - - react-is@^16.13.1, react-is@^16.6.0, react-is@^16.7.0: - version "16.13.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - - react-is@^17.0.1: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" - integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== - - react-live-chat-loader@^2.7.3: - version "2.7.3" - resolved "https://registry.yarnpkg.com/react-live-chat-loader/-/react-live-chat-loader-2.7.3.tgz#a66a7d64eacdf0a680570b4e9a99639a88bffaae" - integrity sha512-VviVqnF3PYDBJ77JiPZv4cpulx806L22WfsIQxvlxlEWmzKNp/0lEs57uP6EJcE+d1jQwGcR9DIsj5qouE6OkA== - - react-multi-email@^0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/react-multi-email/-/react-multi-email-0.5.3.tgz#734a0d4d1af23feef5cb5e635bde23963b0a9e8b" - integrity sha512-1AneeJlAwjvzkPV740q2SXes/kW3HKOzR3gs+U7whrHN5nz+yH5Unosf/rvz8kRj/eFwBf6fTzMqlJiupu7S5Q== - - react-phone-number-input@^3.1.41: - version "3.1.46" - resolved "https://registry.yarnpkg.com/react-phone-number-input/-/react-phone-number-input-3.1.46.tgz#f25ba70ff83ffb413c824062c5b46f891ee451bc" - integrity sha512-afYl7BMy/0vMqWtzsZBmOgiPdqQAGyPO/Z3auorFs4K/zgFSBq3YoaASleodBkeRO/PygJ4ML8Wnb4Ce+3dlVQ== - dependencies: - classnames "^2.2.5" - country-flag-icons "^1.0.2" - input-format "^0.3.7" - libphonenumber-js "^1.9.47" - prop-types "^15.7.2" - - react-query@^3.33.7: - version "3.34.16" - resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.34.16.tgz#279ea180bcaeaec49c7864b29d1711ee9f152594" - integrity sha512-7FvBvjgEM4YQ8nPfmAr+lJfbW95uyW/TVjFoi2GwCkF33/S8ajx45tuPHPFGWs4qYwPy1mzwxD4IQfpUDrefNQ== - dependencies: - "@babel/runtime" "^7.5.5" - broadcast-channel "^3.4.1" - match-sorter "^6.0.2" - - react-remove-scroll-bar@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/react-remove-scroll-bar/-/react-remove-scroll-bar-2.2.0.tgz#d4d545a7df024f75d67e151499a6ab5ac97c8cdd" - integrity sha512-UU9ZBP1wdMR8qoUs7owiVcpaPwsQxUDC2lypP6mmixaGlARZa7ZIBx1jcuObLdhMOvCsnZcvetOho0wzPa9PYg== - dependencies: - react-style-singleton "^2.1.0" - tslib "^1.0.0" - - react-remove-scroll@^2.4.0: - version "2.4.4" - resolved "https://registry.yarnpkg.com/react-remove-scroll/-/react-remove-scroll-2.4.4.tgz#2dfff377cf17efc00de39dad51c143fc7a1b9e3e" - integrity sha512-EyC5ohYhaeKbThMSQxuN2i+QC5HqV3AJvNZKEdiATITexu0gHm00+5ko0ltNS1ajYJVeDgVG2baRSCei0AUWlQ== - dependencies: - react-remove-scroll-bar "^2.1.0" - react-style-singleton "^2.1.0" - tslib "^1.0.0" - use-callback-ref "^1.2.3" - use-sidecar "^1.0.1" - - react-router-dom@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.3.0.tgz#da1bfb535a0e89a712a93b97dd76f47ad1f32363" - integrity sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ== - dependencies: - "@babel/runtime" "^7.12.13" - history "^4.9.0" - loose-envify "^1.3.1" - prop-types "^15.6.2" - react-router "5.2.1" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - - react-router@5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/react-router/-/react-router-5.2.1.tgz#4d2e4e9d5ae9425091845b8dbc6d9d276239774d" - integrity sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ== - dependencies: - "@babel/runtime" "^7.12.13" - history "^4.9.0" - hoist-non-react-statics "^3.1.0" - loose-envify "^1.3.1" - mini-create-react-context "^0.4.0" - path-to-regexp "^1.7.0" - prop-types "^15.6.2" - react-is "^16.6.0" - tiny-invariant "^1.0.2" - tiny-warning "^1.0.0" - - react-select@^5.2.1, react-select@^5.2.2: - version "5.2.2" - resolved "https://registry.yarnpkg.com/react-select/-/react-select-5.2.2.tgz#3d5edf0a60f1276fd5f29f9f90a305f0a25a5189" - integrity sha512-miGS2rT1XbFNjduMZT+V73xbJEeMzVkJOz727F6MeAr2hKE0uUSA8Ff7vD44H32x2PD3SRB6OXTY/L+fTV3z9w== - dependencies: - "@babel/runtime" "^7.12.0" - "@emotion/cache" "^11.4.0" - "@emotion/react" "^11.1.1" - "@types/react-transition-group" "^4.4.0" - memoize-one "^5.0.0" - prop-types "^15.6.0" - react-transition-group "^4.3.0" - - react-ssr-prepass@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/react-ssr-prepass/-/react-ssr-prepass-1.5.0.tgz#bc4ca7fcb52365e6aea11cc254a3d1bdcbd030c5" - integrity sha512-yFNHrlVEReVYKsLI5lF05tZoHveA5pGzjFbFJY/3pOqqjGOmMmqx83N4hIjN2n6E1AOa+eQEUxs3CgRnPmT0RQ== - - react-style-singleton@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/react-style-singleton/-/react-style-singleton-2.1.1.tgz#ce7f90b67618be2b6b94902a30aaea152ce52e66" - integrity sha512-jNRp07Jza6CBqdRKNgGhT3u9umWvils1xsuMOjZlghBDH2MU0PL2WZor4PGYjXpnRCa9DQSlHMs/xnABWOwYbA== - dependencies: - get-nonce "^1.0.0" - invariant "^2.2.4" - tslib "^1.0.0" - - react-timezone-select@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/react-timezone-select/-/react-timezone-select-1.3.1.tgz#844fc8825826865d68451426d77902532f472017" - integrity sha512-ydNax+6+nJcOOE5lZA4EfkU7wcHz/b/2KK7dEfSUmnUjlHnZKSO/rf1x3SOX8EgNNrWM/Pn8BbPIPqbM0Vu1iQ== - dependencies: - react-select "^5.2.2" - spacetime "^6.16.3" - timezone-soft "^1.3.1" - - react-transition-group@^4.3.0: - version "4.4.2" - resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.2.tgz#8b59a56f09ced7b55cbd53c36768b922890d5470" - integrity sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg== - dependencies: - "@babel/runtime" "^7.5.5" - dom-helpers "^5.0.1" - loose-envify "^1.4.0" - prop-types "^15.6.2" - - react-twemoji@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/react-twemoji/-/react-twemoji-0.3.0.tgz#8c8d5aedec8dda5cc0538043639073bcdd44c3a8" - integrity sha512-y2ZQD3KvpZklETxz9c1NycRdUVF5nKsJ0bPNW3SaRJT+ReK36sMcneYwRPfv9EK2p3s9ph/NczDglnB8wbMJ0g== - dependencies: - lodash.isequal "^4.5.0" - prop-types "^15.7.2" - twemoji "^13.0.1" - - react-use-intercom@1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/react-use-intercom/-/react-use-intercom-1.4.0.tgz#796527728c131ebf132186385bf78f69dbcd84cc" - integrity sha512-HqPp7nRnftREE01i88w2kYWOV45zvJt0Of6jtHflIBa3eKl1bAs/izZUINGCJ0DOdgAdlbLweAvJlP4VTzsJjQ== - - react-virtualized-auto-sizer@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.6.tgz#66c5b1c9278064c5ef1699ed40a29c11518f97ca" - integrity sha512-7tQ0BmZqfVF6YYEWcIGuoR3OdYe8I/ZFbNclFlGOC3pMqunkYF/oL30NCjSGl9sMEb17AnzixDz98Kqc3N76HQ== - - react-window@^1.8.6: - version "1.8.6" - resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.6.tgz#d011950ac643a994118632665aad0c6382e2a112" - integrity sha512-8VwEEYyjz6DCnGBsd+MgkD0KJ2/OXFULyDtorIiTz+QzwoP94tBoA7CnbtyXMm+cCeAUER5KJcPtWl9cpKbOBg== - dependencies: - "@babel/runtime" "^7.0.0" - memoize-one ">=3.1.1 <6" - - react@17.0.2, react@^17.0.2: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" - integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - - read-pkg-up@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" - integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== - dependencies: - find-up "^4.1.0" - read-pkg "^5.2.0" - type-fest "^0.8.1" - - read-pkg@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" - integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= - dependencies: - load-json-file "^4.0.0" - normalize-package-data "^2.3.2" - path-type "^3.0.0" - - read-pkg@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" - integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== - dependencies: - "@types/normalize-package-data" "^2.4.0" - normalize-package-data "^2.5.0" - parse-json "^5.0.0" - type-fest "^0.6.0" - - readable-stream@^1.0.26-4: - version "1.1.14" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" - integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - - readable-stream@^2.0.0, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5: - version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" - integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - - readable-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" - - readable-stream@~1.0.26, readable-stream@~1.0.26-4: - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - integrity sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw= - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - - readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - - redis-errors@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" - integrity sha1-62LSrbFeTq9GEMBK/hUpOEJQq60= - - redis-parser@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/redis-parser/-/redis-parser-3.0.0.tgz#b66d828cdcafe6b4b8a428a7def4c6bcac31c8b4" - integrity sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ= - dependencies: - redis-errors "^1.0.0" - - redis@4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/redis/-/redis-4.0.1.tgz#c020e2ac7f83f0c1d42ced50b8a7af28164bd6ee" - integrity sha512-qfcq1oz2ci7pNdCfTLLEuKhS8jZ17dFiT1exogOr+jd3EVP/h9qpy7K+VajB4BXA0k8q68KFqR6HrliKV6jt1Q== - dependencies: - "@node-redis/client" "^1.0.1" - "@node-redis/json" "^1.0.1" - "@node-redis/search" "^1.0.1" - "@node-redis/time-series" "^1.0.0" - - reflect-metadata@0.1.13, reflect-metadata@^0.1.13: - version "0.1.13" - resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" - integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== - - regenerate-unicode-properties@^10.0.1: - version "10.0.1" - resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz#7f442732aa7934a3740c779bb9b3340dccc1fb56" - integrity sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw== - dependencies: - regenerate "^1.4.2" - - regenerate@^1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" - integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== - - regenerator-runtime@^0.13.3, regenerator-runtime@^0.13.4: - version "0.13.9" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" - integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== - - regenerator-transform@^0.14.2: - version "0.14.5" - resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.5.tgz#c98da154683671c9c4dcb16ece736517e1b7feb4" - integrity sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw== - dependencies: - "@babel/runtime" "^7.8.4" - - regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - - regexp.prototype.flags@^1.3.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz#b3f4c0059af9e47eca9f3f660e51d81307e72307" - integrity sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - - regexpp@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - - regexpu-core@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.0.1.tgz#c531122a7840de743dcf9c83e923b5560323ced3" - integrity sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw== - dependencies: - regenerate "^1.4.2" - regenerate-unicode-properties "^10.0.1" - regjsgen "^0.6.0" - regjsparser "^0.8.2" - unicode-match-property-ecmascript "^2.0.0" - unicode-match-property-value-ecmascript "^2.0.0" - - regjsgen@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.6.0.tgz#83414c5354afd7d6627b16af5f10f41c4e71808d" - integrity sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA== - - regjsparser@^0.8.2: - version "0.8.4" - resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.8.4.tgz#8a14285ffcc5de78c5b95d62bbf413b6bc132d5f" - integrity sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA== - dependencies: - jsesc "~0.5.0" - - remark-gfm@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/remark-gfm/-/remark-gfm-1.0.0.tgz#9213643001be3f277da6256464d56fd28c3b3c0d" - integrity sha512-KfexHJCiqvrdBZVbQ6RopMZGwaXz6wFJEfByIuEwGf0arvITHjiKKZ1dpXujjH9KZdm1//XJQwgfnJ3lmXaDPA== - dependencies: - mdast-util-gfm "^0.1.0" - micromark-extension-gfm "^0.3.0" - - remark-html@^14.0.1: - version "14.0.1" - resolved "https://registry.yarnpkg.com/remark-html/-/remark-html-14.0.1.tgz#2118516604c1a6c2ea9d5914a526942554e04e30" - integrity sha512-a/x5bTlFrkwYkz43zuJIk0m0IuS5Rx8zLztGwdzmAdUj0Hsi4C4nkJ8gTQRNXY/ET/gMrqQORMMI0arRItq/aQ== - dependencies: - "@types/mdast" "^3.0.0" - hast-util-sanitize "^4.0.0" - hast-util-to-html "^8.0.0" - mdast-util-to-hast "^11.0.0" - unified "^10.0.0" - - remark-mdx@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/remark-mdx/-/remark-mdx-2.0.0.tgz#bd921780c19ce3e51941e54b1e6388440ed499b3" - integrity sha512-TDnjSv77Oynf+K1deGWZPKSwh3/9hykVAxVm9enAw6BmicCGklREET8s19KYnjGsNPms0pNDJLmp+bnHDVItAQ== - dependencies: - mdast-util-mdx "^2.0.0" - micromark-extension-mdxjs "^1.0.0" - - remark-parse@^10.0.0: - version "10.0.1" - resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-10.0.1.tgz#6f60ae53edbf0cf38ea223fe643db64d112e0775" - integrity sha512-1fUyHr2jLsVOkhbvPRBJ5zTKZZyD6yZzYaWCS6BPBdQ8vEMBCH+9zNCDA6tET/zHCi/jLqjCWtlJZUPk+DbnFw== - dependencies: - "@types/mdast" "^3.0.0" - mdast-util-from-markdown "^1.0.0" - unified "^10.0.0" - - remark-parse@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-9.0.0.tgz#4d20a299665880e4f4af5d90b7c7b8a935853640" - integrity sha512-geKatMwSzEXKHuzBNU1z676sGcDcFoChMK38TgdHJNAYfFtsfHDQG7MoJAjs6sgYMqyLduCYWDIWZIxiPeafEw== - dependencies: - mdast-util-from-markdown "^0.8.0" - - remark-rehype@^10.0.0: - version "10.1.0" - resolved "https://registry.yarnpkg.com/remark-rehype/-/remark-rehype-10.1.0.tgz#32dc99d2034c27ecaf2e0150d22a6dcccd9a6279" - integrity sha512-EFmR5zppdBp0WQeDVZ/b66CWJipB2q2VLNFMabzDSGR66Z2fQii83G5gTBbgGEnEEA0QRussvrFHxk1HWGJskw== - dependencies: - "@types/hast" "^2.0.0" - "@types/mdast" "^3.0.0" - mdast-util-to-hast "^12.1.0" - unified "^10.0.0" - - remark-stringify@^10.0.0: - version "10.0.2" - resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-10.0.2.tgz#50414a6983f5008eb9e72eed05f980582d1f69d7" - integrity sha512-6wV3pvbPvHkbNnWB0wdDvVFHOe1hBRAx1Q/5g/EpH4RppAII6J8Gnwe7VbHuXaoKIF6LAg6ExTel/+kNqSQ7lw== - dependencies: - "@types/mdast" "^3.0.0" - mdast-util-to-markdown "^1.0.0" - unified "^10.0.0" - - remark-stringify@^9.0.0: - version "9.0.1" - resolved "https://registry.yarnpkg.com/remark-stringify/-/remark-stringify-9.0.1.tgz#576d06e910548b0a7191a71f27b33f1218862894" - integrity sha512-mWmNg3ZtESvZS8fv5PTvaPckdL4iNlCHTt8/e/8oN08nArHRHjNZMKzA/YW3+p7/lYqIw4nx1XsjCBo/AxNChg== - dependencies: - mdast-util-to-markdown "^0.6.0" - - remark@^13.0.0: - version "13.0.0" - resolved "https://registry.yarnpkg.com/remark/-/remark-13.0.0.tgz#d15d9bf71a402f40287ebe36067b66d54868e425" - integrity sha512-HDz1+IKGtOyWN+QgBiAT0kn+2s6ovOxHyPAFGKVE81VSzJ+mq7RwHFledEvB5F1p4iJvOah/LOKdFuzvRnNLCA== - dependencies: - remark-parse "^9.0.0" - remark-stringify "^9.0.0" - unified "^9.1.0" - - remark@^14.0.1: - version "14.0.2" - resolved "https://registry.yarnpkg.com/remark/-/remark-14.0.2.tgz#4a1833f7441a5c29e44b37bb1843fb820797b40f" - integrity sha512-A3ARm2V4BgiRXaUo5K0dRvJ1lbogrbXnhkJRmD0yw092/Yl0kOCZt1k9ZeElEwkZsWGsMumz6qL5MfNJH9nOBA== - dependencies: - "@types/mdast" "^3.0.0" - remark-parse "^10.0.0" - remark-stringify "^10.0.0" - unified "^10.0.0" - - remove-accents@0.4.2: - version "0.4.2" - resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.4.2.tgz#0a43d3aaae1e80db919e07ae254b285d9e1c7bb5" - integrity sha1-CkPTqq4egNuRngeuJUsoXZ4ce7U= - - remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= - - repeat-element@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" - integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== - - repeat-string@^1.0.0, repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= - - request@^2.79.0: - version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" - integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - - require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= - - require-main-filename@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" - integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== - - reselect@^4.0.0: - version "4.1.5" - resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.5.tgz#852c361247198da6756d07d9296c2b51eddb79f6" - integrity sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ== - - 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-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-pathname@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" - integrity sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng== - - resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= - - 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.0, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.14.2, resolve@^1.18.1, resolve@^1.20.0, resolve@^1.22.0: - version "1.22.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.0.tgz#5e0b8c67c15df57a89bdbabe603a002f21731198" - integrity sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw== - dependencies: - is-core-module "^2.8.1" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - - resolve@^2.0.0-next.3: - version "2.0.0-next.3" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.3.tgz#d41016293d4a8586a39ca5d9b5f15cbea1f55e46" - integrity sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q== - dependencies: - is-core-module "^2.2.0" - path-parse "^1.0.6" - - responselike@1.0.2, responselike@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" - integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= - dependencies: - lowercase-keys "^1.0.0" - - restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - - ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - - retry@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" - integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= - - reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - - rfdc@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" - integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== - - rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - - ripemd160@2.0.2, ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" - integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - - rlp@^2.2.4: - version "2.2.7" - resolved "https://registry.yarnpkg.com/rlp/-/rlp-2.2.7.tgz#33f31c4afac81124ac4b283e2bd4d9720b30beaf" - integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== - dependencies: - bn.js "^5.2.0" - - rollup-plugin-node-builtins@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/rollup-plugin-node-builtins/-/rollup-plugin-node-builtins-2.1.2.tgz#24a1fed4a43257b6b64371d8abc6ce1ab14597e9" - integrity sha1-JKH+1KQyV7a2Q3HYq8bOGrFFl+k= - dependencies: - browserify-fs "^1.0.0" - buffer-es6 "^4.9.2" - crypto-browserify "^3.11.0" - process-es6 "^0.11.2" - - rollup-plugin-polyfill-node@0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/rollup-plugin-polyfill-node/-/rollup-plugin-polyfill-node-0.8.0.tgz#859c070822f5e38d221e5b4238cb34aa894c2b19" - integrity sha512-C4UeKedOmOBkB3FgR+z/v9kzRwV1Q/H8xWs1u1+CNe4XOV6hINfOrcO+TredKxYvopCmr+WKUSNsFUnD1RLHgQ== - dependencies: - "@rollup/plugin-inject" "^4.0.0" - - rsvp@^4.8.4: - version "4.8.5" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" - integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== - - run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - - rxjs@^7.5.5: - version "7.5.5" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.5.tgz#2ebad89af0f560f460ad5cc4213219e1f7dd4e9f" - integrity sha512-sy+H0pQofO95VDmFLzyaw9xNJU4KTRSwQIGM6+iG3SypAtCiLDzpeG8sJrNCWn2Up9km+KhkvTdbkrdy+yzZdw== - dependencies: - tslib "^2.1.0" - - sade@^1.7.3: - version "1.8.1" - resolved "https://registry.yarnpkg.com/sade/-/sade-1.8.1.tgz#0a78e81d658d394887be57d2a409bf703a3b2701" - integrity sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A== - dependencies: - mri "^1.1.0" - - safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, 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== - - safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - - safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= - dependencies: - ret "~0.1.10" - - "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - - sane@^4.0.3: - version "4.1.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" - integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== - dependencies: - "@cnakazawa/watch" "^1.0.3" - anymatch "^2.0.0" - capture-exit "^2.0.0" - exec-sh "^0.3.2" - execa "^1.0.0" - fb-watchman "^2.0.0" - micromatch "^3.1.4" - minimist "^1.1.1" - walker "~1.0.5" - - saslprep@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" - integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag== - dependencies: - sparse-bitfield "^3.0.3" - - sax@>=0.6.0, sax@^1.2.4: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - - saxes@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" - integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== - dependencies: - xmlchars "^2.2.0" - - scheduler@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" - integrity sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ== - dependencies: - loose-envify "^1.1.0" - object-assign "^4.1.1" - - scrypt-js@^3.0.0, scrypt-js@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/scrypt-js/-/scrypt-js-3.0.1.tgz#d314a57c2aef69d1ad98a138a21fe9eafa9ee312" - integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== - - secp256k1@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.3.tgz#c4559ecd1b8d3c1827ed2d1b94190d69ce267303" - integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA== - dependencies: - elliptic "^6.5.4" - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - - section-matter@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/section-matter/-/section-matter-1.0.0.tgz#e9041953506780ec01d59f292a19c7b850b84167" - integrity sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA== - dependencies: - extend-shallow "^2.0.1" - kind-of "^6.0.0" - - seek-bzip@^1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/seek-bzip/-/seek-bzip-1.0.6.tgz#35c4171f55a680916b52a07859ecf3b5857f21c4" - integrity sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ== - dependencies: - commander "^2.8.1" - - "semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.6.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - - semver@7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e" - integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A== - - semver@7.x, semver@^7.3.2, semver@^7.3.5: - version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" - integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== - dependencies: - lru-cache "^6.0.0" - - semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" - integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== - - semver@~2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/semver/-/semver-2.3.2.tgz#b9848f25d6cf36333073ec9ef8856d42f1233e52" - integrity sha1-uYSPJdbPNjMwc+ye+IVtQvEjPlI= - - send@0.17.2: - version "0.17.2" - resolved "https://registry.yarnpkg.com/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820" - integrity sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww== - dependencies: - debug "2.6.9" - depd "~1.1.2" - destroy "~1.0.4" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "1.8.1" - mime "1.6.0" - ms "2.1.3" - on-finished "~2.3.0" - range-parser "~1.2.1" - statuses "~1.5.0" - - seq-queue@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e" - integrity sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4= - - serve-static@1.14.2: - version "1.14.2" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.2.tgz#722d6294b1d62626d41b43a013ece4598d292bfa" - integrity sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ== - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.17.2" - - servify@^0.1.12: - version "0.1.12" - resolved "https://registry.yarnpkg.com/servify/-/servify-0.1.12.tgz#142ab7bee1f1d033b66d0707086085b17c06db95" - integrity sha512-/xE6GvsKKqyo1BAY+KxOWXcLpPsUUyji7Qg3bVD7hh1eRze5bR1uYiuDA/k3Gof1s9BTzQZEJK8sNcNGFIzeWw== - dependencies: - body-parser "^1.16.0" - cors "^2.8.1" - express "^4.14.0" - request "^2.79.0" - xhr "^2.3.3" - - set-blocking@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" - integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= - - set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - - setimmediate@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= - - setprototypeof@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" - integrity sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ= - - setprototypeof@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" - integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== - - sha.js@^2.4.0, sha.js@^2.4.11, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - - shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= - dependencies: - shebang-regex "^1.0.0" - - shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - - shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= - - shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - - shell-quote@^1.6.1: - version "1.7.3" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123" - integrity sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw== - - shellwords@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" - integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== - - short-uuid@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/short-uuid/-/short-uuid-4.2.0.tgz#3706d9e7287ac589dc5ffe324d3e34817a07540b" - integrity sha512-r3cxuPPZSuF0QkKsK9bBR7u+7cwuCRzWzgjPh07F5N2iIUNgblnMHepBY16xgj5t1lG9iOP9k/TEafY1qhRzaw== - dependencies: - any-base "^1.1.0" - uuid "^8.3.2" - - side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== - dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" - - signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: - version "3.0.7" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - - simple-concat@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" - integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== - - simple-get@^2.7.0: - version "2.8.2" - resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.2.tgz#5708fb0919d440657326cd5fe7d2599d07705019" - integrity sha512-Ijd/rV5o+mSBBs4F/x9oDPtTx9Zb6X9brmnXvMW4J7IR15ngi9q5xxqWBKU744jTZiaXtxaPL7uHG6vtN8kUkw== - dependencies: - decompress-response "^3.3.0" - once "^1.3.1" - simple-concat "^1.0.0" - - sirv@^1.0.7: - version "1.0.19" - resolved "https://registry.yarnpkg.com/sirv/-/sirv-1.0.19.tgz#1d73979b38c7fe91fcba49c85280daa9c2363b49" - integrity sha512-JuLThK3TnZG1TAKDwNIqNq6QA2afLOCcm+iE8D1Kj3GA40pSPsxQjjJl0J8X3tsR7T+CP1GavpzLwYkgVLWrZQ== - dependencies: - "@polka/url" "^1.0.0-next.20" - mrmime "^1.0.0" - totalist "^1.0.0" - - sisteransi@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" - integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== - - slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - - slice-ansi@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" - integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - - slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - - slice-ansi@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" - integrity sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== - dependencies: - ansi-styles "^6.0.0" - is-fullwidth-code-point "^4.0.0" - - smart-buffer@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" - integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== - - snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - - snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - - snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - - socket.io-parser@*: - version "4.1.2" - resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-4.1.2.tgz#0a97d4fb8e67022158a568450a6e41887e42035e" - integrity sha512-j3kk71QLJuyQ/hh5F/L2t1goqzdTL0gvDzuhTuNSwihfuFUrcSji0qFZmJJPtG6Rmug153eOPsUizeirf1IIog== - dependencies: - "@socket.io/component-emitter" "~3.0.0" - debug "~4.3.1" - - socks-proxy-agent@6.1.1: - version "6.1.1" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.1.1.tgz#e664e8f1aaf4e1fb3df945f09e3d94f911137f87" - integrity sha512-t8J0kG3csjA4g6FTbsMOWws+7R7vuRC8aQ/wy3/1OWmsgwA68zs/+cExQ0koSitUDXqhufF/YJr9wtNMZHw5Ew== - dependencies: - agent-base "^6.0.2" - debug "^4.3.1" - socks "^2.6.1" - - socks@^2.6.1: - version "2.6.2" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.2.tgz#ec042d7960073d40d94268ff3bb727dc685f111a" - integrity sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA== - dependencies: - ip "^1.1.5" - smart-buffer "^4.2.0" - - sort-keys-length@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/sort-keys-length/-/sort-keys-length-1.0.1.tgz#9cb6f4f4e9e48155a6aa0671edd336ff1479a188" - integrity sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg= - dependencies: - sort-keys "^1.0.0" - - sort-keys@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" - integrity sha1-RBttTTRnmPG05J6JIK37oOVD+a0= - dependencies: - is-plain-obj "^1.0.0" - - sort-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" - integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= - dependencies: - is-plain-obj "^1.0.0" - - source-map-js@^1.0.1, source-map-js@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" - integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== - - source-map-resolve@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" - integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== - dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" - - source-map-support@0.4.18: - version "0.4.18" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.18.tgz#0286a6de8be42641338594e97ccea75f0a2c585f" - integrity sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA== - dependencies: - source-map "^0.5.6" - - source-map-support@^0.5.21, source-map-support@^0.5.6: - version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - - source-map-url@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" - integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== - - source-map@^0.5.0, source-map@^0.5.6, source-map@^0.5.7: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= - - source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - - source-map@^0.7.0, source-map@^0.7.3: - version "0.7.3" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" - integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== - - sourcemap-codec@^1.4.8: - version "1.4.8" - resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" - integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== - - space-separated-tokens@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-2.0.1.tgz#43193cec4fb858a2ce934b7f98b7f2c18107098b" - integrity sha512-ekwEbFp5aqSPKaqeY1PGrlGQxPNaq+Cnx4+bE2D8sciBQrHpbwoBbawqTN2+6jPs9IdWxxiUcN0K2pkczD3zmw== - - spacetime@^6.16.3: - version "6.16.3" - resolved "https://registry.yarnpkg.com/spacetime/-/spacetime-6.16.3.tgz#86d3b05db33421a9ee478b1f2ca025582fc61fcf" - integrity sha512-JQEfj3VHT1gU1IMV5NvhgAP8P+2mDFd84ZCiHN//dp6hRKmuW0IizHissy62lO0nilfFjVhnoSaMC7te+Y5f4A== - - sparse-bitfield@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" - integrity sha1-/0rm5oZWBWuks+eSqzM004JzyhE= - dependencies: - memory-pager "^1.0.2" - - spdx-correct@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" - integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - - spdx-exceptions@^2.1.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" - integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== - - spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - - spdx-license-ids@^3.0.0: - version "3.0.11" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95" - integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g== - - split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - - split2@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/split2/-/split2-4.1.0.tgz#101907a24370f85bb782f08adaabe4e281ecf809" - integrity sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ== - - sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - - sqlstring@^2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.3.tgz#2ddc21f03bce2c387ed60680e739922c65751d0c" - integrity sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg== - - sshpk@^1.7.0: - version "1.17.0" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" - integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - - stack-utils@2.0.5, stack-utils@^2.0.2, 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" - - static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - - "statuses@>= 1.3.1 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - - strict-uri-encode@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" - integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM= - - string-argv@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" - integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== - - 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-range@~1.2, string-range@~1.2.1: - version "1.2.2" - resolved "https://registry.yarnpkg.com/string-range/-/string-range-1.2.2.tgz#a893ed347e72299bc83befbbf2a692a8d239d5dd" - integrity sha1-qJPtNH5yKZvIO++78qaSqNI51d0= - - string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - - string-width@^5.0.0: - version "5.1.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" - integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== - dependencies: - eastasianwidth "^0.2.0" - emoji-regex "^9.2.2" - strip-ansi "^7.0.1" - - string.prototype.matchall@^4.0.6: - version "4.0.6" - resolved "https://registry.yarnpkg.com/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz#5abb5dabc94c7b0ea2380f65ba610b3a544b15fa" - integrity sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - get-intrinsic "^1.1.1" - has-symbols "^1.0.2" - internal-slot "^1.0.3" - regexp.prototype.flags "^1.3.1" - side-channel "^1.0.4" - - string.prototype.padend@^3.0.0: - version "3.1.3" - resolved "https://registry.yarnpkg.com/string.prototype.padend/-/string.prototype.padend-3.1.3.tgz#997a6de12c92c7cb34dc8a201a6c53d9bd88a5f1" - integrity sha512-jNIIeokznm8SD/TZISQsZKYu7RJyheFNt84DUPrh482GC8RVp2MKqm2O5oBRdGxbDQoXrhhWtPIWQOiy20svUg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.1" - - string.prototype.trimend@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" - integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - - string.prototype.trimstart@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" - integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.3" - - 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" - integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= - - string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - - stringify-entities@^4.0.0, stringify-entities@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/stringify-entities/-/stringify-entities-4.0.2.tgz#13d113dc7449dc8ae4cb22c28883ee3fff8753e3" - integrity sha512-MTxTVcEkorNtBbNpoFJPEh0kKdM6+QbMjLbaxmvaPMmayOXdr/AIVIIJX7FReUVweRBFJfZepK4A4AKgwuFpMQ== - dependencies: - character-entities-html4 "^2.0.0" - character-entities-legacy "^3.0.0" - - strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - - strip-ansi@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" - integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw== - dependencies: - ansi-regex "^6.0.1" - - strip-bom-string@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" - integrity sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI= - - strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - - 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-dirs@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/strip-dirs/-/strip-dirs-2.1.0.tgz#4987736264fc344cf20f6c34aca9d13d1d4ed6c5" - integrity sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g== - dependencies: - is-natural-number "^4.0.1" - - strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= - - 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-hex-prefix@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz#0c5f155fef1151373377de9dbb588da05500e36f" - integrity sha1-DF8VX+8RUTczd96du1iNoFUA428= - dependencies: - is-hex-prefixed "1.0.0" - - strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - - strip-markdown@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/strip-markdown/-/strip-markdown-4.2.0.tgz#2a26eadf6cd358ac18faa7f53f60ccae10cbf120" - integrity sha512-sZYHI1KoKOOBfIq78R3E62NHg7kk6aKtZSqiH7wWxFB6Ak6PTZe4N88aJnzjV00Lbfw91oyLpy3baYfTTqNYBA== - - strip-outer@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-outer/-/strip-outer-1.0.1.tgz#b2fd2abf6604b9d1e6013057195df836b8a9d631" - integrity sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg== - dependencies: - escape-string-regexp "^1.0.2" - - stripe@*, stripe@^8.191.0: - version "8.209.0" - resolved "https://registry.yarnpkg.com/stripe/-/stripe-8.209.0.tgz#a8f34132fb4140bdf9152943b15c641ad99cd3b1" - integrity sha512-ozfs8t0fxA/uvCK1DNvitSdEublOHK5CTRsrd2AWWk9LogjXcfkxmtz3KGSSQd+jyA2+rbee9TMzhJ6aabQ5WQ== - dependencies: - "@types/node" ">=8.1.0" - qs "^6.6.0" - - style-to-object@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/style-to-object/-/style-to-object-0.3.0.tgz#b1b790d205991cc783801967214979ee19a76e46" - integrity sha512-CzFnRRXhzWIdItT3OmF8SQfWyahHhjq3HwcMNCNLn+N7klOOqPjMeG/4JSu77D7ypZdGvSzvkrbyeTMizz2VrA== - dependencies: - inline-style-parser "0.1.1" - - styled-jsx@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.0.tgz#816b4b92e07b1786c6b7111821750e0ba4d26e77" - integrity sha512-qUqsWoBquEdERe10EW8vLp3jT25s/ssG1/qX5gZ4wu15OZpmSMFI2v+fWlRhLfykA5rFtlJ1ME8A8pm/peV4WA== - - stylis@4.0.13: - version "4.0.13" - resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.0.13.tgz#f5db332e376d13cc84ecfe5dace9a2a51d954c91" - integrity sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag== - - superjson@1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/superjson/-/superjson-1.8.1.tgz#c0fe510b8ff71c3bde5733a125623994ca9ec608" - integrity sha512-RaBKdbsYj29Ky+XcdE11pJAyKXPrqiCV269koH2WAlpeHh/9qnK0ET84GiVWvnutiufyDolK/vS2jtdFYr341w== - dependencies: - debug "^4.3.1" - lodash.clonedeep "^4.5.0" - - supports-color@^4.0.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b" - integrity sha1-vnoN5ITexcXN34s9WRJQRJEvY1s= - dependencies: - has-flag "^2.0.0" - - supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - - supports-color@^7.0.0, supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - - supports-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-color@^9.2.1: - version "9.2.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-9.2.1.tgz#599dc9d45acf74c6176e0d880bab1d7d718fe891" - integrity sha512-Obv7ycoCTG51N7y175StI9BlAXrmgZrFhZOb0/PyjHBher/NmsdBgbbQ1Inhq+gIhz6+7Gb+jWF2Vqi7Mf1xnQ== - - 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== - - swarm-js@^0.1.40: - version "0.1.40" - resolved "https://registry.yarnpkg.com/swarm-js/-/swarm-js-0.1.40.tgz#b1bc7b6dcc76061f6c772203e004c11997e06b99" - integrity sha512-yqiOCEoA4/IShXkY3WKwP5PvZhmoOOD8clsKA7EEcRILMkTEYHCQ21HDCAcVpmIxZq4LyZvWeRJ6quIyHk1caA== - dependencies: - bluebird "^3.5.0" - buffer "^5.0.5" - eth-lib "^0.1.26" - fs-extra "^4.0.2" - got "^7.1.0" - mime-types "^2.1.16" - mkdirp-promise "^5.0.1" - mock-fs "^4.1.0" - setimmediate "^1.0.5" - tar "^4.0.2" - xhr-request "^1.0.1" - - symbol-tree@^3.2.4: - version "3.2.4" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" - integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== - - tailwindcss@^3.0.23: - version "3.0.23" - resolved "https://registry.yarnpkg.com/tailwindcss/-/tailwindcss-3.0.23.tgz#c620521d53a289650872a66adfcb4129d2200d10" - integrity sha512-+OZOV9ubyQ6oI2BXEhzw4HrqvgcARY38xv3zKcjnWtMIZstEsXdI9xftd1iB7+RbOnj2HOEzkA0OyB5BaSxPQA== - dependencies: - arg "^5.0.1" - chalk "^4.1.2" - chokidar "^3.5.3" - color-name "^1.1.4" - cosmiconfig "^7.0.1" - detective "^5.2.0" - didyoumean "^1.2.2" - dlv "^1.1.3" - fast-glob "^3.2.11" - glob-parent "^6.0.2" - is-glob "^4.0.3" - normalize-path "^3.0.0" - object-hash "^2.2.0" - postcss "^8.4.6" - postcss-js "^4.0.0" - postcss-load-config "^3.1.0" - postcss-nested "5.0.6" - postcss-selector-parser "^6.0.9" - postcss-value-parser "^4.2.0" - quick-lru "^5.1.1" - resolve "^1.22.0" - - tapable@^2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" - integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== - - tar-stream@^1.5.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" - integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== - dependencies: - bl "^1.0.0" - buffer-alloc "^1.2.0" - end-of-stream "^1.0.0" - fs-constants "^1.0.0" - readable-stream "^2.3.0" - to-buffer "^1.1.1" - xtend "^4.0.0" - - tar@^4.0.2: - version "4.4.19" - resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3" - integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA== - dependencies: - chownr "^1.1.4" - fs-minipass "^1.2.7" - minipass "^2.9.0" - minizlib "^1.3.3" - mkdirp "^0.5.5" - safe-buffer "^5.2.1" - yallist "^3.1.1" - - 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" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= - - thenify-all@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" - integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= - dependencies: - thenify ">= 3.1.0 < 4" - - "thenify@>= 3.1.0 < 4": - version "3.3.1" - resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" - integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== - dependencies: - any-promise "^1.0.0" - - thirty-two@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/thirty-two/-/thirty-two-1.0.2.tgz#4ca2fffc02a51290d2744b9e3f557693ca6b627a" - integrity sha1-TKL//AKlEpDSdEueP1V2k8prYno= - - throat@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" - integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== - - throat@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.1.tgz#d514fedad95740c12c2d7fc70ea863eb51ade375" - integrity sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w== - - through@^2.3.8: - version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" - integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= - - thumbprint@0.0.1, thumbprint@^0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/thumbprint/-/thumbprint-0.0.1.tgz#55e86f9a9b14efb45b15c039645d47b6226bb777" - integrity sha1-VehvmpsU77RbFcA5ZF1HtiJrt3c= - - timed-out@^4.0.0, timed-out@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" - integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8= - - timezone-soft@^1.3.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/timezone-soft/-/timezone-soft-1.3.1.tgz#0e994067cbccc76a9c16b71fd8f2f94394be5b0d" - integrity sha512-mphMogFJzQy6UIpl/UgKLSNbhmLtdgbz866TnqJ/CnWnc+7dsNyAe8nPwVdOW3Mf8nT0lA32MW/gYhAl4/RkVg== - - timm@^1.6.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/timm/-/timm-1.7.1.tgz#96bab60c7d45b5a10a8a4d0f0117c6b7e5aff76f" - integrity sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw== - - tiny-invariant@^1.0.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.2.0.tgz#a1141f86b672a9148c72e978a19a73b9b94a15a9" - integrity sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg== - - tiny-warning@^1.0.0, tiny-warning@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" - integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA== - - tinycolor2@^1.4.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.2.tgz#3f6a4d1071ad07676d7fa472e1fac40a719d8803" - integrity sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA== - - title@^3.4.2: - version "3.4.4" - resolved "https://registry.yarnpkg.com/title/-/title-3.4.4.tgz#5c0ab11fd69643bc05dc006bba52aaf5c1630f5e" - integrity sha512-ViLJMyg5TFwWQ7Aqrs3e0IPINA99++cOLzQFIuBw6rKPhn8Cz7J7sdsag0BQPCf4ip7bHY1/docykbQe2R4N6Q== - dependencies: - arg "1.0.0" - chalk "2.3.0" - clipboardy "1.2.2" - titleize "1.0.0" - - titleize@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/titleize/-/titleize-1.0.0.tgz#7d350722061830ba6617631e0cfd3ea08398d95a" - integrity sha1-fTUHIgYYMLpmF2MeDP0+oIOY2Vo= - - 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-buffer@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" - integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== - - to-fast-properties@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= - - to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= - dependencies: - kind-of "^3.0.2" - - to-readable-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" - integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== - - to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - - to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - - to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - - toidentifier@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" - integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== - - toposort@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/toposort/-/toposort-2.0.2.tgz#ae21768175d1559d48bef35420b2f4962f09c330" - integrity sha1-riF2gXXRVZ1IvvNUILL0li8JwzA= - - totalist@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df" - integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g== - - tough-cookie@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" - integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== - dependencies: - psl "^1.1.33" - punycode "^2.1.1" - universalify "^0.1.2" - - tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - - tr46@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" - integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== - dependencies: - punycode "^2.1.1" - - tr46@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9" - integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA== - dependencies: - punycode "^2.1.1" - - tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= - - trim-repeated@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-repeated/-/trim-repeated-1.0.0.tgz#e3646a2ea4e891312bf7eace6cfb05380bc01c21" - integrity sha1-42RqLqTokTEr9+rObPsFOAvAHCE= - dependencies: - escape-string-regexp "^1.0.2" - - trough@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" - integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== - - trough@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/trough/-/trough-2.1.0.tgz#0f7b511a4fde65a46f18477ab38849b22c554876" - integrity sha512-AqTiAOLcj85xS7vQ8QkAV41hPDIJ71XJB4RCUrzo/1GM2CQwhkJGaf9Hgr7BOugMRpgGUrqRg/DrBDl4H40+8g== - - ts-jest@^26.0.0: - version "26.5.6" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.6.tgz#c32e0746425274e1dfe333f43cd3c800e014ec35" - integrity sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA== - dependencies: - bs-logger "0.x" - buffer-from "1.x" - fast-json-stable-stringify "2.x" - jest-util "^26.1.0" - json5 "2.x" - lodash "4.x" - make-error "1.x" - mkdirp "1.x" - semver "7.x" - yargs-parser "20.x" - - ts-morph@^13.0.2: - version "13.0.3" - resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-13.0.3.tgz#c0c51d1273ae2edb46d76f65161eb9d763444c1d" - integrity sha512-pSOfUMx8Ld/WUreoSzvMFQG5i9uEiWIsBYjpU9+TTASOeUa89j5HykomeqVULm1oqWtBdleI3KEFRLrlA3zGIw== - dependencies: - "@ts-morph/common" "~0.12.3" - code-block-writer "^11.0.0" - - ts-node@^10.6.0: - version "10.7.0" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.7.0.tgz#35d503d0fab3e2baa672a0e94f4b40653c2463f5" - integrity sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A== - dependencies: - "@cspotcode/source-map-support" "0.7.0" - "@tsconfig/node10" "^1.0.7" - "@tsconfig/node12" "^1.0.7" - "@tsconfig/node14" "^1.0.0" - "@tsconfig/node16" "^1.0.2" - acorn "^8.4.1" - acorn-walk "^8.1.1" - arg "^4.1.0" - create-require "^1.1.0" - diff "^4.0.1" - make-error "^1.1.1" - v8-compile-cache-lib "^3.0.0" - yn "3.1.1" - - tsconfig-paths@^3.12.0, tsconfig-paths@^3.9.0: - version "3.14.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.0.tgz#4fcc48f9ccea8826c41b9ca093479de7f5018976" - integrity sha512-cg/1jAZoL57R39+wiw4u/SCC6Ic9Q5NqjBOb+9xISedOYurfog9ZNmKJSxAnb2m/5Bq4lE9lhUcau33Ml8DM0g== - dependencies: - "@types/json5" "^0.0.29" - json5 "^1.0.1" - minimist "^1.2.0" - strip-bom "^3.0.0" - - tsdav@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/tsdav/-/tsdav-2.0.0.tgz#e0a91d0ad79e793885b3fdc34157bd8aeedfb0f1" - integrity sha512-ENdQyhu4T03QZxh5dhoDP7vXB8bqwpBATCA57pu61Gam5/wg+7JApQuUdGjXHGzcqSpWpD960avPCdj2M+hlLQ== - dependencies: - base-64 "1.0.0" - cross-fetch "3.1.5" - debug "4.3.3" - eslint-module-utils "2.7.3" - rollup-plugin-node-builtins "2.1.2" - rollup-plugin-polyfill-node "0.8.0" - xml-js "1.6.11" - - tslib@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.1.tgz#410eb0d113e5b6356490eec749603725b021b43e" - integrity sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ== - - tslib@2.3.1, tslib@^2.0.0, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" - integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== - - tslib@^1.0.0, tslib@^1.8.1, tslib@^1.9.3: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - - tslog@^3.2.1: - version "3.3.2" - resolved "https://registry.yarnpkg.com/tslog/-/tslog-3.3.2.tgz#ceef419054a85d992cfdd923dc04aa0ea3539e24" - integrity sha512-K+XduMfa9+yiHE/vxbUD/dL7RAbw9yIfi9tMjQj3uQ8evkPRKkmw0mQgEkzmueyg23hJHGaOQmDnCEZoKEws+w== - dependencies: - source-map-support "^0.5.21" - - tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - - tsyringe@^4.6.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/tsyringe/-/tsyringe-4.6.0.tgz#14915d3d7f0db35e1cf7269bdbf7c440713c8d07" - integrity sha512-BMQAZamSfEmIQzH8WJeRu1yZGQbPSDuI9g+yEiKZFIcO46GPZuMOC2d0b52cVBdw1d++06JnDSIIZvEnogMdAw== - dependencies: - tslib "^1.9.3" - - tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - - turbo-darwin-64@1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/turbo-darwin-64/-/turbo-darwin-64-1.1.6.tgz#1f493d9fed174e609b65c2f64028d42d095c9bb7" - integrity sha512-xzl79T7mPKaIGhMBCAzpTvXkbFNZaMyeOMsNXxVT5dTY+d3FwLFfbqHIoG1dH745TbH6i67bxtt70lKdQa+qdQ== - - turbo-darwin-arm64@1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/turbo-darwin-arm64/-/turbo-darwin-arm64-1.1.6.tgz#aa6218492de696e49c1af16bb1d13118aa85a203" - integrity sha512-r0D+Kfwcaqec5h9Xa4T/VD6mWZ2LQr+zOEBBL6UA15htgel06B2eXiGdjRiw4i7ieV80tEBEDdz9tSWJBhAL/Q== - - turbo-freebsd-64@1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/turbo-freebsd-64/-/turbo-freebsd-64-1.1.6.tgz#9a7b6affb3177f100a2315cdd81c3b2f87180287" - integrity sha512-v5MJeRcyeCDF3La40TOub0+/OuGGFuLzlVHb4jYxthESbtLve1H23bDiL+4gCQgPYOsKMOvKQpuoMaKW2gxk7A== - - turbo-freebsd-arm64@1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/turbo-freebsd-arm64/-/turbo-freebsd-arm64-1.1.6.tgz#e70e94277c7149ba95cbacd826068f46b0346727" - integrity sha512-5gm3r+M5f/Idt/pggyCQ+MZSlaUdxUeb/4LtPohhWOoj4PYo1o5kwInaRlckr7uV36E4/npDvz9cDV96Pohejg== - - turbo-linux-32@1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/turbo-linux-32/-/turbo-linux-32-1.1.6.tgz#02f072f68bb8a71e205f24cee2068ee455fb1cb1" - integrity sha512-dLc1Vd/LQP5n3NGLMf+cdaK99sMWvHdDvTUSrSwoYDy5fWFpUm0E12lAxRH3tikX2m7Kfcy2uY5xSJIuq5xzYQ== - - turbo-linux-64@1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/turbo-linux-64/-/turbo-linux-64-1.1.6.tgz#5b90ab2aa1e2e0a94f18905871d88656335f0285" - integrity sha512-V4rb41yQUA+vPDgXc06oHmKbgrBUbwm09oRtjvmlIQU8zX8qujMPZIun8tGP4NuzErJXGzD3WDgj7VSsO23IIw== - - turbo-linux-arm64@1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/turbo-linux-arm64/-/turbo-linux-arm64-1.1.6.tgz#f7e738e35b5daa7e5f82f61aa1018a39ad03501f" - integrity sha512-QsE7gow3WxWXKwNWJX4DIJys6xc6Up4/icjdTZCZbglPLwuG2UiUzjJ2+beXxVU4EmpQF6NwKubHCtrs8m8/kQ== - - turbo-linux-arm@1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/turbo-linux-arm/-/turbo-linux-arm-1.1.6.tgz#39b29c3f91a5e426fb17f1fe543ed8587b861c7b" - integrity sha512-zAaIa0+EhRYYkM51ruB1LCUqyeigK66A+KfXZ3Y9+aiKg7EYbDvuv+ReD4srLPKoIuAxR5dYlk5RVhSKejt2Cw== - - turbo-linux-mips64le@1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/turbo-linux-mips64le/-/turbo-linux-mips64le-1.1.6.tgz#b10aab67382984d728e3c2e7239bd4d9a67da9e2" - integrity sha512-098DB9daXoI6LRCkuOv1Pqim+H4wXZrFza9Xd7zJIel1WmxEgNsHqWpSH5Jn2J92LbkWl+tfN1+myw4+a4ESfw== - - turbo-linux-ppc64le@1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/turbo-linux-ppc64le/-/turbo-linux-ppc64le-1.1.6.tgz#0fa6bdcf3420ee65b4faa2755fe852390c022a5b" - integrity sha512-U5A1mnsGM994h/1VT4FbsV/bb+I0fgvkY5/TTX7MfA9Iwt0SxsNlh+Jgofe1svPz0CKEe6Hl2WQSGHTlBPJb5Q== - - turbo-windows-32@1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/turbo-windows-32/-/turbo-windows-32-1.1.6.tgz#724185a8584fa2c14edc4892056f23576aeb0317" - integrity sha512-0C+/EI11j8ABtI6O2n+NYL2osDI6moo7YL8pqiWbNrdEGI2KbeCTVQpruUH+GONsMov06pR4BouL9UT2jSpG0g== - - turbo-windows-64@1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/turbo-windows-64/-/turbo-windows-64-1.1.6.tgz#3965a5c0c55273de2882e580ca042c6564c43272" - integrity sha512-O2kC+7+zuMjFIi6mpU1qz+Bv27TcHkkCczcDNVU29G52pm5lwj7BZ+/gu+EPJSnF5VrgdA6Oru6KVXPRS1q+Cg== - - turbo@latest: - version "1.1.6" - resolved "https://registry.yarnpkg.com/turbo/-/turbo-1.1.6.tgz#dcae11bbd7a465473bdf416b82caac2b7f94d641" - integrity sha512-pZTc6Sb5MtK/X/qhiDSssc8AZWoUoYf14ZqYjvDWg/aEtqgwYorVJqfRcj4XOXOqtVZ3gO/91eXwdyh/q2aQHA== - optionalDependencies: - turbo-darwin-64 "1.1.6" - turbo-darwin-arm64 "1.1.6" - turbo-freebsd-64 "1.1.6" - turbo-freebsd-arm64 "1.1.6" - turbo-linux-32 "1.1.6" - turbo-linux-64 "1.1.6" - turbo-linux-arm "1.1.6" - turbo-linux-arm64 "1.1.6" - turbo-linux-mips64le "1.1.6" - turbo-linux-ppc64le "1.1.6" - turbo-windows-32 "1.1.6" - turbo-windows-64 "1.1.6" - - tween-functions@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/tween-functions/-/tween-functions-1.2.0.tgz#1ae3a50e7c60bb3def774eac707acbca73bbc3ff" - integrity sha1-GuOlDnxguz3vd06scHrLynO7w/8= - - tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - - twemoji-parser@13.1.0: - version "13.1.0" - resolved "https://registry.yarnpkg.com/twemoji-parser/-/twemoji-parser-13.1.0.tgz#65e7e449c59258791b22ac0b37077349127e3ea4" - integrity sha512-AQOzLJpYlpWMy8n+0ATyKKZzWlZBJN+G0C+5lhX7Ftc2PeEVdUU/7ns2Pn2vVje26AIZ/OHwFoUbdv6YYD/wGg== - - twemoji@^13.0.1: - version "13.1.1" - resolved "https://registry.yarnpkg.com/twemoji/-/twemoji-13.1.1.tgz#6e31409908bb5383cdb1d09c9c8e7856aa6e2e3b" - integrity sha512-IIIoq+n1lk1M1+evBKZD3DO0ud02fDQ4ssbgAv8rp3YBWUeNmskjlisFUPPDacQ50XS3bhrd4Kq9Q2gqhxb0dg== - dependencies: - fs-extra "^8.0.1" - jsonfile "^5.0.0" - twemoji-parser "13.1.0" - universalify "^0.1.2" - - type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - - type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= - 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.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - - type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - - type-fest@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" - integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== - - type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - - type-is@^1.6.18, type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - - type@^1.0.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" - integrity sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg== - - type@^2.5.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/type/-/type-2.6.0.tgz#3ca6099af5981d36ca86b78442973694278a219f" - integrity sha512-eiDBDOmkih5pMbo9OqsqPRGMljLodLcwd5XD5JbtNB0o89xZAwynY9EdCDsJU7LtcVCClu9DvM7/0Ep1hYX3EQ== - - typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== - dependencies: - is-typedarray "^1.0.0" - - typedarray-to-buffer@~1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-1.0.4.tgz#9bb8ba0e841fb3f4cf1fe7c245e9f3fa8a5fe99c" - integrity sha1-m7i6DoQfs/TPH+fCRenz+opf6Zw= - - typedarray@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" - integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= - - typeorm@0.2.41: - version "0.2.41" - resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.41.tgz#88758101ac158dc0a0a903d70eaacea2974281cc" - integrity sha512-/d8CLJJxKPgsnrZWiMyPI0rz2MFZnBQrnQ5XP3Vu3mswv2WPexb58QM6BEtmRmlTMYN5KFWUz8SKluze+wS9xw== - dependencies: - "@sqltools/formatter" "^1.2.2" - app-root-path "^3.0.0" - buffer "^6.0.3" - chalk "^4.1.0" - cli-highlight "^2.1.11" - debug "^4.3.1" - dotenv "^8.2.0" - glob "^7.1.6" - js-yaml "^4.0.0" - mkdirp "^1.0.4" - reflect-metadata "^0.1.13" - sha.js "^2.4.11" - tslib "^2.1.0" - xml2js "^0.4.23" - yargs "^17.0.1" - zen-observable-ts "^1.0.0" - - typescript@^4.5.3: - version "4.6.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.2.tgz#fe12d2727b708f4eef40f51598b3398baa9611d4" - integrity sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg== - - typescript@^4.6.3: - version "4.6.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.3.tgz#eefeafa6afdd31d725584c67a0eaba80f6fc6c6c" - integrity sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw== - - uglify-js@^3.1.4: - version "3.15.3" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.15.3.tgz#9aa82ca22419ba4c0137642ba0df800cb06e0471" - integrity sha512-6iCVm2omGJbsu3JWac+p6kUiOpg3wFO2f8lIXjfEb8RrmLjzog1wTPMmwKB7swfzzqxj9YM+sGUM++u1qN4qJg== - - ultron@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.1.tgz#9fe1536a10a664a65266a1e3ccf85fd36302bc9c" - integrity sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og== - - unbox-primitive@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.1.tgz#085e215625ec3162574dc8859abee78a59b14471" - integrity sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw== - dependencies: - function-bind "^1.1.1" - has-bigints "^1.0.1" - has-symbols "^1.0.2" - which-boxed-primitive "^1.0.2" - - unbzip2-stream@^1.0.9: - version "1.4.3" - resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz#b0da04c4371311df771cdc215e87f2130991ace7" - integrity sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg== - dependencies: - buffer "^5.2.1" - through "^2.3.8" - - unicode-canonical-property-names-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz#301acdc525631670d39f6146e0e77ff6bbdebddc" - integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== - - unicode-match-property-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" - integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== - dependencies: - unicode-canonical-property-names-ecmascript "^2.0.0" - unicode-property-aliases-ecmascript "^2.0.0" - - unicode-match-property-value-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz#1a01aa57247c14c568b89775a54938788189a714" - integrity sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw== - - unicode-property-aliases-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz#0a36cb9a585c4f6abd51ad1deddb285c165297c8" - integrity sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ== - - unified@^10.0.0: - version "10.1.2" - resolved "https://registry.yarnpkg.com/unified/-/unified-10.1.2.tgz#b1d64e55dafe1f0b98bb6c719881103ecf6c86df" - integrity sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q== - dependencies: - "@types/unist" "^2.0.0" - bail "^2.0.0" - extend "^3.0.0" - is-buffer "^2.0.0" - is-plain-obj "^4.0.0" - trough "^2.0.0" - vfile "^5.0.0" - - unified@^9.1.0: - version "9.2.2" - resolved "https://registry.yarnpkg.com/unified/-/unified-9.2.2.tgz#67649a1abfc3ab85d2969502902775eb03146975" - integrity sha512-Sg7j110mtefBD+qunSLO1lqOEKdrwBFBrR6Qd8f4uwkhWNlbkaqwHse6e7QvD3AP/MNoJdEDLaf8OxYyoWgorQ== - dependencies: - bail "^1.0.0" - extend "^3.0.0" - is-buffer "^2.0.0" - is-plain-obj "^2.0.0" - trough "^1.0.0" - vfile "^4.0.0" - - union-value@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - - unist-builder@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/unist-builder/-/unist-builder-3.0.0.tgz#728baca4767c0e784e1e64bb44b5a5a753021a04" - integrity sha512-GFxmfEAa0vi9i5sd0R2kcrI9ks0r82NasRq5QHh2ysGngrc6GiqD5CDf1FjPenY4vApmFASBIIlk/jj5J5YbmQ== - dependencies: - "@types/unist" "^2.0.0" - - unist-util-generated@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/unist-util-generated/-/unist-util-generated-2.0.0.tgz#86fafb77eb6ce9bfa6b663c3f5ad4f8e56a60113" - integrity sha512-TiWE6DVtVe7Ye2QxOVW9kqybs6cZexNwTwSMVgkfjEReqy/xwGpAXb99OxktoWwmL+Z+Epb0Dn8/GNDYP1wnUw== - - unist-util-is@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-4.1.0.tgz#976e5f462a7a5de73d94b706bac1b90671b57797" - integrity sha512-ZOQSsnce92GrxSqlnEEseX0gi7GH9zTJZ0p9dtu87WRb/37mMPO2Ilx1s/t9vBHrFhbgweUwb+t7cIn5dxPhZg== - - unist-util-is@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-5.1.1.tgz#e8aece0b102fa9bc097b0fef8f870c496d4a6236" - integrity sha512-F5CZ68eYzuSvJjGhCLPL3cYx45IxkqXSetCcRgUXtbcm50X2L9oOWQlfUfDdAf+6Pd27YDblBfdtmsThXmwpbQ== - - unist-util-position-from-estree@^1.0.0, unist-util-position-from-estree@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/unist-util-position-from-estree/-/unist-util-position-from-estree-1.1.1.tgz#96f4d543dfb0428edc01ebb928570b602d280c4c" - integrity sha512-xtoY50b5+7IH8tFbkw64gisG9tMSpxDjhX9TmaJJae/XuxQ9R/Kc8Nv1eOsf43Gt4KV/LkriMy9mptDr7XLcaw== - dependencies: - "@types/unist" "^2.0.0" - - unist-util-position@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/unist-util-position/-/unist-util-position-4.0.1.tgz#f8484b2da19a897a0180556d160c28633070dbb9" - integrity sha512-mgy/zI9fQ2HlbOtTdr2w9lhVaiFUHWQnZrFF2EUoVOqtAUdzqMtNiD99qA5a1IcjWVR8O6aVYE9u7Z2z1v0SQA== - - unist-util-remove-position@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-4.0.1.tgz#d5b46a7304ac114c8d91990ece085ca7c2c135c8" - integrity sha512-0yDkppiIhDlPrfHELgB+NLQD5mfjup3a8UYclHruTJWmY74je8g+CIFr79x5f6AkmzSwlvKLbs63hC0meOMowQ== - dependencies: - "@types/unist" "^2.0.0" - unist-util-visit "^4.0.0" - - unist-util-stringify-position@^2.0.0: - version "2.0.3" - resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz#cce3bfa1cdf85ba7375d1d5b17bdc4cada9bd9da" - integrity sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g== - dependencies: - "@types/unist" "^2.0.2" - - unist-util-stringify-position@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-3.0.2.tgz#5c6aa07c90b1deffd9153be170dce628a869a447" - integrity sha512-7A6eiDCs9UtjcwZOcCpM4aPII3bAAGv13E96IkawkOAW0OhH+yRxtY0lzo8KiHpzEMfH7Q+FizUmwp8Iqy5EWg== - dependencies: - "@types/unist" "^2.0.0" - - unist-util-visit-parents@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-3.1.1.tgz#65a6ce698f78a6b0f56aa0e88f13801886cdaef6" - integrity sha512-1KROIZWo6bcMrZEwiH2UrXDyalAa0uqzWCxCJj6lPOvTve2WkfgCytoDTPaMnodXh1WrXOq0haVYHj99ynJlsg== - dependencies: - "@types/unist" "^2.0.0" - unist-util-is "^4.0.0" - - unist-util-visit-parents@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-4.1.1.tgz#e83559a4ad7e6048a46b1bdb22614f2f3f4724f2" - integrity sha512-1xAFJXAKpnnJl8G7K5KgU7FY55y3GcLIXqkzUj5QF/QVP7biUm0K0O2oqVkYsdjzJKifYeWn9+o6piAK2hGSHw== - dependencies: - "@types/unist" "^2.0.0" - unist-util-is "^5.0.0" - - unist-util-visit-parents@^5.0.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-5.1.0.tgz#44bbc5d25f2411e7dfc5cecff12de43296aa8521" - integrity sha512-y+QVLcY5eR/YVpqDsLf/xh9R3Q2Y4HxkZTp7ViLDU6WtJCEcPmRzW1gpdWDCDIqIlhuPDXOgttqPlykrHYDekg== - dependencies: - "@types/unist" "^2.0.0" - unist-util-is "^5.0.0" - - unist-util-visit@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-3.1.0.tgz#9420d285e1aee938c7d9acbafc8e160186dbaf7b" - integrity sha512-Szoh+R/Ll68QWAyQyZZpQzZQm2UPbxibDvaY8Xc9SUtYgPsDzx5AWSk++UUt2hJuow8mvwR+rG+LQLw+KsuAKA== - dependencies: - "@types/unist" "^2.0.0" - unist-util-is "^5.0.0" - unist-util-visit-parents "^4.0.0" - - unist-util-visit@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-4.1.0.tgz#f41e407a9e94da31594e6b1c9811c51ab0b3d8f5" - integrity sha512-n7lyhFKJfVZ9MnKtqbsqkQEk5P1KShj0+//V7mAcoI6bpbUjh3C/OG8HVD+pBihfh6Ovl01m8dkcv9HNqYajmQ== - dependencies: - "@types/unist" "^2.0.0" - unist-util-is "^5.0.0" - unist-util-visit-parents "^5.0.0" - - universalify@^0.1.0, universalify@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" - integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== - - unload@2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7" - integrity sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA== - dependencies: - "@babel/runtime" "^7.6.2" - detect-node "^2.0.4" - - unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= - - unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - - update-input-width@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/update-input-width/-/update-input-width-1.2.2.tgz#9a6a35858ae8e66fbfe0304437b23a4934fc7d37" - integrity sha512-6QwD9ZVSXb96PxOZ01DU0DJTPwQGY7qBYgdniZKJN02Xzom2m+9J6EPxMbefskqtj4x78qbe5psDSALq9iNEYg== - - uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - - urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= - - url-parse-lax@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73" - integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM= - dependencies: - prepend-http "^1.0.1" - - url-parse-lax@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" - integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= - dependencies: - prepend-http "^2.0.0" - - url-set-query@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/url-set-query/-/url-set-query-1.0.0.tgz#016e8cfd7c20ee05cafe7795e892bd0702faa339" - integrity sha1-AW6M/Xwg7gXK/neV6JK9BwL6ozk= - - url-template@^2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21" - integrity sha1-/FZaPMy/93MMd19WQflVV5FDnyE= - - url-to-options@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-1.0.1.tgz#1505a03a289a48cbd7a434efbaeec5055f5633a9" - integrity sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k= - - use-callback-ref@^1.2.3: - version "1.2.5" - resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.2.5.tgz#6115ed242cfbaed5915499c0a9842ca2912f38a5" - integrity sha512-gN3vgMISAgacF7sqsLPByqoePooY3n2emTH59Ur5d/M8eg4WTWu1xp8i8DHjohftIyEx0S08RiYxbffr4j8Peg== - - use-sidecar@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/use-sidecar/-/use-sidecar-1.0.5.tgz#ffff2a17c1df42e348624b699ba6e5c220527f2b" - integrity sha512-k9jnrjYNwN6xYLj1iaGhonDghfvmeTmYjAiGvOr7clwKfPjMXJf4/HOr7oT5tJwYafgp2tG2l3eZEOfoELiMcA== - dependencies: - detect-node-es "^1.1.0" - tslib "^1.9.3" - - use-subscription@1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.5.1.tgz#73501107f02fad84c6dd57965beb0b75c68c42d1" - integrity sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA== - dependencies: - object-assign "^4.1.1" - - use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - - utf-8-validate@^5.0.2: - version "5.0.9" - resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.9.tgz#ba16a822fbeedff1a58918f2a6a6b36387493ea3" - integrity sha512-Yek7dAy0v3Kl0orwMlvi7TPtiCNrdfHNd7Gcc/pLq4BLXqfAmd0J7OWMizUQnTTJsyjKn02mU7anqwfmUP4J8Q== - dependencies: - node-gyp-build "^4.3.0" - - utf8@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/utf8/-/utf8-3.0.0.tgz#f052eed1364d696e769ef058b183df88c87f69d1" - integrity sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ== - - utif@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/utif/-/utif-2.0.1.tgz#9e1582d9bbd20011a6588548ed3266298e711759" - integrity sha512-Z/S1fNKCicQTf375lIP9G8Sa1H/phcysstNrrSdZKj1f9g58J4NMgb5IgiEZN9/nLMPDwF0W7hdOe9Qq2IYoLg== - dependencies: - pako "^1.0.5" - - util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= - - util@^0.12.0: - version "0.12.4" - resolved "https://registry.yarnpkg.com/util/-/util-0.12.4.tgz#66121a31420df8f01ca0c464be15dfa1d1850253" - integrity sha512-bxZ9qtSlGUWSOy9Qa9Xgk11kSslpuZwaxCg4sNIDj6FLucDab2JxnHwyNTCpHMtK1MjoQiWQ6DiUMZYbSrO+Sw== - dependencies: - inherits "^2.0.3" - is-arguments "^1.0.4" - is-generator-function "^1.0.7" - is-typed-array "^1.1.3" - safe-buffer "^5.1.2" - which-typed-array "^1.1.2" - - utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= - - uuid@3.3.2: - version "3.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131" - integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== - - uuid@^3.3.2: - version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" - integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== - - uuid@^8.0.0, uuid@^8.3.0, uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - - uvu@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/uvu/-/uvu-0.5.3.tgz#3d83c5bc1230f153451877bfc7f4aea2392219ae" - integrity sha512-brFwqA3FXzilmtnIyJ+CxdkInkY/i4ErvP7uV0DnUVxQcQ55reuHphorpF+tZoVHK2MniZ/VJzI7zJQoc9T9Yw== - dependencies: - dequal "^2.0.0" - diff "^5.0.0" - kleur "^4.0.3" - sade "^1.7.3" - - v8-compile-cache-lib@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz#0582bcb1c74f3a2ee46487ceecf372e46bce53e8" - integrity sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA== - - v8-compile-cache@^2.0.3: - version "2.3.0" - 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@^7.0.0: - version "7.1.2" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz#30898d1a7fa0c84d225a2c1434fb958f290883c1" - integrity sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" - source-map "^0.7.3" - - v8-to-istanbul@^8.1.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed" - integrity sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w== - dependencies: - "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" - source-map "^0.7.3" - - validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - - value-equal@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/value-equal/-/value-equal-1.0.1.tgz#1e0b794c734c5c0cade179c437d356d931a34d6c" - integrity sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw== - - varint@^5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/varint/-/varint-5.0.2.tgz#5b47f8a947eb668b848e034dcfa87d0ff8a7f7a4" - integrity sha512-lKxKYG6H03yCZUpAGOPOsMcGxd1RHCu1iKvEHYDPmTyq2HueGhD73ssNBqqQWfvYs04G9iUFRvmAVLW20Jw6ow== - - vary@^1, vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= - - verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - - vfile-message@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a" - integrity sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ== - dependencies: - "@types/unist" "^2.0.0" - unist-util-stringify-position "^2.0.0" - - vfile-message@^3.0.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-3.1.2.tgz#a2908f64d9e557315ec9d7ea3a910f658ac05f7d" - integrity sha512-QjSNP6Yxzyycd4SVOtmKKyTsSvClqBPJcd00Z0zuPj3hOIjg0rUPG6DbFGPvUKRgYyaIWLPKpuEclcuvb3H8qA== - dependencies: - "@types/unist" "^2.0.0" - unist-util-stringify-position "^3.0.0" - - vfile@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/vfile/-/vfile-4.2.1.tgz#03f1dce28fc625c625bc6514350fbdb00fa9e624" - integrity sha512-O6AE4OskCG5S1emQ/4gl8zK586RqA3srz3nfK/Viy0UPToBc5Trp9BVFb1u0CjsKrAWwnpr4ifM/KBXPWwJbCA== - dependencies: - "@types/unist" "^2.0.0" - is-buffer "^2.0.0" - unist-util-stringify-position "^2.0.0" - vfile-message "^2.0.0" - - vfile@^5.0.0: - version "5.3.2" - resolved "https://registry.yarnpkg.com/vfile/-/vfile-5.3.2.tgz#b499fbc50197ea50ad3749e9b60beb16ca5b7c54" - integrity sha512-w0PLIugRY3Crkgw89TeMvHCzqCs/zpreR31hl4D92y6SOE07+bfJe+dK5Q2akwS+i/c801kzjoOr9gMcTe6IAA== - dependencies: - "@types/unist" "^2.0.0" - is-buffer "^2.0.0" - unist-util-stringify-position "^3.0.0" - vfile-message "^3.0.0" - - void-elements@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" - integrity sha1-YU9/v42AHwu18GYfWy9XhXUOTwk= - - w3c-hr-time@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" - integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== - dependencies: - browser-process-hrtime "^1.0.0" - - w3c-xmlserializer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" - integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== - dependencies: - xml-name-validator "^3.0.0" - - walker@^1.0.7, walker@~1.0.5: - version "1.0.8" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" - integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== - dependencies: - makeerror "1.0.12" - - warning@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3" - integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w== - dependencies: - loose-envify "^1.0.0" - - web3-bzz@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3-bzz/-/web3-bzz-1.7.1.tgz#ea1e7d27050eca089bc5d71b7f7688d20b68a25d" - integrity sha512-sVeUSINx4a4pfdnT+3ahdRdpDPvZDf4ZT/eBF5XtqGWq1mhGTl8XaQAk15zafKVm6Onq28vN8abgB/l+TrG8kA== - dependencies: - "@types/node" "^12.12.6" - got "9.6.0" - swarm-js "^0.1.40" - - web3-core-helpers@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3-core-helpers/-/web3-core-helpers-1.7.1.tgz#6dc34eff6ad31149db6c7cc2babbf574a09970cd" - integrity sha512-xn7Sx+s4CyukOJdlW8bBBDnUCWndr+OCJAlUe/dN2wXiyaGRiCWRhuQZrFjbxLeBt1fYFH7uWyYHhYU6muOHgw== - dependencies: - web3-eth-iban "1.7.1" - web3-utils "1.7.1" - - web3-core-method@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3-core-method/-/web3-core-method-1.7.1.tgz#912c87d0f107d3f823932cf8a716852e3250e557" - integrity sha512-383wu5FMcEphBFl5jCjk502JnEg3ugHj7MQrsX7DY76pg5N5/dEzxeEMIJFCN6kr5Iq32NINOG3VuJIyjxpsEg== - dependencies: - "@ethersproject/transactions" "^5.0.0-beta.135" - web3-core-helpers "1.7.1" - web3-core-promievent "1.7.1" - web3-core-subscriptions "1.7.1" - web3-utils "1.7.1" - - web3-core-promievent@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3-core-promievent/-/web3-core-promievent-1.7.1.tgz#7f78ec100a696954d0c882dac619fec28b2efc96" - integrity sha512-Vd+CVnpPejrnevIdxhCkzMEywqgVbhHk/AmXXceYpmwA6sX41c5a65TqXv1i3FWRJAz/dW7oKz9NAzRIBAO/kA== - dependencies: - eventemitter3 "4.0.4" - - web3-core-requestmanager@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3-core-requestmanager/-/web3-core-requestmanager-1.7.1.tgz#5cd7507276ca449538fe11cb4f363de8507502e5" - integrity sha512-/EHVTiMShpZKiq0Jka0Vgguxi3vxq1DAHKxg42miqHdUsz4/cDWay2wGALDR2x3ofDB9kqp7pb66HsvQImQeag== - dependencies: - util "^0.12.0" - web3-core-helpers "1.7.1" - web3-providers-http "1.7.1" - web3-providers-ipc "1.7.1" - web3-providers-ws "1.7.1" - - web3-core-subscriptions@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3-core-subscriptions/-/web3-core-subscriptions-1.7.1.tgz#f7c834ee3544f4a5641a989304f61fde6a523e0b" - integrity sha512-NZBsvSe4J+Wt16xCf4KEtBbxA9TOwSVr8KWfUQ0tC2KMdDYdzNswl0Q9P58xaVuNlJ3/BH+uDFZJJ5E61BSA1Q== - dependencies: - eventemitter3 "4.0.4" - web3-core-helpers "1.7.1" - - web3-core@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3-core/-/web3-core-1.7.1.tgz#ef9b7f03909387b9ab783f34cdc5ebcb50248368" - integrity sha512-HOyDPj+4cNyeNPwgSeUkhtS0F+Pxc2obcm4oRYPW5ku6jnTO34pjaij0us+zoY3QEusR8FfAKVK1kFPZnS7Dzw== - dependencies: - "@types/bn.js" "^4.11.5" - "@types/node" "^12.12.6" - bignumber.js "^9.0.0" - web3-core-helpers "1.7.1" - web3-core-method "1.7.1" - web3-core-requestmanager "1.7.1" - web3-utils "1.7.1" - - web3-eth-abi@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3-eth-abi/-/web3-eth-abi-1.7.1.tgz#6632003220a4defee4de8215dc703e43147382ea" - integrity sha512-8BVBOoFX1oheXk+t+uERBibDaVZ5dxdcefpbFTWcBs7cdm0tP8CD1ZTCLi5Xo+1bolVHNH2dMSf/nEAssq5pUA== - dependencies: - "@ethersproject/abi" "5.0.7" - web3-utils "1.7.1" - - web3-eth-accounts@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3-eth-accounts/-/web3-eth-accounts-1.7.1.tgz#f938060d08f4b641bebe743809b0018fd4e4ba51" - integrity sha512-3xGQ2bkTQc7LFoqGWxp5cQDrKndlX05s7m0rAFVoyZZODMqrdSGjMPMqmWqHzJRUswNEMc+oelqSnGBubqhguQ== - dependencies: - "@ethereumjs/common" "^2.5.0" - "@ethereumjs/tx" "^3.3.2" - crypto-browserify "3.12.0" - eth-lib "0.2.8" - ethereumjs-util "^7.0.10" - scrypt-js "^3.0.1" - uuid "3.3.2" - web3-core "1.7.1" - web3-core-helpers "1.7.1" - web3-core-method "1.7.1" - web3-utils "1.7.1" - - web3-eth-contract@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3-eth-contract/-/web3-eth-contract-1.7.1.tgz#3f5147e5f1441ae388c985ba95023d02503378ae" - integrity sha512-HpnbkPYkVK3lOyos2SaUjCleKfbF0SP3yjw7l551rAAi5sIz/vwlEzdPWd0IHL7ouxXbO0tDn7jzWBRcD3sTbA== - dependencies: - "@types/bn.js" "^4.11.5" - web3-core "1.7.1" - web3-core-helpers "1.7.1" - web3-core-method "1.7.1" - web3-core-promievent "1.7.1" - web3-core-subscriptions "1.7.1" - web3-eth-abi "1.7.1" - web3-utils "1.7.1" - - web3-eth-ens@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3-eth-ens/-/web3-eth-ens-1.7.1.tgz#18ddb22e14e50108f9515c9d17f14560d69ff397" - integrity sha512-DVCF76i9wM93DrPQwLrYiCw/UzxFuofBsuxTVugrnbm0SzucajLLNftp3ITK0c4/lV3x9oo5ER/wD6RRMHQnvw== - dependencies: - content-hash "^2.5.2" - eth-ens-namehash "2.0.8" - web3-core "1.7.1" - web3-core-helpers "1.7.1" - web3-core-promievent "1.7.1" - web3-eth-abi "1.7.1" - web3-eth-contract "1.7.1" - web3-utils "1.7.1" - - web3-eth-iban@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3-eth-iban/-/web3-eth-iban-1.7.1.tgz#2148dff256392491df36b175e393b03c6874cd31" - integrity sha512-XG4I3QXuKB/udRwZdNEhdYdGKjkhfb/uH477oFVMLBqNimU/Cw8yXUI5qwFKvBHM+hMQWfzPDuSDEDKC2uuiMg== - dependencies: - bn.js "^4.11.9" - web3-utils "1.7.1" - - web3-eth-personal@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3-eth-personal/-/web3-eth-personal-1.7.1.tgz#38635f94223f951422105e5fcb7f7ba767a3ee9f" - integrity sha512-02H6nFBNfNmFjMGZL6xcDi0r7tUhxrUP91FTFdoLyR94eIJDadPp4rpXfG7MVES873i1PReh4ep5pSCHbc3+Pg== - dependencies: - "@types/node" "^12.12.6" - web3-core "1.7.1" - web3-core-helpers "1.7.1" - web3-core-method "1.7.1" - web3-net "1.7.1" - web3-utils "1.7.1" - - web3-eth@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3-eth/-/web3-eth-1.7.1.tgz#721599865f675b43877f5a18babfb7ae087449f7" - integrity sha512-Uz3gO4CjTJ+hMyJZAd2eiv2Ur1uurpN7sTMATWKXYR/SgG+SZgncnk/9d8t23hyu4lyi2GiVL1AqVqptpRElxg== - dependencies: - web3-core "1.7.1" - web3-core-helpers "1.7.1" - web3-core-method "1.7.1" - web3-core-subscriptions "1.7.1" - web3-eth-abi "1.7.1" - web3-eth-accounts "1.7.1" - web3-eth-contract "1.7.1" - web3-eth-ens "1.7.1" - web3-eth-iban "1.7.1" - web3-eth-personal "1.7.1" - web3-net "1.7.1" - web3-utils "1.7.1" - - web3-net@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3-net/-/web3-net-1.7.1.tgz#c75ff7ccabb949cf15e9098505516eb1ed8e37de" - integrity sha512-8yPNp2gvjInWnU7DCoj4pIPNhxzUjrxKlODsyyXF8j0q3Z2VZuQp+c63gL++r2Prg4fS8t141/HcJw4aMu5sVA== - dependencies: - web3-core "1.7.1" - web3-core-method "1.7.1" - web3-utils "1.7.1" - - web3-providers-http@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3-providers-http/-/web3-providers-http-1.7.1.tgz#3e00e013f013766aade28da29247daa1a937e759" - integrity sha512-dmiO6G4dgAa3yv+2VD5TduKNckgfR97VI9YKXVleWdcpBoKXe2jofhdvtafd42fpIoaKiYsErxQNcOC5gI/7Vg== - dependencies: - web3-core-helpers "1.7.1" - xhr2-cookies "1.1.0" - - web3-providers-ipc@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3-providers-ipc/-/web3-providers-ipc-1.7.1.tgz#cde879a2ba57b1deac2e1030de90d185b793dd50" - integrity sha512-uNgLIFynwnd5M9ZC0lBvRQU5iLtU75hgaPpc7ZYYR+kjSk2jr2BkEAQhFVJ8dlqisrVmmqoAPXOEU0flYZZgNQ== - dependencies: - oboe "2.1.5" - web3-core-helpers "1.7.1" - - web3-providers-ws@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3-providers-ws/-/web3-providers-ws-1.7.1.tgz#b6b3919ce155eff29b21bc3f205a098299a8c1b2" - integrity sha512-Uj0n5hdrh0ESkMnTQBsEUS2u6Unqdc7Pe4Zl+iZFb7Yn9cIGsPJBl7/YOP4137EtD5ueXAv+MKwzcelpVhFiFg== - dependencies: - eventemitter3 "4.0.4" - web3-core-helpers "1.7.1" - websocket "^1.0.32" - - web3-shh@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3-shh/-/web3-shh-1.7.1.tgz#c6a0fc67321dd585085e3e3be8f2c1c8d61636ef" - integrity sha512-NO+jpEjo8kYX6c7GiaAm57Sx93PLYkWYUCWlZmUOW7URdUcux8VVluvTWklGPvdM9H1WfDrol91DjuSW+ykyqg== - dependencies: - web3-core "1.7.1" - web3-core-method "1.7.1" - web3-core-subscriptions "1.7.1" - web3-net "1.7.1" - - web3-utils@1.7.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3-utils/-/web3-utils-1.7.1.tgz#77d8bacaf426c66027d8aa4864d77f0ed211aacd" - integrity sha512-fef0EsqMGJUgiHPdX+KN9okVWshbIumyJPmR+btnD1HgvoXijKEkuKBv0OmUqjbeqmLKP2/N9EiXKJel5+E1Dw== - dependencies: - bn.js "^4.11.9" - ethereum-bloom-filters "^1.0.6" - ethereumjs-util "^7.1.0" - ethjs-unit "0.1.6" - number-to-bn "1.7.0" - randombytes "^2.1.0" - utf8 "3.0.0" - - web3@^1.6.1: - version "1.7.1" - resolved "https://registry.yarnpkg.com/web3/-/web3-1.7.1.tgz#4d01371a2c0c07dba089f8009dabd2b11821c5e8" - integrity sha512-RKVdyZ5FuVEykj62C1o2tc0teJciSOh61jpVB9yb344dBHO3ZV4XPPP24s/PPqIMXmVFN00g2GD9M/v1SoHO/A== - dependencies: - web3-bzz "1.7.1" - web3-core "1.7.1" - web3-eth "1.7.1" - web3-eth-personal "1.7.1" - web3-net "1.7.1" - web3-shh "1.7.1" - web3-utils "1.7.1" - - webcrypto-core@^1.4.0: - version "1.7.1" - resolved "https://registry.yarnpkg.com/webcrypto-core/-/webcrypto-core-1.7.1.tgz#eb30112c28d0f75442cfb52cae59676c7fe155ef" - integrity sha512-Gw2zLzYSJ7Imp5lLDu3CcWB5oTTACMDEE2PjoLfttGgIhd7BfackBdVgEzd9ZM/i65gpNq0+IelL0JZ48QwzNg== - dependencies: - "@peculiar/asn1-schema" "^2.0.44" - "@peculiar/json-schema" "^1.1.12" - "@types/web" "^0.0.55" - asn1js "^2.2.0" - pvtsutils "^1.2.2" - tslib "^2.3.1" - - webextension-polyfill-ts@^0.22.0: - version "0.22.0" - resolved "https://registry.yarnpkg.com/webextension-polyfill-ts/-/webextension-polyfill-ts-0.22.0.tgz#86cfd7bab4d9d779d98c8340983f4b691b2343f3" - integrity sha512-3P33ClMwZ/qiAT7UH1ROrkRC1KM78umlnPpRhdC/292UyoTTW9NcjJEqDsv83HbibcTB6qCtpVeuB2q2/oniHQ== - dependencies: - webextension-polyfill "^0.7.0" - - webextension-polyfill-ts@^0.25.0: - version "0.25.0" - resolved "https://registry.yarnpkg.com/webextension-polyfill-ts/-/webextension-polyfill-ts-0.25.0.tgz#fff041626365dbd0e29c40b197e989a55ec221ca" - integrity sha512-ikQhwwHYkpBu00pFaUzIKY26I6L87DeRI+Q6jBT1daZUNuu8dSrg5U9l/ZbqdaQ1M/TTSPKeAa3kolP5liuedw== - dependencies: - webextension-polyfill "^0.7.0" - - webextension-polyfill@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/webextension-polyfill/-/webextension-polyfill-0.7.0.tgz#0df1120ff0266056319ce1a622b09ad8d4a56505" - integrity sha512-su48BkMLxqzTTvPSE1eWxKToPS2Tv5DLGxKexLEVpwFd6Po6N8hhSLIvG6acPAg7qERoEaDL+Y5HQJeJeml5Aw== - - webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= - - webidl-conversions@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" - integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== - - webidl-conversions@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" - integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== - - webidl-conversions@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" - integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== - - webpack-bundle-analyzer@4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.3.0.tgz#2f3c0ca9041d5ee47fa418693cf56b4a518b578b" - integrity sha512-J3TPm54bPARx6QG8z4cKBszahnUglcv70+N+8gUqv2I5KOFHJbzBiLx+pAp606so0X004fxM7hqRu10MLjJifA== - dependencies: - acorn "^8.0.4" - acorn-walk "^8.0.0" - chalk "^4.1.0" - commander "^6.2.0" - gzip-size "^6.0.0" - lodash "^4.17.20" - opener "^1.5.2" - sirv "^1.0.7" - ws "^7.3.1" - - websocket@^1.0.32: - version "1.0.34" - resolved "https://registry.yarnpkg.com/websocket/-/websocket-1.0.34.tgz#2bdc2602c08bf2c82253b730655c0ef7dcab3111" - integrity sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ== - dependencies: - bufferutil "^4.0.1" - debug "^2.2.0" - es5-ext "^0.10.50" - typedarray-to-buffer "^3.1.5" - utf-8-validate "^5.0.2" - yaeti "^0.0.6" - - whatwg-encoding@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" - integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== - dependencies: - iconv-lite "0.4.24" - - whatwg-mimetype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" - integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== - - whatwg-url@^11.0.0: - version "11.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-11.0.0.tgz#0a849eebb5faf2119b901bb76fd795c2848d4018" - integrity sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ== - dependencies: - tr46 "^3.0.0" - webidl-conversions "^7.0.0" - - whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - - whatwg-url@^8.0.0, whatwg-url@^8.5.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" - integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== - dependencies: - lodash "^4.7.0" - tr46 "^2.1.0" - webidl-conversions "^6.1.0" - - which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - - which-module@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" - integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= - - which-typed-array@^1.1.2: - version "1.1.7" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.7.tgz#2761799b9a22d4b8660b3c1b40abaa7739691793" - integrity sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-abstract "^1.18.5" - foreach "^2.0.5" - has-tostringtag "^1.0.0" - is-typed-array "^1.1.7" - - which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - - which@^2.0.1, which@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - - word-wrap@^1.2.3, word-wrap@~1.2.3: - version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" - integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== - - wordwrap@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" - integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= - - wrap-ansi@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" - integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - - wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - - wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - - write-file-atomic@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" - integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== - dependencies: - imurmurhash "^0.1.4" - is-typedarray "^1.0.0" - signal-exit "^3.0.2" - typedarray-to-buffer "^3.1.5" - - ws@8.4.2: - version "8.4.2" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.4.2.tgz#18e749868d8439f2268368829042894b6907aa0b" - integrity sha512-Kbk4Nxyq7/ZWqr/tarI9yIt/+iNNFOjBXEWgTb4ydaNHBNGgvf2QHbS9fdfsndfjFlFwEd4Al+mw83YkaD10ZA== - - ws@^3.0.0: - version "3.3.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-3.3.3.tgz#f1cf84fe2d5e901ebce94efaece785f187a228f2" - integrity sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA== - dependencies: - async-limiter "~1.0.0" - safe-buffer "~5.1.0" - ultron "~1.1.0" - - ws@^7.3.1, ws@^7.4.6: - version "7.5.7" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.7.tgz#9e0ac77ee50af70d58326ecff7e85eb3fa375e67" - integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A== - - xhr-request-promise@^0.1.2: - version "0.1.3" - resolved "https://registry.yarnpkg.com/xhr-request-promise/-/xhr-request-promise-0.1.3.tgz#2d5f4b16d8c6c893be97f1a62b0ed4cf3ca5f96c" - integrity sha512-YUBytBsuwgitWtdRzXDDkWAXzhdGB8bYm0sSzMPZT7Z2MBjMSTHFsyCT1yCRATY+XC69DUrQraRAEgcoCRaIPg== - dependencies: - xhr-request "^1.1.0" - - xhr-request@^1.0.1, xhr-request@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/xhr-request/-/xhr-request-1.1.0.tgz#f4a7c1868b9f198723444d82dcae317643f2e2ed" - integrity sha512-Y7qzEaR3FDtL3fP30k9wO/e+FBnBByZeybKOhASsGP30NIkRAAkKD/sCnLvgEfAIEC1rcmK7YG8f4oEnIrrWzA== - dependencies: - buffer-to-arraybuffer "^0.0.5" - object-assign "^4.1.1" - query-string "^5.0.1" - simple-get "^2.7.0" - timed-out "^4.0.1" - url-set-query "^1.0.0" - xhr "^2.0.4" - - xhr2-cookies@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/xhr2-cookies/-/xhr2-cookies-1.1.0.tgz#7d77449d0999197f155cb73b23df72505ed89d48" - integrity sha1-fXdEnQmZGX8VXLc7I99yUF7YnUg= - dependencies: - cookiejar "^2.1.1" - - xhr@^2.0.1, xhr@^2.0.4, xhr@^2.3.3: - version "2.6.0" - resolved "https://registry.yarnpkg.com/xhr/-/xhr-2.6.0.tgz#b69d4395e792b4173d6b7df077f0fc5e4e2b249d" - integrity sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA== - dependencies: - global "~4.4.0" - is-function "^1.0.1" - parse-headers "^2.0.0" - xtend "^4.0.0" - - xml-crypto@2.1.3, xml-crypto@^2.1.3: - version "2.1.3" - resolved "https://registry.yarnpkg.com/xml-crypto/-/xml-crypto-2.1.3.tgz#6a7272b610ea3e4ea7f13e9e4876f1b20cbc32c8" - integrity sha512-MpXZwnn9JK0mNPZ5mnFIbNnQa+8lMGK4NtnX2FlJMfMWR60sJdFO9X72yO6ji068pxixzk53O7x0/iSKh6IhyQ== - dependencies: - "@xmldom/xmldom" "^0.7.0" - xpath "0.0.32" - - xml-js@1.6.11: - version "1.6.11" - resolved "https://registry.yarnpkg.com/xml-js/-/xml-js-1.6.11.tgz#927d2f6947f7f1c19a316dd8eea3614e8b18f8e9" - integrity sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g== - dependencies: - sax "^1.2.4" - - xml-name-validator@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" - integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== - - xml-parse-from-string@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz#a9029e929d3dbcded169f3c6e28238d95a5d5a28" - integrity sha1-qQKekp09vN7RafPG4oI42VpdWig= - - xml2js@0.4.23, xml2js@^0.4.23, xml2js@^0.4.5: - version "0.4.23" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" - integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== - dependencies: - sax ">=0.6.0" - xmlbuilder "~11.0.0" - - xmlbuilder@15.1.1: - version "15.1.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-15.1.1.tgz#9dcdce49eea66d8d10b42cae94a79c3c8d0c2ec5" - integrity sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg== - - xmlbuilder@~11.0.0: - version "11.0.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" - integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== - - xmlchars@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" - integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== - - xpath@0.0.32: - version "0.0.32" - resolved "https://registry.yarnpkg.com/xpath/-/xpath-0.0.32.tgz#1b73d3351af736e17ec078d6da4b8175405c48af" - integrity sha512-rxMJhSIoiO8vXcWvSifKqhvV96GjiD5wYb8/QHdoRyQvraTpp4IEv944nhGausZZ3u7dhQXteZuZbaqfpB7uYw== - - xtend@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.2.0.tgz#eef6b1f198c1c8deafad8b1765a04dad4a01c5a9" - integrity sha1-7vax8ZjByN6vrYsXZaBNrUoBxak= - - xtend@^4.0.0, xtend@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - - xtend@~2.0.4: - version "2.0.6" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.0.6.tgz#5ea657a6dba447069c2e59c58a1138cb0c5e6cee" - integrity sha1-XqZXptukRwacLlnFihE4ywxebO4= - dependencies: - is-object "~0.1.2" - object-keys "~0.2.0" - - xtend@~2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" - integrity sha1-bv7MKk2tjmlixJAbM3znuoe10os= - dependencies: - object-keys "~0.4.0" - - xtend@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-3.0.0.tgz#5cce7407baf642cba7becda568111c493f59665a" - integrity sha1-XM50B7r2Qsunvs2laBEcST9ZZlo= - - y18n@^4.0.0: - version "4.0.3" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf" - integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ== - - y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - - yaeti@^0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/yaeti/-/yaeti-0.0.6.tgz#f26f484d72684cf42bedfb76970aa1608fbf9577" - integrity sha1-8m9ITXJoTPQr7ft2lwqhYI+/lXc= - - yallist@4.0.0, yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - - yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= - - yallist@^3.0.0, yallist@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== - - yaml@^1.10.0, yaml@^1.10.2, yaml@^1.7.2: - version "1.10.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== - - yargs-parser@20.x, yargs-parser@^20.2.2: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - - yargs-parser@^18.1.2: - version "18.1.3" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" - integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - - yargs-parser@^21.0.0: - version "21.0.1" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.0.1.tgz#0267f286c877a4f0f728fceb6f8a3e4cb95c6e35" - integrity sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg== - - yargs@^15.3.1, yargs@^15.4.1: - version "15.4.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" - integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== - dependencies: - cliui "^6.0.0" - decamelize "^1.2.0" - find-up "^4.1.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^4.2.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^18.1.2" - - yargs@^16.0.0, yargs@^16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - - yargs@^17.0.1: - version "17.3.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.3.1.tgz#da56b28f32e2fd45aefb402ed9c26f42be4c07b9" - integrity sha512-WUANQeVgjLbNsEmGk20f+nlHgOqzRFpiGWVaBrYGYIGANIIu3lWjoyi0fNlFmJkvfhCZ6BXINe7/W2O2bV4iaA== - 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" - - yauzl@2.10.0, yauzl@^2.10.0, yauzl@^2.4.2: - version "2.10.0" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" - integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= - dependencies: - buffer-crc32 "~0.2.3" - fd-slicer "~1.1.0" - - yazl@2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.5.1.tgz#a3d65d3dd659a5b0937850e8609f22fffa2b5c35" - integrity sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw== - dependencies: - buffer-crc32 "~0.2.3" - - yn@3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" - integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== - - yup@^0.32.9: - version "0.32.11" - resolved "https://registry.yarnpkg.com/yup/-/yup-0.32.11.tgz#d67fb83eefa4698607982e63f7ca4c5ed3cf18c5" - integrity sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg== - dependencies: - "@babel/runtime" "^7.15.4" - "@types/lodash" "^4.14.175" - lodash "^4.17.21" - lodash-es "^4.17.21" - nanoclone "^0.2.1" - property-expr "^2.0.4" - toposort "^2.0.2" - - zen-observable-ts@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz#2d1aa9d79b87058e9b75698b92791c1838551f83" - integrity sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA== - dependencies: - "@types/zen-observable" "0.8.3" - zen-observable "0.8.15" - - zen-observable@0.8.15: - version "0.8.15" - resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" - integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== - - zod-prisma@^0.5.4: - version "0.5.4" - resolved "https://registry.yarnpkg.com/zod-prisma/-/zod-prisma-0.5.4.tgz#f1c4d107cb9e4c666e2432017e6dcc390ef23700" - integrity sha512-5Ca4Qd1a1jy1T/NqCEpbr0c+EsbjJfJ/7euEHob3zDvtUK2rTuD1Rc/vfzH8q8PtaR2TZbysD88NHmrLwpv3Xg== - dependencies: - "@prisma/generator-helper" "~3.8.1" - parenthesis "^3.1.8" - ts-morph "^13.0.2" - - zod@^3.14.2: - version "3.14.2" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.14.2.tgz#0b4ed79085c471adce0e7f2c0a4fbb5ddc516ba2" - integrity sha512-iF+wrtzz7fQfkmn60PG6XFxaWBhYYKzp2i+nv24WbLUWb2JjymdkHlzBwP0erpc78WotwP5g9AAu7Sk8GWVVNw== - - zod@^3.8.2, zod@^3.9.5: - version "3.13.4" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.13.4.tgz#5d6fe03ef4824a637d7ef50b5441cf6ab3acede0" - integrity sha512-LZRucWt4j/ru5azOkJxCfpR87IyFDn8h2UODdqvXzZLb3K7bb9chUrUIGTy3BPsr8XnbQYfQ5Md5Hu2OYIo1mg== - - zwitch@^1.0.0: - version "1.0.5" - resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920" - integrity sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw== - - zwitch@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-2.0.2.tgz#91f8d0e901ffa3d66599756dde7f57b17c95dce1" - integrity sha512-JZxotl7SxAJH0j7dN4pxsTV6ZLXoLdGME+PsjkL/DaBrVryK9kTGq06GfKrwcSOqypP+fdXGoCHE36b99fWVoA== From 3011e0ecf744ca4abec9b32647b7a91f7e85b0dd Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 29 Mar 2022 03:23:22 +0200 Subject: [PATCH 042/658] chore: no default export --- lib/helpers/withMiddleware.ts | 2 +- lib/validations/shared/queryIdString.ts | 3 +++ .../shared/queryIdTransformParseInt.ts | 3 +++ pages/_middleware.ts | 2 +- pages/api/users/[id]/delete.ts | 5 ++-- pages/api/users/[id]/edit.ts | 3 ++- pages/api/users/[id]/index.ts | 3 ++- pages/api/users/index.ts | 3 ++- pages/api/users/new.ts | 24 +++++++++---------- 9 files changed, 29 insertions(+), 19 deletions(-) diff --git a/lib/helpers/withMiddleware.ts b/lib/helpers/withMiddleware.ts index 99f3958af7..d333439df8 100644 --- a/lib/helpers/withMiddleware.ts +++ b/lib/helpers/withMiddleware.ts @@ -12,4 +12,4 @@ const withMiddleware = label( ["sentry","verifyApiKey"] // <-- Provide a list of middleware to call automatically ); -export default withMiddleware; \ No newline at end of file +export { withMiddleware }; \ No newline at end of file diff --git a/lib/validations/shared/queryIdString.ts b/lib/validations/shared/queryIdString.ts index c221606841..e89986dca5 100644 --- a/lib/validations/shared/queryIdString.ts +++ b/lib/validations/shared/queryIdString.ts @@ -5,6 +5,9 @@ import { z } from "zod"; // at different endpoints that require this validation. const schemaQueryIdAsString = z .object({ + // since we added apiKey as query param this is required by next-validations helper + // for query params to work properly and not fail. + apiKey: z.string().cuid(), // since nextjs parses query params as strings, // we need to cast them to numbers using z.transform() and parseInt() id: z.string() diff --git a/lib/validations/shared/queryIdTransformParseInt.ts b/lib/validations/shared/queryIdTransformParseInt.ts index d185d1a255..b1f2eb4835 100644 --- a/lib/validations/shared/queryIdTransformParseInt.ts +++ b/lib/validations/shared/queryIdTransformParseInt.ts @@ -5,6 +5,9 @@ import { z } from "zod"; // at different endpoints that require this validation. const schemaQueryIdParseInt = z .object({ + // since we added apiKey as query param this is required by next-validations helper + // for query params to work properly and not fail. + apiKey: z.string().cuid(), // since nextjs parses query params as strings, // we need to cast them to numbers using z.transform() and parseInt() id: z diff --git a/pages/_middleware.ts b/pages/_middleware.ts index c631934a91..624d392043 100644 --- a/pages/_middleware.ts +++ b/pages/_middleware.ts @@ -3,7 +3,7 @@ import { NextRequest, NextResponse } from "next/server"; // Not much useful yet as prisma.client can't be used in the middlewares (client is not available) // For now we just throw early if no apiKey is passed, // but we could also check if the apiKey is valid if we had prisma here. -export async function middleware({ nextUrl }: NextRequest) { +export async function requireApiKeyAsQueryParams({ nextUrl }: NextRequest) { const response = NextResponse.next(); const apiKey = nextUrl.searchParams.get("apiKey"); diff --git a/pages/api/users/[id]/delete.ts b/pages/api/users/[id]/delete.ts index f7bbf96856..1a2a2b240e 100644 --- a/pages/api/users/[id]/delete.ts +++ b/pages/api/users/[id]/delete.ts @@ -1,7 +1,8 @@ -import prisma from "@calcom/prisma"; import type { NextApiRequest, NextApiResponse } from "next"; +import prisma from "@calcom/prisma"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; @@ -24,4 +25,4 @@ export async function deleteUser(req: NextApiRequest, res: NextApiResponse) { if (data) res.status(200).json({ data }); else res.status(400).json({ error: "No data found" }); } + export default withMiddleware("addRequestId")(user); \ No newline at end of file diff --git a/pages/api/users/new.ts b/pages/api/users/new.ts index 7f319e62d9..1ad079ca44 100644 --- a/pages/api/users/new.ts +++ b/pages/api/users/new.ts @@ -1,26 +1,26 @@ -import prisma from "@calcom/prisma"; - -import { User } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; +import prisma from "@calcom/prisma"; +import { User } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; import { schemaUser, withValidUser } from "@lib/validations/user"; + type ResponseData = { data?: User; - message?: string; - error?: string; + error?: object; }; async function createUser(req: NextApiRequest, res: NextApiResponse) { const { body, method } = req; const safe = schemaUser.safeParse(body); if (method === "POST" && safe.success) { - await prisma.user - .create({ data: safe.data }) - .then((data) => res.status(201).json({ data })) - .catch((error) => res.status(400).json({ message: "Could not create user type", error: error })); - // Reject any other HTTP method than POST - } else res.status(405).json({ error: "Only POST Method allowed" }); + const data = await prisma.user + .create({ data: safe.data }) + if (data) res.status(201).json({ data }) + else (error: unknown) => res.status(400).json({ error: { message: "Could not create user type", error: error } }); + // Reject any other HTTP method than POST + } else res.status(405).json({ error: { message: "Only POST Method allowed" } }); } -export default withValidUser(createUser); +export default withMiddleware("addRequestId")(withValidUser(createUser)); From 20a93a13c94954e6d2fe5379a6e2f3b3f0d66446 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 29 Mar 2022 03:59:57 +0200 Subject: [PATCH 043/658] feat: update users/teams/apiKeys to use middleware --- lib/helpers/httpMethods.ts | 19 +++++++++++ lib/helpers/withMiddleware.ts | 6 +++- pages/api/api-keys/[id]/delete.ts | 26 +++++++------- pages/api/api-keys/[id]/edit.ts | 25 ++++++++------ pages/api/api-keys/[id]/index.ts | 26 ++++++++------ pages/api/api-keys/index.ts | 17 +++++----- pages/api/api-keys/new.ts | 33 +++++++++--------- pages/api/booking-references/[id]/edit.ts | 2 +- pages/api/booking-references/[id]/index.ts | 2 +- pages/api/booking-references/new.ts | 2 +- pages/api/credentials/[id]/index.ts | 2 +- .../api/daily-event-references/[id]/delete.ts | 17 ++++++---- .../api/daily-event-references/[id]/index.ts | 2 +- pages/api/destination-calendars/[id]/index.ts | 2 +- .../event-type-custom-inputs/[id]/index.ts | 2 +- pages/api/memberships/[id]/index.ts | 2 +- pages/api/schedules/[id]/index.ts | 2 +- pages/api/selected-calendars/[id]/index.ts | 2 +- pages/api/teams/[id]/delete.ts | 24 +++++++------ pages/api/teams/[id]/edit.ts | 25 +++++++------- pages/api/teams/[id]/index.ts | 24 ++++++------- pages/api/teams/index.ts | 16 ++++----- pages/api/teams/new.ts | 34 +++++++++---------- pages/api/users/[id]/delete.ts | 21 ++++++------ pages/api/users/[id]/edit.ts | 15 ++++---- pages/api/users/[id]/index.ts | 18 +++++----- pages/api/users/index.ts | 5 +-- pages/api/users/new.ts | 14 ++++---- 28 files changed, 216 insertions(+), 169 deletions(-) create mode 100644 lib/helpers/httpMethods.ts diff --git a/lib/helpers/httpMethods.ts b/lib/helpers/httpMethods.ts new file mode 100644 index 0000000000..4bfeb1b1fe --- /dev/null +++ b/lib/helpers/httpMethods.ts @@ -0,0 +1,19 @@ +import { NextMiddleware } from "next-api-middleware"; + +export const httpMethod = ( + allowedHttpMethod: "GET" | "POST" | "PATCH" | "DELETE" +): NextMiddleware => { + return async function (req, res, next) { + if (req.method === allowedHttpMethod || req.method == "OPTIONS") { + await next(); + } else { + res.status(404); + res.end(); + } + }; +}; + +export const postOnly = httpMethod("POST"); +export const getOnly = httpMethod("GET"); +export const patchOnly = httpMethod("PATCH"); +export const deleteOnly = httpMethod("DELETE"); \ No newline at end of file diff --git a/lib/helpers/withMiddleware.ts b/lib/helpers/withMiddleware.ts index d333439df8..7d94e5da7a 100644 --- a/lib/helpers/withMiddleware.ts +++ b/lib/helpers/withMiddleware.ts @@ -2,9 +2,13 @@ import { label } from "next-api-middleware"; import { addRequestId } from "./addRequestid"; import { captureErrors } from "./captureErrors"; import { verifyApiKey } from "./verifyApiKey"; - +import { postOnly, deleteOnly, patchOnly, getOnly } from "./httpMethods"; const withMiddleware = label( { + getOnly, + patchOnly, + postOnly, + deleteOnly, addRequestId, verifyApiKey, sentry: captureErrors, // <-- Optionally alias middleware diff --git a/pages/api/api-keys/[id]/delete.ts b/pages/api/api-keys/[id]/delete.ts index 10e6aaef98..722705a303 100644 --- a/pages/api/api-keys/[id]/delete.ts +++ b/pages/api/api-keys/[id]/delete.ts @@ -1,27 +1,29 @@ -import prisma from "@calcom/prisma"; import type { NextApiRequest, NextApiResponse } from "next"; +import prisma from "@calcom/prisma"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; - type ResponseData = { message?: string; error?: unknown; }; -export async function apiKey(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdAsString.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const apiKey = await prisma.apiKey +export async function deleteApiKey(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdAsString.safeParse(req.query); + if (safe.success) { + const data = await prisma.apiKey .delete({ where: { id: safe.data.id } }) // We only remove the apiKey type from the database if there's an existing resource. - if (apiKey) res.status(200).json({ message: `apiKey with id: ${safe.data.id} deleted successfully` }); + if (data) res.status(200).json({ message: `ApiKey with id: ${safe.data.id} deleted successfully` }); // This catches the error thrown by prisma.apiKey.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only DELETE Method allowed" }); + else res.status(400).json({ message: `ApiKey with id: ${safe.data.id} was not able to be processed` }); + } } -export default withValidQueryIdString(apiKey); +export default withMiddleware("deleteOnly", "addRequestId")( + withValidQueryIdString( + deleteApiKey + ) +); diff --git a/pages/api/api-keys/[id]/edit.ts b/pages/api/api-keys/[id]/edit.ts index 4fc4572444..d436faf967 100644 --- a/pages/api/api-keys/[id]/edit.ts +++ b/pages/api/api-keys/[id]/edit.ts @@ -1,9 +1,10 @@ import prisma from "@calcom/prisma"; -import { ApiKey } from "@prisma/client"; +import { ApiKey } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; import { schemaApiKey, withValidApiKey } from "@lib/validations/apiKey"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; type ResponseData = { @@ -17,17 +18,19 @@ export async function editApiKey(req: NextApiRequest, res: NextApiResponse { - res.status(200).json({ data: apiKey }); - }).catch(error => { - res.status(404).json({ message: `apiKey with ID ${safeQuery.data.id} not found and wasn't updated`, error }) - }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only PATCH Method allowed for updating API keys" }); + }) + if (data) res.status(200).json({ data }); + else (error: unknown) => res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + } } -export default withValidQueryIdString(withValidApiKey(editApiKey)); +export default withMiddleware("patchOnly","addRequestId")( + withValidQueryIdString( + withValidApiKey( + editApiKey) + ) +); diff --git a/pages/api/api-keys/[id]/index.ts b/pages/api/api-keys/[id]/index.ts index 49b3a7f6a2..18d6dbcc69 100644 --- a/pages/api/api-keys/[id]/index.ts +++ b/pages/api/api-keys/[id]/index.ts @@ -1,9 +1,10 @@ import prisma from "@calcom/prisma"; -import { ApiKey } from "@prisma/client"; +import { ApiKey } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; type ResponseData = { data?: ApiKey; @@ -11,16 +12,19 @@ type ResponseData = { error?: unknown; }; -export async function apiKey(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdAsString.safeParse(query); - if (method === "GET" && safe.success) { - const apiKey = await prisma.apiKey.findUnique({ where: { id: safe.data.id } }); - if (!apiKey) res.status(404).json({ message: "API key was not found" }); - else res.status(200).json({ data: apiKey }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only GET Method allowed" }); +export async function apiKeyById(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdAsString.safeParse(req.query); + if (safe.success) { + const data = await prisma.apiKey.findUnique({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ data }); + else res.status(404).json({ message: "ApiKey was not found" }); + } } -export default withValidQueryIdString(apiKey); +export default withMiddleware("addRequestId","getOnly")( + withValidQueryIdString( + apiKeyById + ) +); diff --git a/pages/api/api-keys/index.ts b/pages/api/api-keys/index.ts index 5155c36c59..eca77dbefe 100644 --- a/pages/api/api-keys/index.ts +++ b/pages/api/api-keys/index.ts @@ -1,18 +1,19 @@ import prisma from "@calcom/prisma"; -import { ApiKey } from "@prisma/client"; +import { ApiKey } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { NextApiRequest, NextApiResponse } from "next"; type ResponseData = { data?: ApiKey[]; error?: unknown; - message?: string; }; -export default async function apiKeys(req: NextApiRequest, res: NextApiResponse) { - const { method } = req; - if (method === "GET") { - const data = await prisma.apiKey.findMany({}); - res.status(200).json({ data }); - } else res.status(405).json({ message: "Only GET Method allowed" }); +async function allApiKeys(req: NextApiRequest, res: NextApiResponse) { + const data = await prisma.apiKey.findMany(); + + if (data) res.status(200).json({ data }); + else res.status(400).json({ error: "No data found" }); } + +export default withMiddleware("addRequestId","getOnly")(allApiKeys); \ No newline at end of file diff --git a/pages/api/api-keys/new.ts b/pages/api/api-keys/new.ts index 8787824fbd..b49b8a7049 100644 --- a/pages/api/api-keys/new.ts +++ b/pages/api/api-keys/new.ts @@ -1,27 +1,28 @@ -import prisma from "@calcom/prisma"; - -import { ApiKey } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; +import prisma from "@calcom/prisma"; +import { ApiKey } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; import { schemaApiKey, withValidApiKey } from "@lib/validations/apiKey"; + type ResponseData = { data?: ApiKey; - message?: string; - error?: string; + error?: object; }; async function createApiKey(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - const safe = schemaApiKey.safeParse(body); - if (method === "POST" && safe.success) { - const apiKey = await prisma.apiKey - .create({ data: { ...safe.data, user: { connect: { id: 1 } } } }) - - if (apiKey) res.status(201).json({ data: apiKey }); - else res.status(404).json({ message: "API Key not created" }); - - } else res.status(405).json({ error: "Only POST Method allowed" }); + const safe = schemaApiKey.safeParse(req.body); + if (safe.success) { + const data = await prisma.apiKey + .create({ data: safe.data }) + if (data) res.status(201).json({ data }) + else (error: unknown) => res.status(400).json({ error: { message: "Could not create apiKey type", error: error } }); + } } -export default withValidApiKey(createApiKey); +export default withMiddleware("addRequestId","postOnly")( + withValidApiKey( + createApiKey + ) +); diff --git a/pages/api/booking-references/[id]/edit.ts b/pages/api/booking-references/[id]/edit.ts index cdfe7a739b..834574a3a1 100644 --- a/pages/api/booking-references/[id]/edit.ts +++ b/pages/api/booking-references/[id]/edit.ts @@ -3,7 +3,7 @@ import prisma from "@calcom/prisma"; import { BookingReference } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaBookingReference, withValidBookingReference } from "@lib/validations/bookingReference"; +import { schemaBookingReference, withValidBookingReference } from "@lib/validations/booking-reference"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { diff --git a/pages/api/booking-references/[id]/index.ts b/pages/api/booking-references/[id]/index.ts index ec973f5016..8a649fb4d9 100644 --- a/pages/api/booking-references/[id]/index.ts +++ b/pages/api/booking-references/[id]/index.ts @@ -18,7 +18,7 @@ export async function bookingReference(req: NextApiRequest, res: NextApiResponse const data = await prisma.bookingReference.findUnique({ where: { id: safe.data.id } }); if (data) res.status(200).json({ data }); - if (!data) res.status(404).json({ message: "Event type not found" }); + else res.status(404).json({ message: "Event type not found" }); // Reject any other HTTP method than POST } else res.status(405).json({ message: "Only GET Method allowed" }); } diff --git a/pages/api/booking-references/new.ts b/pages/api/booking-references/new.ts index ba21befec8..e792e3f1c7 100644 --- a/pages/api/booking-references/new.ts +++ b/pages/api/booking-references/new.ts @@ -3,7 +3,7 @@ import prisma from "@calcom/prisma"; import { BookingReference } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaBookingReference, withValidBookingReference } from "@lib/validations/bookingReference"; +import { schemaBookingReference, withValidBookingReference } from "@lib/validations/booking-reference"; type ResponseData = { data?: BookingReference; diff --git a/pages/api/credentials/[id]/index.ts b/pages/api/credentials/[id]/index.ts index 14ca851867..a15e0463bc 100644 --- a/pages/api/credentials/[id]/index.ts +++ b/pages/api/credentials/[id]/index.ts @@ -18,7 +18,7 @@ export async function credential(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const dailyEventReference = await prisma.dailyEventReference + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (safe.success) { + const deletedDailyEventReference = await prisma.dailyEventReference .delete({ where: { id: safe.data.id } }) // We only remove the dailyEventReference type from the database if there's an existing resource. - if (dailyEventReference) res.status(200).json({ message: `dailyEventReference with id: ${safe.data.id} deleted successfully` }); + if (deletedDailyEventReference) res.status(200).json({ message: `dailyEventReference with id: ${safe.data.id} deleted successfully` }); // This catches the error thrown by prisma.dailyEventReference.delete() if the resource is not found. else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); // Reject any other HTTP method than POST } else res.status(405).json({ message: "Only DELETE Method allowed" }); } -export default withValidQueryIdTransformParseInt(deleteDailyEventReference); +// export default withValidQueryIdTransformParseInt(deleteDailyEventReference); +export default withMiddleware("deleteOnly")( + withValidQueryIdTransformParseInt( + deleteDailyEventReference + ) +); diff --git a/pages/api/daily-event-references/[id]/index.ts b/pages/api/daily-event-references/[id]/index.ts index c9b243f707..166a661dcc 100644 --- a/pages/api/daily-event-references/[id]/index.ts +++ b/pages/api/daily-event-references/[id]/index.ts @@ -18,7 +18,7 @@ export async function dailyEventReference(req: NextApiRequest, res: NextApiRespo const data = await prisma.dailyEventReference.findUnique({ where: { id: safe.data.id } }); if (data) res.status(200).json({ data }); - if (!data) res.status(404).json({ message: "Event type not found" }); + else res.status(404).json({ message: "Event type not found" }); // Reject any other HTTP method than POST } else res.status(405).json({ message: "Only GET Method allowed" }); } diff --git a/pages/api/destination-calendars/[id]/index.ts b/pages/api/destination-calendars/[id]/index.ts index 95a1409372..95a44a5edf 100644 --- a/pages/api/destination-calendars/[id]/index.ts +++ b/pages/api/destination-calendars/[id]/index.ts @@ -18,7 +18,7 @@ export async function destinationCalendar(req: NextApiRequest, res: NextApiRespo const data = await prisma.destinationCalendar.findUnique({ where: { id: safe.data.id } }); if (data) res.status(200).json({ data }); - if (!data) res.status(404).json({ message: "Event type not found" }); + else res.status(404).json({ message: "Event type not found" }); // Reject any other HTTP method than POST } else res.status(405).json({ message: "Only GET Method allowed" }); } diff --git a/pages/api/event-type-custom-inputs/[id]/index.ts b/pages/api/event-type-custom-inputs/[id]/index.ts index 3b7a926dcd..c53b2e4c06 100644 --- a/pages/api/event-type-custom-inputs/[id]/index.ts +++ b/pages/api/event-type-custom-inputs/[id]/index.ts @@ -18,7 +18,7 @@ export async function eventTypeCustomInput(req: NextApiRequest, res: NextApiResp const data = await prisma.eventTypeCustomInput.findUnique({ where: { id: safe.data.id } }); if (data) res.status(200).json({ data }); - if (!data) res.status(404).json({ message: "Event type not found" }); + else res.status(404).json({ message: "Event type not found" }); // Reject any other HTTP method than POST } else res.status(405).json({ message: "Only GET Method allowed" }); } diff --git a/pages/api/memberships/[id]/index.ts b/pages/api/memberships/[id]/index.ts index 7f56aa3889..8f1496ddc5 100644 --- a/pages/api/memberships/[id]/index.ts +++ b/pages/api/memberships/[id]/index.ts @@ -18,7 +18,7 @@ export async function membership(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const team = await prisma.team + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (safe.success) { + const data = await prisma.team .delete({ where: { id: safe.data.id } }) // We only remove the team type from the database if there's an existing resource. - if (team) res.status(200).json({ message: `team with id: ${safe.data.id} deleted successfully` }); + if (data) res.status(200).json({ message: `Team with id: ${safe.data.id} deleted successfully` }); // This catches the error thrown by prisma.team.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only DELETE Method allowed" }); + else res.status(400).json({ message: `Team with id: ${safe.data.id} was not able to be processed` }); + } } -export default withValidQueryIdTransformParseInt(deleteTeam); +export default withMiddleware("deleteOnly", "addRequestId")( + withValidQueryIdTransformParseInt( + deleteTeam + ) +); diff --git a/pages/api/teams/[id]/edit.ts b/pages/api/teams/[id]/edit.ts index c046c97da4..96e2fa5d3a 100644 --- a/pages/api/teams/[id]/edit.ts +++ b/pages/api/teams/[id]/edit.ts @@ -4,6 +4,7 @@ import { Team } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; import { schemaTeam, withValidTeam } from "@lib/validations/team"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { @@ -17,21 +18,19 @@ export async function editTeam(req: NextApiRequest, res: NextApiResponse { - res.status(200).json({ data: team }); - }).catch(error => { - res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) - }); - } - } else { - // Reject any other HTTP method than POST - res.status(405).json({ message: "Only PATCH Method allowed for updating teams" }); + }) + if (data) res.status(200).json({ data }); + else (error: unknown) => res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) } } -export default withValidQueryIdTransformParseInt(withValidTeam(editTeam)); +export default withMiddleware("patchOnly","addRequestId")( + withValidQueryIdTransformParseInt( + withValidTeam( + editTeam) + ) +); diff --git a/pages/api/teams/[id]/index.ts b/pages/api/teams/[id]/index.ts index cd9cd660d4..9868c043fd 100644 --- a/pages/api/teams/[id]/index.ts +++ b/pages/api/teams/[id]/index.ts @@ -4,6 +4,7 @@ import { Team } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; type ResponseData = { data?: Team; @@ -11,20 +12,19 @@ type ResponseData = { error?: unknown; }; -export async function team(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - - if (method === "GET" && safe.success) { - const team = await prisma.team.findUnique({ where: { id: safe.data.id } }); +export async function teamById(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (safe.success) { + const data = await prisma.team.findUnique({ where: { id: safe.data.id } }); - if (team) res.status(200).json({ data: team }); - if (!team) res.status(404).json({ message: "Event type not found" }); - } else { - // Reject any other HTTP method than POST - res.status(405).json({ message: "Only GET Method allowed" }); + if (data) res.status(200).json({ data }); + else res.status(404).json({ message: "Team was not found" }); } } -export default withValidQueryIdTransformParseInt(team); +export default withMiddleware("addRequestId","getOnly")( + withValidQueryIdTransformParseInt( + teamById + ) +); diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index 0b57f21604..1fd88d492f 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -1,6 +1,7 @@ import prisma from "@calcom/prisma"; import { Team } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { NextApiRequest, NextApiResponse } from "next"; type ResponseData = { @@ -8,12 +9,11 @@ type ResponseData = { error?: unknown; }; -export default async function team(req: NextApiRequest, res: NextApiResponse) { - try { - const data = await prisma.team.findMany(); - res.status(200).json({ data }); - } catch (error) { - // FIXME: Add zod for validation/error handling - res.status(400).json({ error: error }); - } +async function allTeams(req: NextApiRequest, res: NextApiResponse) { + const data = await prisma.team.findMany(); + + if (data) res.status(200).json({ data }); + else res.status(400).json({ error: "No data found" }); } + +export default withMiddleware("addRequestId","getOnly")(allTeams); \ No newline at end of file diff --git a/pages/api/teams/new.ts b/pages/api/teams/new.ts index ebcb513777..7ae4d0034e 100644 --- a/pages/api/teams/new.ts +++ b/pages/api/teams/new.ts @@ -1,30 +1,28 @@ -import prisma from "@calcom/prisma"; - -import { Team } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; +import prisma from "@calcom/prisma"; +import { Team } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; import { schemaTeam, withValidTeam } from "@lib/validations/team"; + type ResponseData = { data?: Team; - message?: string; - error?: string; + error?: object; }; async function createTeam(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - if (method === "POST") { - const safe = schemaTeam.safeParse(body); - if (safe.success && safe.data) { - await prisma.team - .create({ data: safe.data }) - .then((team) => res.status(201).json({ data: team })) - .catch((error) => res.status(400).json({ message: "Could not create team", error: error })); - } - } else { - // Reject any other HTTP method than POST - res.status(405).json({ error: "Only POST Method allowed" }); + const safe = schemaTeam.safeParse(req.body); + if (safe.success) { + const data = await prisma.team + .create({ data: safe.data }) + if (data) res.status(201).json({ data }) + else (error: unknown) => res.status(400).json({ error: { message: "Could not create team type", error: error } }); } } -export default withValidTeam(createTeam); +export default withMiddleware("addRequestId","postOnly")( + withValidTeam( + createTeam + ) +); diff --git a/pages/api/users/[id]/delete.ts b/pages/api/users/[id]/delete.ts index 1a2a2b240e..6542b99134 100644 --- a/pages/api/users/[id]/delete.ts +++ b/pages/api/users/[id]/delete.ts @@ -5,24 +5,25 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; - type ResponseData = { message?: string; error?: unknown; }; export async function deleteUser(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const user = await prisma.user + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (safe.success) { + const data = await prisma.user .delete({ where: { id: safe.data.id } }) // We only remove the user type from the database if there's an existing resource. - if (user) res.status(200).json({ message: `user with id: ${safe.data.id} deleted successfully` }); + if (data) res.status(200).json({ message: `User with id: ${safe.data.id} deleted successfully` }); // This catches the error thrown by prisma.user.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only DELETE Method allowed" }); + else res.status(400).json({ message: `User with id: ${safe.data.id} was not able to be processed` }); + } } -export default withMiddleware("addRequestId")((withValidQueryIdTransformParseInt(deleteUser))); +export default withMiddleware("deleteOnly", "addRequestId")( + withValidQueryIdTransformParseInt( + deleteUser + ) +); diff --git a/pages/api/users/[id]/edit.ts b/pages/api/users/[id]/edit.ts index a59a0df940..3e5425b3d9 100644 --- a/pages/api/users/[id]/edit.ts +++ b/pages/api/users/[id]/edit.ts @@ -18,16 +18,19 @@ export async function editUser(req: NextApiRequest, res: NextApiResponse res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + } } -export default withMiddleware("addRequestId")(withValidQueryIdTransformParseInt(withValidUser(editUser))); +export default withMiddleware("patchOnly","addRequestId")( + withValidQueryIdTransformParseInt( + withValidUser( + editUser) + ) +); diff --git a/pages/api/users/[id]/index.ts b/pages/api/users/[id]/index.ts index cbd088e9df..6264acd115 100644 --- a/pages/api/users/[id]/index.ts +++ b/pages/api/users/[id]/index.ts @@ -12,17 +12,19 @@ type ResponseData = { error?: unknown; }; -export async function user(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "GET" && safe.success) { +export async function userById(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (safe.success) { const data = await prisma.user.findUnique({ where: { id: safe.data.id } }); if (data) res.status(200).json({ data }); - if (!data) res.status(404).json({ message: "Event type not found" }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only GET Method allowed" }); + else res.status(404).json({ message: "User was not found" }); + } } -export default withMiddleware("addRequestId")(withValidQueryIdTransformParseInt(user)); +export default withMiddleware("addRequestId","getOnly")( + withValidQueryIdTransformParseInt( + userById + ) +); diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 9c7473252f..ef75e93cc7 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -9,10 +9,11 @@ type ResponseData = { error?: unknown; }; -async function user(req: NextApiRequest, res: NextApiResponse) { +async function allUsers(req: NextApiRequest, res: NextApiResponse) { const data = await prisma.user.findMany(); + if (data) res.status(200).json({ data }); else res.status(400).json({ error: "No data found" }); } -export default withMiddleware("addRequestId")(user); \ No newline at end of file +export default withMiddleware("addRequestId","getOnly")(allUsers); \ No newline at end of file diff --git a/pages/api/users/new.ts b/pages/api/users/new.ts index 1ad079ca44..6ce94b5df0 100644 --- a/pages/api/users/new.ts +++ b/pages/api/users/new.ts @@ -12,15 +12,17 @@ type ResponseData = { }; async function createUser(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - const safe = schemaUser.safeParse(body); - if (method === "POST" && safe.success) { + const safe = schemaUser.safeParse(req.body); + if (safe.success) { const data = await prisma.user .create({ data: safe.data }) if (data) res.status(201).json({ data }) else (error: unknown) => res.status(400).json({ error: { message: "Could not create user type", error: error } }); - // Reject any other HTTP method than POST - } else res.status(405).json({ error: { message: "Only POST Method allowed" } }); + } } -export default withMiddleware("addRequestId")(withValidUser(createUser)); +export default withMiddleware("addRequestId","postOnly")( + withValidUser( + createUser + ) +); From 443e01f0daae5637842e0a46c6b9413fd8b6f833 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 29 Mar 2022 04:01:23 +0200 Subject: [PATCH 044/658] chore: update imports to use dasheS --- pages/api/daily-event-references/[id]/edit.ts | 2 +- pages/api/daily-event-references/new.ts | 2 +- pages/api/destination-calendars/[id]/edit.ts | 2 +- pages/api/destination-calendars/new.ts | 2 +- pages/api/selected-calendars/[id]/edit.ts | 2 +- pages/api/selected-calendars/new.ts | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pages/api/daily-event-references/[id]/edit.ts b/pages/api/daily-event-references/[id]/edit.ts index eb731dde8a..30c5bbca78 100644 --- a/pages/api/daily-event-references/[id]/edit.ts +++ b/pages/api/daily-event-references/[id]/edit.ts @@ -3,7 +3,7 @@ import prisma from "@calcom/prisma"; import { DailyEventReference } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaDailyEventReference, withValidDailyEventReference } from "@lib/validations/dailyEventReference"; +import { schemaDailyEventReference, withValidDailyEventReference } from "@lib/validations/daily-event-reference"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { diff --git a/pages/api/daily-event-references/new.ts b/pages/api/daily-event-references/new.ts index c508b37e08..153742739a 100644 --- a/pages/api/daily-event-references/new.ts +++ b/pages/api/daily-event-references/new.ts @@ -3,7 +3,7 @@ import prisma from "@calcom/prisma"; import { DailyEventReference } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaDailyEventReference, withValidDailyEventReference } from "@lib/validations/dailyEventReference"; +import { schemaDailyEventReference, withValidDailyEventReference } from "@lib/validations/daily-event-reference"; type ResponseData = { data?: DailyEventReference; diff --git a/pages/api/destination-calendars/[id]/edit.ts b/pages/api/destination-calendars/[id]/edit.ts index 5cc11fa10d..5495656d70 100644 --- a/pages/api/destination-calendars/[id]/edit.ts +++ b/pages/api/destination-calendars/[id]/edit.ts @@ -3,7 +3,7 @@ import prisma from "@calcom/prisma"; import { DestinationCalendar } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaDestinationCalendar, withValidDestinationCalendar } from "@lib/validations/destinationCalendar"; +import { schemaDestinationCalendar, withValidDestinationCalendar } from "@lib/validations/destination-calendar"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { diff --git a/pages/api/destination-calendars/new.ts b/pages/api/destination-calendars/new.ts index 514217401c..485219322d 100644 --- a/pages/api/destination-calendars/new.ts +++ b/pages/api/destination-calendars/new.ts @@ -3,7 +3,7 @@ import prisma from "@calcom/prisma"; import { DestinationCalendar } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaDestinationCalendar, withValidDestinationCalendar } from "@lib/validations/destinationCalendar"; +import { schemaDestinationCalendar, withValidDestinationCalendar } from "@lib/validations/destination-calendar"; type ResponseData = { data?: DestinationCalendar; diff --git a/pages/api/selected-calendars/[id]/edit.ts b/pages/api/selected-calendars/[id]/edit.ts index c53dc4222e..10d5bfde02 100644 --- a/pages/api/selected-calendars/[id]/edit.ts +++ b/pages/api/selected-calendars/[id]/edit.ts @@ -3,7 +3,7 @@ import prisma from "@calcom/prisma"; import { SelectedCalendar } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaSelectedCalendar, withValidSelectedCalendar } from "@lib/validations/selectedCalendar"; +import { schemaSelectedCalendar, withValidSelectedCalendar } from "@lib/validations/selected-calendar"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { diff --git a/pages/api/selected-calendars/new.ts b/pages/api/selected-calendars/new.ts index 649e276a5e..ee17fcf477 100644 --- a/pages/api/selected-calendars/new.ts +++ b/pages/api/selected-calendars/new.ts @@ -3,7 +3,7 @@ import prisma from "@calcom/prisma"; import { SelectedCalendar } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaSelectedCalendar, withValidSelectedCalendar } from "@lib/validations/selectedCalendar"; +import { schemaSelectedCalendar, withValidSelectedCalendar } from "@lib/validations/selected-calendar"; type ResponseData = { data?: SelectedCalendar; From 1de7bc4146a770068709d3524c636d7afffe592d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 30 Mar 2022 14:17:55 +0200 Subject: [PATCH 045/658] prettier --- .eslintrc.json | 28 ++++--- .prettierignore | 3 + README.md | 6 +- jest.config.ts | 30 +------ lib/helpers/addRequestid.ts | 12 +-- lib/helpers/captureErrors.ts | 6 +- lib/helpers/httpMethods.ts | 14 ++-- lib/helpers/verifyApiKey.ts | 25 +++--- lib/helpers/withMiddleware.ts | 19 +++-- lib/types.ts | 22 +++++ lib/utils/stringifyISODate.ts | 8 +- lib/validations/apiKey.ts | 25 +++--- lib/validations/availability.ts | 4 +- lib/validations/booking-reference.ts | 4 +- lib/validations/booking.ts | 2 +- lib/validations/credential.ts | 4 +- lib/validations/daily-event-reference.ts | 4 +- lib/validations/destination-calendar.ts | 4 +- lib/validations/eventType.ts | 2 +- lib/validations/membership.ts | 4 +- lib/validations/payment.ts | 4 +- lib/validations/schedule.ts | 4 +- lib/validations/selected-calendar.ts | 4 +- lib/validations/shared/baseApiParams.ts | 13 +++ lib/validations/shared/queryIdString.ts | 17 ++-- .../shared/queryIdTransformParseInt.ts | 15 ++-- lib/validations/team.ts | 2 +- lib/validations/user.ts | 80 ++++++------------- lib/validations/webhook.ts | 4 +- next.config.js | 4 +- package.json | 2 +- pages/_middleware.ts | 3 +- pages/api/api-keys/[id]/delete.ts | 11 +-- pages/api/api-keys/[id]/edit.ts | 36 +++++---- pages/api/api-keys/[id]/index.ts | 18 ++--- pages/api/api-keys/index.ts | 11 +-- pages/api/api-keys/new.ts | 22 +++-- pages/api/attendees/[id]/delete.ts | 13 +-- pages/api/attendees/[id]/edit.ts | 34 +++++--- pages/api/attendees/[id]/index.ts | 13 +-- pages/api/attendees/index.ts | 6 +- pages/api/attendees/new.ts | 18 ++--- pages/api/availabilities/[id]/delete.ts | 13 +-- pages/api/availabilities/[id]/edit.ts | 30 ++++--- pages/api/availabilities/[id]/index.ts | 14 ++-- pages/api/availabilities/index.ts | 6 +- pages/api/availabilities/new.ts | 10 ++- pages/api/booking-references/[id]/delete.ts | 16 ++-- pages/api/booking-references/[id]/edit.ts | 26 +++--- pages/api/booking-references/[id]/index.ts | 12 +-- pages/api/booking-references/index.ts | 6 +- pages/api/booking-references/new.ts | 18 +++-- pages/api/bookings/[id]/delete.ts | 16 ++-- pages/api/bookings/[id]/edit.ts | 34 +++++--- pages/api/bookings/[id]/index.ts | 12 +-- pages/api/bookings/index.ts | 6 +- pages/api/bookings/new.ts | 6 +- pages/api/credentials/[id]/delete.ts | 16 ++-- pages/api/credentials/[id]/edit.ts | 26 +++--- pages/api/credentials/[id]/index.ts | 12 +-- pages/api/credentials/index.ts | 6 +- pages/api/credentials/new.ts | 16 ++-- .../api/daily-event-references/[id]/delete.ts | 26 +++--- pages/api/daily-event-references/[id]/edit.ts | 31 ++++--- .../api/daily-event-references/[id]/index.ts | 12 +-- pages/api/daily-event-references/index.ts | 6 +- pages/api/daily-event-references/new.ts | 23 +++--- .../api/destination-calendars/[id]/delete.ts | 16 ++-- pages/api/destination-calendars/[id]/edit.ts | 31 ++++--- pages/api/destination-calendars/[id]/index.ts | 12 +-- pages/api/destination-calendars/index.ts | 6 +- pages/api/destination-calendars/new.ts | 23 +++--- .../event-type-custom-inputs/[id]/delete.ts | 16 ++-- .../api/event-type-custom-inputs/[id]/edit.ts | 31 ++++--- .../event-type-custom-inputs/[id]/index.ts | 12 +-- pages/api/event-type-custom-inputs/index.ts | 6 +- pages/api/event-type-custom-inputs/new.ts | 23 +++--- pages/api/event-types/[id]/delete.ts | 19 +++-- pages/api/event-types/[id]/edit.ts | 34 +++++--- pages/api/event-types/[id]/index.ts | 12 +-- pages/api/event-types/index.ts | 12 +-- pages/api/event-types/new.ts | 6 +- pages/api/memberships/[id]/delete.ts | 16 ++-- pages/api/memberships/[id]/edit.ts | 26 +++--- pages/api/memberships/[id]/index.ts | 12 +-- pages/api/memberships/index.ts | 6 +- pages/api/memberships/new.ts | 16 ++-- pages/api/schedules/[id]/delete.ts | 13 +-- pages/api/schedules/[id]/edit.ts | 26 +++--- pages/api/schedules/[id]/index.ts | 12 +-- pages/api/schedules/index.ts | 6 +- pages/api/schedules/new.ts | 16 ++-- pages/api/selected-calendars/[id]/delete.ts | 16 ++-- pages/api/selected-calendars/[id]/edit.ts | 26 +++--- pages/api/selected-calendars/[id]/index.ts | 12 +-- pages/api/selected-calendars/index.ts | 6 +- pages/api/selected-calendars/new.ts | 18 +++-- pages/api/teams/[id]/delete.ts | 36 +++++---- pages/api/teams/[id]/edit.ts | 51 ++++++------ pages/api/teams/[id]/index.ts | 35 ++++---- pages/api/teams/index.ts | 21 +++-- pages/api/teams/new.ts | 27 ++++--- pages/api/users/[id]/delete.ts | 40 +++++----- pages/api/users/[id]/edit.ts | 53 ++++++------ pages/api/users/[id]/index.ts | 43 +++++----- pages/api/users/index.ts | 27 ++++--- pages/api/users/new.ts | 35 ++++---- prettier.rc.js | 7 ++ tests/api-keys/[id]/api-key.id.delete.test.ts | 26 +++--- tests/api-keys/[id]/api-key.id.edit.test.ts | 44 ++++++---- tests/api-keys/[id]/api-key.id.index.test.ts | 15 ++-- tests/api-keys/api-key.index.test.ts | 14 +++- tests/api-keys/api-key.new.test.ts | 30 ++++--- tests/bookings/[id]/booking.id.edit.test.ts | 46 ++++++++--- tests/bookings/[id]/booking.id.index.test.ts | 7 +- tests/bookings/booking.index.test.ts | 14 +++- tests/bookings/booking.new.test.ts | 30 ++++--- .../[id]/event-type.id.edit.test.ts | 46 ++++++++--- .../[id]/event-type.id.index.test.ts | 2 - tests/event-types/event-type.index.test.ts | 3 +- tests/event-types/event-type.new.test.ts | 16 ++-- tests/teams/[id]/team.id.edit.test.ts | 39 ++++++--- tests/teams/[id]/team.id.index.test.ts | 2 - tests/users/[id]/user.id.edit.test.ts | 46 ++++++++--- tests/users/[id]/user.id.index.test.ts | 11 ++- tsconfig.json | 21 ++--- 126 files changed, 1240 insertions(+), 992 deletions(-) create mode 100644 .prettierignore create mode 100644 lib/types.ts create mode 100644 lib/validations/shared/baseApiParams.ts create mode 100644 prettier.rc.js diff --git a/.eslintrc.json b/.eslintrc.json index 176de0b130..0378cf43af 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,15 +1,17 @@ // FIXME: import eslint-config-calcom-base from '@calcom/config/eslint { - "root": true, - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:@next/next/recommended" - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { "project": ["./tsconfig.json"] }, - "plugins": [ - "@typescript-eslint" - ], - "ignorePatterns": ["src/**/*.test.ts", "src/frontend/generated/*"] -} \ No newline at end of file + "root": true, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended", + "plugin:@next/next/recommended" + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { "project": ["./tsconfig.json"] }, + "plugins": ["@typescript-eslint", "prettier"], + "rules": { + "prettier/prettier": "error" + }, + "ignorePatterns": ["src/**/*.test.ts", "src/frontend/generated/*"] +} diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000000..9e622a406d --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +.next/ +coverage/ +node_modules/ \ No newline at end of file diff --git a/README.md b/README.md index dc598bf1e8..2ede2ddbc9 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,6 @@ It doesn't have react or react-dom as a dependency, and will only be used by a r - `api.cal.com/v1` - `api.cal.com/api/v1` - ## API Endpoint Validation ### Zod @@ -32,7 +31,6 @@ We also use this useful helper library that let's us wrap our endpoints in a val We aim to provide a fully tested API for our peace of mind, this is accomplished by using jest + node-mocks-http - ## Next.config.js ### Redirects @@ -40,15 +38,14 @@ We aim to provide a fully tested API for our peace of mind, this is accomplished Since this will only support an API, we redirect the requests to root to the /api folder. We also added a redirect for future-proofing API versioning when we might need it, without having to resort to dirty hacks like a v1/v2 folders with lots of duplicated code, instead we redirect /api/v*/:rest to /api/:rest?version=* - The priority is the booking-related API routes so people can build their own booking flow, then event type management routes, then availability management routes etc - How to add a new model or endpoint Basically there's three places of the codebase you need to think about for each feature. /pages/api/ + - This is the most important one, and where your endpoint will live. You will leverage nextjs dynamic routes and expose one file for each endpoint you want to support ideally. ## How the codebase is organized. @@ -66,7 +63,6 @@ GET pages/api/endpoint/[id]/index.ts - Read All of your resource PATCH pages/api/endpoint/[id]/edit.ts - Create new resource DELETE pages/api/endpoint/[id]/delete.ts - Create new resource - ## `/tests/` This is where all your endpoint's tests live, we mock prisma calls. We aim for at least 50% global coverage. Test each of your endpoints. diff --git a/jest.config.ts b/jest.config.ts index d52a95bf87..7923b4cacc 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -7,10 +7,8 @@ const config = { clearMocks: true, coverageDirectory: "./coverage", collectCoverage: true, - "collectCoverageFrom": [ - "pages/api/**/*.ts" - ], - + collectCoverageFrom: ["pages/api/**/*.ts"], + // An array of regexp pattern strings used to skip coverage collection // coveragePathIgnorePatterns: [ // "/node_modules/" @@ -20,12 +18,7 @@ const config = { // coverageProvider: "babel", // A list of reporter names that Jest uses when writing coverage reports - coverageReporters: [ - "json", - "text", - "lcov", - "clover" - ], + coverageReporters: ["json", "text", "lcov", "clover"], // An object that configures minimum threshold enforcement for coverage results coverageThreshold: { @@ -42,34 +35,19 @@ const config = { // Make calling deprecated APIs throw helpful error messages errorOnDeprecated: true, - // Force coverage collection from ignored files using an array of glob patterns - // forceCoverageMatch: [], - - // A path to a module which exports an async function that is triggered once before all test suites - // globalSetup: undefined, - - // A path to a module which exports an async function that is triggered once after all test suites - // globalTeardown: undefined, - - // A set of global variables that need to be available in all test environments - // globals: {}, - // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. maxWorkers: "50%", - - moduleNameMapper: { "^@lib/(.*)$": "/lib/$1", "^@api/(.*)$": "/pages/api/$1", }, - // The paths to modules that run some code to configure or set up the testing environment before each test // setupFiles: [], // A list of paths to modules that run some code to configure or set up the testing framework before each test - setupFilesAfterEnv: ['/jest.setup.ts'], + setupFilesAfterEnv: ["/jest.setup.ts"], // The number of seconds after which a test is considered as slow and reported as such in the results. slowTestThreshold: 0.1, diff --git a/lib/helpers/addRequestid.ts b/lib/helpers/addRequestid.ts index 2096927a1e..af151e00cc 100644 --- a/lib/helpers/addRequestid.ts +++ b/lib/helpers/addRequestid.ts @@ -1,9 +1,9 @@ -import { NextMiddleware } from "next-api-middleware"; import { nanoid } from "nanoid"; +import { NextMiddleware } from "next-api-middleware"; export const addRequestId: NextMiddleware = async (_req, res, next) => { - // Apply header - res.setHeader("X-Response-ID", nanoid()); - // Let remaining middleware and API route execute - await next(); -}; \ No newline at end of file + // Apply header + res.setHeader("Calcom-Response-ID", nanoid()); + // Let remaining middleware and API route execute + await next(); +}; diff --git a/lib/helpers/captureErrors.ts b/lib/helpers/captureErrors.ts index b78174f36a..9229ad92d8 100644 --- a/lib/helpers/captureErrors.ts +++ b/lib/helpers/captureErrors.ts @@ -1,5 +1,5 @@ -import { NextMiddleware } from "next-api-middleware"; import * as Sentry from "@sentry/nextjs"; +import { NextMiddleware } from "next-api-middleware"; export const captureErrors: NextMiddleware = async (_req, res, next) => { try { @@ -7,10 +7,8 @@ export const captureErrors: NextMiddleware = async (_req, res, next) => { // middleware and the API route handler await next(); } catch (err) { - const eventId = Sentry.captureException(err); - console.log(eventId) + Sentry.captureException(err); res.status(500); res.json({ error: err }); } }; - diff --git a/lib/helpers/httpMethods.ts b/lib/helpers/httpMethods.ts index 4bfeb1b1fe..d19102d4dc 100644 --- a/lib/helpers/httpMethods.ts +++ b/lib/helpers/httpMethods.ts @@ -1,19 +1,17 @@ import { NextMiddleware } from "next-api-middleware"; -export const httpMethod = ( - allowedHttpMethod: "GET" | "POST" | "PATCH" | "DELETE" -): NextMiddleware => { +export const httpMethod = (allowedHttpMethod: "GET" | "POST" | "PATCH" | "DELETE"): NextMiddleware => { return async function (req, res, next) { if (req.method === allowedHttpMethod || req.method == "OPTIONS") { await next(); } else { - res.status(404); + res.status(405).json({ message: `Only ${allowedHttpMethod} Method allowed` }); res.end(); } }; }; -export const postOnly = httpMethod("POST"); -export const getOnly = httpMethod("GET"); -export const patchOnly = httpMethod("PATCH"); -export const deleteOnly = httpMethod("DELETE"); \ No newline at end of file +export const HTTP_POST = httpMethod("POST"); +export const HTTP_GET = httpMethod("GET"); +export const HTTP_PATCH = httpMethod("PATCH"); +export const HTTP_DELETE = httpMethod("DELETE"); diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index ffc602dcde..0da9a2090b 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -1,20 +1,23 @@ import { NextMiddleware } from "next-api-middleware"; + // import { nanoid } from "nanoid"; import prisma from "@calcom/prisma"; const dateInPast = function (firstDate: Date, secondDate: Date) { - if (firstDate.setHours(0, 0, 0, 0) <= secondDate.setHours(0, 0, 0, 0)) { - return true; - } -} + if (firstDate.setHours(0, 0, 0, 0) <= secondDate.setHours(0, 0, 0, 0)) { + return true; + } +}; const today = new Date(); export const verifyApiKey: NextMiddleware = async (req, res, next) => { - const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.apiKey as string } }); - if (!apiKey) { - res.status(400).json({ error: 'Your api key is not valid' }); - throw new Error('No api key found'); - } - if (apiKey.expiresAt && dateInPast(apiKey.expiresAt, today)) await next(); - else res.status(400).json({ error: 'Your api key is not valid' }); + const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.apiKey as string } }); + if (!apiKey) { + res.status(400).json({ error: "Your api key is not valid" }); + throw new Error("No api key found"); + } + if (apiKey.expiresAt && apiKey.userId && dateInPast(apiKey.expiresAt, today)) { + res.setHeader("Calcom-User-ID", apiKey.userId); + await next(); + } else res.status(400).json({ error: "Your api key is not valid" }); }; diff --git a/lib/helpers/withMiddleware.ts b/lib/helpers/withMiddleware.ts index 7d94e5da7a..c410882081 100644 --- a/lib/helpers/withMiddleware.ts +++ b/lib/helpers/withMiddleware.ts @@ -1,19 +1,22 @@ import { label } from "next-api-middleware"; + import { addRequestId } from "./addRequestid"; import { captureErrors } from "./captureErrors"; +import { HTTP_POST, HTTP_DELETE, HTTP_PATCH, HTTP_GET, httpMethod } from "./httpMethods"; import { verifyApiKey } from "./verifyApiKey"; -import { postOnly, deleteOnly, patchOnly, getOnly } from "./httpMethods"; + const withMiddleware = label( { - getOnly, - patchOnly, - postOnly, - deleteOnly, + HTTP_GET, + HTTP_PATCH, + HTTP_POST, + HTTP_DELETE, addRequestId, verifyApiKey, - sentry: captureErrors, // <-- Optionally alias middleware + sentry: captureErrors, + httpMethod: httpMethod("GET" || "DELETE" || "PATCH" || "POST"), }, - ["sentry","verifyApiKey"] // <-- Provide a list of middleware to call automatically + ["sentry", "verifyApiKey", "httpMethod", "addRequestId"] // <-- Provide a list of middleware to call automatically ); -export { withMiddleware }; \ No newline at end of file +export { withMiddleware }; diff --git a/lib/types.ts b/lib/types.ts new file mode 100644 index 0000000000..fde9ba7e87 --- /dev/null +++ b/lib/types.ts @@ -0,0 +1,22 @@ +import { User, ApiKey } from "@calcom/prisma/client"; + +// Base response, used for all responses +export type BaseResponse = { + message?: string; + error?: Error; +}; +// User +export type UserResponse = BaseResponse & { + data?: Partial; +}; +export type UsersResponse = BaseResponse & { + data?: Partial[]; +}; + +// API Key +export type ApiKeyResponse = BaseResponse & { + data?: Partial; +}; +export type ApiKeysResponse = BaseResponse & { + data?: Partial[]; +}; diff --git a/lib/utils/stringifyISODate.ts b/lib/utils/stringifyISODate.ts index 17be60bed7..cf21cd804b 100644 --- a/lib/utils/stringifyISODate.ts +++ b/lib/utils/stringifyISODate.ts @@ -1,4 +1,4 @@ -export const stringifyISODate = (date: Date|undefined): string => { - return `${date?.toISOString()}` -} -// TODO: create a function that takes an object and returns a stringified version of dates of it. \ No newline at end of file +export const stringifyISODate = (date: Date | undefined): string => { + return `${date?.toISOString()}`; +}; +// TODO: create a function that takes an object and returns a stringified version of dates of it. diff --git a/lib/validations/apiKey.ts b/lib/validations/apiKey.ts index a8d89d78f3..2d93b31e09 100644 --- a/lib/validations/apiKey.ts +++ b/lib/validations/apiKey.ts @@ -1,19 +1,16 @@ import { withValidation } from "next-validations"; -import { z } from "zod"; -const schemaApiKey = z - .object({ - // We need to cast the date as strings as when we get it from the json response - // we serve in api it is a string too (JSON doesn't directly support Date types) - createdAt: z.date().optional().or(z.string().optional()), - expiresAt: z.date().optional(), // default is 30 days - note: z.string().min(1).optional(), - }) - .strict(); // Adding strict so that we can disallow passing in extra fields -const withValidApiKey = withValidation({ - schema: schemaApiKey, +import { _ApiKeyModel as ApiKey } from "@calcom/prisma/zod"; + +export const schemaApiKeyBodyParams = ApiKey.omit({ id: true, userId: true, createdAt: true }); + +export const schemaApiKeyPublic = ApiKey.omit({ + id: true, + userId: true, +}); + +export const withValidApiKey = withValidation({ + schema: schemaApiKeyBodyParams, type: "Zod", mode: "body", }); - -export { schemaApiKey, withValidApiKey }; diff --git a/lib/validations/availability.ts b/lib/validations/availability.ts index 1bffc5acec..24f692118b 100644 --- a/lib/validations/availability.ts +++ b/lib/validations/availability.ts @@ -7,13 +7,13 @@ const schemaAvailability = z userId: z.number(), eventTypeId: z.number(), scheduleId: z.number(), - + days: z.array(z.number()), date: z.date().or(z.string()), startTime: z.string(), endTime: z.string(), }) - .strict(); + .strict(); const withValidAvailability = withValidation({ schema: schemaAvailability, type: "Zod", diff --git a/lib/validations/booking-reference.ts b/lib/validations/booking-reference.ts index 3a7298b9ac..fc1fe225c6 100644 --- a/lib/validations/booking-reference.ts +++ b/lib/validations/booking-reference.ts @@ -1,9 +1,7 @@ import { withValidation } from "next-validations"; import { z } from "zod"; -const schemaBookingReference = z - .object({}) - .strict(); +const schemaBookingReference = z.object({}).strict(); const withValidBookingReference = withValidation({ schema: schemaBookingReference, type: "Zod", diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index 7c07aac283..74834e9e0e 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -15,7 +15,7 @@ const schemaBooking = z rejected: z.boolean().default(false), paid: z.boolean().default(false), }) - .strict(); + .strict(); const withValidBooking = withValidation({ schema: schemaBooking, type: "Zod", diff --git a/lib/validations/credential.ts b/lib/validations/credential.ts index b0b142bfd3..4f371491d4 100644 --- a/lib/validations/credential.ts +++ b/lib/validations/credential.ts @@ -1,9 +1,7 @@ import { withValidation } from "next-validations"; import { z } from "zod"; -const schemaCredential = z - .object({}) - .strict(); +const schemaCredential = z.object({}).strict(); const withValidCredential = withValidation({ schema: schemaCredential, type: "Zod", diff --git a/lib/validations/daily-event-reference.ts b/lib/validations/daily-event-reference.ts index 48a8a93e62..3fcdcb2553 100644 --- a/lib/validations/daily-event-reference.ts +++ b/lib/validations/daily-event-reference.ts @@ -1,9 +1,7 @@ import { withValidation } from "next-validations"; import { z } from "zod"; -const schemaDailyEventReference = z - .object({}) - .strict(); +const schemaDailyEventReference = z.object({}).strict(); const withValidDailyEventReference = withValidation({ schema: schemaDailyEventReference, type: "Zod", diff --git a/lib/validations/destination-calendar.ts b/lib/validations/destination-calendar.ts index 34fa856897..541d9db59f 100644 --- a/lib/validations/destination-calendar.ts +++ b/lib/validations/destination-calendar.ts @@ -1,9 +1,7 @@ import { withValidation } from "next-validations"; import { z } from "zod"; -const schemaDestinationCalendar = z - .object({}) - .strict(); +const schemaDestinationCalendar = z.object({}).strict(); const withValidDestinationCalendar = withValidation({ schema: schemaDestinationCalendar, type: "Zod", diff --git a/lib/validations/eventType.ts b/lib/validations/eventType.ts index 34764a21ee..7d96883133 100644 --- a/lib/validations/eventType.ts +++ b/lib/validations/eventType.ts @@ -8,7 +8,7 @@ const schemaEventType = z length: z.number().min(1).max(1440), // max is a full day. description: z.string().min(3).optional(), }) - .strict(); + .strict(); const withValidEventType = withValidation({ schema: schemaEventType, type: "Zod", diff --git a/lib/validations/membership.ts b/lib/validations/membership.ts index 3d52743955..4b4a5a0c33 100644 --- a/lib/validations/membership.ts +++ b/lib/validations/membership.ts @@ -1,9 +1,7 @@ import { withValidation } from "next-validations"; import { z } from "zod"; -const schemaMembership = z - .object({}) - .strict(); +const schemaMembership = z.object({}).strict(); const withValidMembership = withValidation({ schema: schemaMembership, type: "Zod", diff --git a/lib/validations/payment.ts b/lib/validations/payment.ts index b9f019fe0d..f1ed09dcde 100644 --- a/lib/validations/payment.ts +++ b/lib/validations/payment.ts @@ -1,9 +1,7 @@ import { withValidation } from "next-validations"; import { z } from "zod"; -const schemaPayment = z - .object({}) - .strict(); +const schemaPayment = z.object({}).strict(); const withValidPayment = withValidation({ schema: schemaPayment, type: "Zod", diff --git a/lib/validations/schedule.ts b/lib/validations/schedule.ts index 9a0b0f286f..5c8e887271 100644 --- a/lib/validations/schedule.ts +++ b/lib/validations/schedule.ts @@ -1,9 +1,7 @@ import { withValidation } from "next-validations"; import { z } from "zod"; -const schemaSchedule = z - .object({}) - .strict(); +const schemaSchedule = z.object({}).strict(); const withValidSchedule = withValidation({ schema: schemaSchedule, type: "Zod", diff --git a/lib/validations/selected-calendar.ts b/lib/validations/selected-calendar.ts index b1646e1047..29ffdb9c11 100644 --- a/lib/validations/selected-calendar.ts +++ b/lib/validations/selected-calendar.ts @@ -1,9 +1,7 @@ import { withValidation } from "next-validations"; import { z } from "zod"; -const schemaSelectedCalendar = z - .object({}) - .strict(); +const schemaSelectedCalendar = z.object({}).strict(); const withValidSelectedCalendar = withValidation({ schema: schemaSelectedCalendar, type: "Zod", diff --git a/lib/validations/shared/baseApiParams.ts b/lib/validations/shared/baseApiParams.ts new file mode 100644 index 0000000000..03b13838ee --- /dev/null +++ b/lib/validations/shared/baseApiParams.ts @@ -0,0 +1,13 @@ +import { z } from "zod"; + +// Extracted out as utility function so can be reused +// at different endpoints that require this validation. +export const baseApiParams = z + .object({ + // since we added apiKey as query param this is required by next-validations helper + // for query params to work properly and not fail. + apiKey: z.string().cuid(), + // version required for supporting /v1/ redirect to query in api as *?version=1 + version: z.string().optional(), + }) + .strict(); diff --git a/lib/validations/shared/queryIdString.ts b/lib/validations/shared/queryIdString.ts index e89986dca5..718e26123f 100644 --- a/lib/validations/shared/queryIdString.ts +++ b/lib/validations/shared/queryIdString.ts @@ -1,23 +1,18 @@ import { withValidation } from "next-validations"; import { z } from "zod"; +import { baseApiParams } from "./baseApiParams"; + // Extracted out as utility function so can be reused // at different endpoints that require this validation. -const schemaQueryIdAsString = z - .object({ - // since we added apiKey as query param this is required by next-validations helper - // for query params to work properly and not fail. - apiKey: z.string().cuid(), - // since nextjs parses query params as strings, - // we need to cast them to numbers using z.transform() and parseInt() - id: z.string() +export const schemaQueryIdAsString = baseApiParams + .extend({ + id: z.string(), }) .strict(); -const withValidQueryIdString = withValidation({ +export const withValidQueryIdString = withValidation({ schema: schemaQueryIdAsString, type: "Zod", mode: "query", }); - -export { schemaQueryIdAsString, withValidQueryIdString }; diff --git a/lib/validations/shared/queryIdTransformParseInt.ts b/lib/validations/shared/queryIdTransformParseInt.ts index b1f2eb4835..b97d126d43 100644 --- a/lib/validations/shared/queryIdTransformParseInt.ts +++ b/lib/validations/shared/queryIdTransformParseInt.ts @@ -1,15 +1,12 @@ import { withValidation } from "next-validations"; import { z } from "zod"; +import { baseApiParams } from "./baseApiParams"; + // Extracted out as utility function so can be reused // at different endpoints that require this validation. -const schemaQueryIdParseInt = z - .object({ - // since we added apiKey as query param this is required by next-validations helper - // for query params to work properly and not fail. - apiKey: z.string().cuid(), - // since nextjs parses query params as strings, - // we need to cast them to numbers using z.transform() and parseInt() +export const schemaQueryIdParseInt = baseApiParams + .extend({ id: z .string() .regex(/^\d+$/) @@ -17,10 +14,8 @@ const schemaQueryIdParseInt = z }) .strict(); -const withValidQueryIdTransformParseInt = withValidation({ +export const withValidQueryIdTransformParseInt = withValidation({ schema: schemaQueryIdParseInt, type: "Zod", mode: "query", }); - -export { schemaQueryIdParseInt, withValidQueryIdTransformParseInt }; diff --git a/lib/validations/team.ts b/lib/validations/team.ts index 935f49ac1e..44cb1329a8 100644 --- a/lib/validations/team.ts +++ b/lib/validations/team.ts @@ -9,7 +9,7 @@ const schemaTeam = z bio: z.string().min(3).optional(), logo: z.string().optional(), }) - .strict(); + .strict(); const withValidTeam = withValidation({ schema: schemaTeam, type: "Zod", diff --git a/lib/validations/user.ts b/lib/validations/user.ts index b0fd00848c..2058a20c2e 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -1,63 +1,29 @@ import { withValidation } from "next-validations"; -import { z } from "zod"; -import { schemaEventType } from "./eventType"; -import { schemaApiKey } from "./apiKey"; -import { schemaDestinationCalendar } from "./destination-calendar"; -import { schemaWebhook } from "./webhook"; -import { schemaAvailability } from "./availability"; -import { schemaSelectedCalendar } from "./selected-calendar"; -import { schemaBooking } from "./booking"; -import { schemaMembership } from "./membership"; -import { schemaSchedule } from "./schedule"; -import { schemaCredential } from "./credential"; +import { _UserModel as User } from "@calcom/prisma/zod"; -const schemaUser = z - .object({ - username: z.string().min(3), - name: z.string().min(3), - email: z.string().email(), // max is a full day. - emailVerified: z.date().optional(), - password: z.string().optional(), - bio: z.string().min(3).optional(), - avatar: z.string().optional(), - timeZone: z.string().default("Europe/London"), - weekStart: z.string().default("Sunday"), - bufferTime: z.number().default(0), - hideBranding: z.boolean().default(false), - theme: z.string().optional(), - trialEndsAt: z.date().optional(), - eventTypes: z.array((schemaEventType)).optional(), - credentials: z.array((schemaCredential)).optional(), - teams: z.array((schemaMembership)).optional(), - bookings: z.array((schemaBooking)).optional(), - schedules: z.array((schemaSchedule)).optional(), - defaultScheduleId: z.number().optional(), - selectedCalendars: z.array((schemaSelectedCalendar)).optional(), - completedOnboarding: z.boolean().default(false), - locale: z.string().optional(), - timeFormat: z.number().optional().default(12), - twoFactorEnabled: z.boolean().default(false), - twoFactorSecret: z.string().optional(), - identityProvider: z.enum(["CAL", "SAML", "GOOGLE"]).optional().default("CAL"), - identityProviderId: z.string().optional(), - availability: z.array((schemaAvailability)).optional(), - invitedTo: z.number().optional(), - plan: z.enum(['FREE', 'TRIAL', 'PRO']).default("TRIAL"), - webhooks: z.array((schemaWebhook)).optional(), - brandColor: z.string().default("#292929"), - darkBrandColor: z.string().default("#fafafa"), - destinationCalendar: z.array(schemaDestinationCalendar).optional(), // FIXME: instanceof doesnt work here - away: z.boolean().default(false), - metadata: z.object({}).optional(), - verified: z.boolean().default(false), - apiKeys: z.array((schemaApiKey)).optional(), - }) - .strict(); -const withValidUser = withValidation({ - schema: schemaUser, +export const schemaUserBodyParams = User.omit({ + id: true, + createdAt: true, + password: true, + twoFactorEnabled: true, + twoFactorSecret: true, +}); + +export const schemaUserPublic = User.omit({ + identityProvider: true, + identityProviderId: true, + plan: true, + metadata: true, + password: true, + twoFactorEnabled: true, + twoFactorSecret: true, + trialEndsAt: true, + completedOnboarding: true, +}); + +export const withValidUser = withValidation({ + schema: schemaUserBodyParams, type: "Zod", mode: "body", }); - -export { schemaUser, withValidUser }; diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 1b1a35a2da..457a818815 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -1,9 +1,7 @@ import { withValidation } from "next-validations"; import { z } from "zod"; -const schemaWebhook = z - .object({}) - .strict(); +const schemaWebhook = z.object({}).strict(); const withValidWebhook = withValidation({ schema: schemaWebhook, diff --git a/next.config.js b/next.config.js index 7cd0ff53d7..1962fe9a8e 100644 --- a/next.config.js +++ b/next.config.js @@ -1,8 +1,6 @@ // https://www.npmjs.com/package/next-transpile-modules // This makes our @calcom/prisma package from the monorepo to be transpiled and usable by API -const withTM = require("next-transpile-modules")([ - "@calcom/prisma", -]); +const withTM = require("next-transpile-modules")(["@calcom/prisma", "@calcom/lib"]); // use something like withPlugins([withTM], {}) if more plugins added later. diff --git a/package.json b/package.json index feaee290bb..79ed5ea648 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "start": "next start", "build": "next build", "lint": "next lint", - "lint-fix": "next lint --fix", + "lint-fix": "next lint --fix && prettier --write .", "test": "jest --detectOpenHandles", "type-check": "tsc --pretty --noEmit", "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist", diff --git a/pages/_middleware.ts b/pages/_middleware.ts index 624d392043..59f0b1501f 100644 --- a/pages/_middleware.ts +++ b/pages/_middleware.ts @@ -3,7 +3,8 @@ import { NextRequest, NextResponse } from "next/server"; // Not much useful yet as prisma.client can't be used in the middlewares (client is not available) // For now we just throw early if no apiKey is passed, // but we could also check if the apiKey is valid if we had prisma here. -export async function requireApiKeyAsQueryParams({ nextUrl }: NextRequest) { + +export default async function requireApiKeyAsQueryParams({ nextUrl }: NextRequest) { const response = NextResponse.next(); const apiKey = nextUrl.searchParams.get("apiKey"); diff --git a/pages/api/api-keys/[id]/delete.ts b/pages/api/api-keys/[id]/delete.ts index 722705a303..dbe8250fe2 100644 --- a/pages/api/api-keys/[id]/delete.ts +++ b/pages/api/api-keys/[id]/delete.ts @@ -1,7 +1,7 @@ - import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; + import { withMiddleware } from "@lib/helpers/withMiddleware"; import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; @@ -13,8 +13,7 @@ type ResponseData = { export async function deleteApiKey(req: NextApiRequest, res: NextApiResponse) { const safe = await schemaQueryIdAsString.safeParse(req.query); if (safe.success) { - const data = await prisma.apiKey - .delete({ where: { id: safe.data.id } }) + const data = await prisma.apiKey.delete({ where: { id: safe.data.id } }); // We only remove the apiKey type from the database if there's an existing resource. if (data) res.status(200).json({ message: `ApiKey with id: ${safe.data.id} deleted successfully` }); // This catches the error thrown by prisma.apiKey.delete() if the resource is not found. @@ -22,8 +21,4 @@ export async function deleteApiKey(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; + const { query, body } = req; const safeQuery = await schemaQueryIdAsString.safeParse(query); - const safeBody = await schemaApiKey.safeParse(body); + const safeBody = await schemaApiKeyBodyParams.safeParse(body); if (safeQuery.success && safeBody.success) { - const data = await prisma.apiKey.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) + const data = await prisma.apiKey.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); if (data) res.status(200).json({ data }); - else (error: unknown) => res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + else + (error: unknown) => + res + .status(404) + .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); } } -export default withMiddleware("patchOnly","addRequestId")( - withValidQueryIdString( - withValidApiKey( - editApiKey) - ) -); +export default withMiddleware( + "HTTP_PATCH", + "addRequestId" +)(withValidQueryIdString(withValidApiKey(editApiKey))); diff --git a/pages/api/api-keys/[id]/index.ts b/pages/api/api-keys/[id]/index.ts index 18d6dbcc69..36b9203667 100644 --- a/pages/api/api-keys/[id]/index.ts +++ b/pages/api/api-keys/[id]/index.ts @@ -1,14 +1,13 @@ -import prisma from "@calcom/prisma"; - -import { ApiKey } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; +import prisma from "@calcom/prisma"; +import { ApiKey } from "@calcom/prisma/client"; + import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; type ResponseData = { data?: ApiKey; - message?: string; error?: unknown; }; @@ -18,13 +17,8 @@ export async function apiKeyById(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaApiKey.safeParse(req.body); + const safe = schemaApiKeyBodyParams.safeParse(req.body); if (safe.success) { - const data = await prisma.apiKey - .create({ data: safe.data }) - if (data) res.status(201).json({ data }) - else (error: unknown) => res.status(400).json({ error: { message: "Could not create apiKey type", error: error } }); + const data = await prisma.apiKey.create({ data: safe.data }); + if (data) res.status(201).json({ data }); + else + (error: unknown) => res.status(400).json({ error: { message: "Could not create apiKey type", error } }); } } -export default withMiddleware("addRequestId","postOnly")( - withValidApiKey( - createApiKey - ) -); +export default withMiddleware("addRequestId", "HTTP_POST")(withValidApiKey(createApiKey)); diff --git a/pages/api/attendees/[id]/delete.ts b/pages/api/attendees/[id]/delete.ts index 21c0efaff4..99ca9eef3f 100644 --- a/pages/api/attendees/[id]/delete.ts +++ b/pages/api/attendees/[id]/delete.ts @@ -1,9 +1,11 @@ -import prisma from "@calcom/prisma"; - import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { message?: string; @@ -14,12 +16,11 @@ export async function attendee(req: NextApiRequest, res: NextApiResponse { - res.status(200).json({ data: attendee }); - }).catch(error => { - res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) - }); + await prisma.attendee + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((attendee) => { + res.status(200).json({ data: attendee }); + }) + .catch((error) => { + res + .status(404) + .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); + }); // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only PATCH Method allowed for updating attendees" }); + } else res.status(405).json({ message: "Only PATCH Method allowed for updating attendees" }); } export default withValidQueryIdTransformParseInt(withValidAttendee(editAttendee)); diff --git a/pages/api/attendees/[id]/index.ts b/pages/api/attendees/[id]/index.ts index a5521dd057..6fc30b78f2 100644 --- a/pages/api/attendees/[id]/index.ts +++ b/pages/api/attendees/[id]/index.ts @@ -1,9 +1,12 @@ -import prisma from "@calcom/prisma"; - -import { Attendee } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; +import { Attendee } from "@calcom/prisma/client"; + +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: Attendee; @@ -14,7 +17,7 @@ type ResponseData = { export async function attendee(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; const safe = await schemaQueryIdParseInt.safeParse(query); - + if (method === "GET" && safe.success) { const attendee = await prisma.attendee.findUnique({ where: { id: safe.data.id } }); diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index 1a105dd52d..c5ac16eb09 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -1,8 +1,8 @@ -import prisma from "@calcom/prisma"; - -import { Attendee } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; +import prisma from "@calcom/prisma"; +import { Attendee } from "@calcom/prisma/client"; + type ResponseData = { data?: Attendee[]; error?: unknown; diff --git a/pages/api/attendees/new.ts b/pages/api/attendees/new.ts index 12762f14f0..f01d7a3dbe 100644 --- a/pages/api/attendees/new.ts +++ b/pages/api/attendees/new.ts @@ -1,8 +1,8 @@ -import prisma from "@calcom/prisma"; - -import { Attendee } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; +import prisma from "@calcom/prisma"; +import { Attendee } from "@calcom/prisma/client"; + import { schemaAttendee, withValidAttendee } from "@lib/validations/attendee"; type ResponseData = { @@ -14,13 +14,13 @@ type ResponseData = { async function createAttendee(req: NextApiRequest, res: NextApiResponse) { const { body, method } = req; const safe = schemaAttendee.safeParse(body); - + if (method === "POST" && safe.success) { - await prisma.attendee - .create({ data: safe.data }) - .then((attendee) => res.status(201).json({ data: attendee })) - .catch((error) => res.status(400).json({ message: "Could not create attendee type", error: error })); - // Reject any other HTTP method than POST + await prisma.attendee + .create({ data: safe.data }) + .then((attendee) => res.status(201).json({ data: attendee })) + .catch((error) => res.status(400).json({ message: "Could not create attendee type", error: error })); + // Reject any other HTTP method than POST } else res.status(405).json({ error: "Only POST Method allowed" }); } diff --git a/pages/api/availabilities/[id]/delete.ts b/pages/api/availabilities/[id]/delete.ts index 43db244859..b59534eb08 100644 --- a/pages/api/availabilities/[id]/delete.ts +++ b/pages/api/availabilities/[id]/delete.ts @@ -1,8 +1,11 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { message?: string; @@ -13,12 +16,12 @@ export async function availability(req: NextApiRequest, res: NextApiResponse { + }) + .then((availability) => { res.status(200).json({ data: availability }); - }).catch(error => { - res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + }) + .catch((error) => { + res + .status(404) + .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); }); - // Reject any other HTTP method than PATCH - } else res.status(405).json({ message: "Only PATCH Method allowed for updating availabilities" }); + // Reject any other HTTP method than PATCH + } else res.status(405).json({ message: "Only PATCH Method allowed for updating availabilities" }); } export default withValidQueryIdTransformParseInt(withValidAvailability(editAvailability)); diff --git a/pages/api/availabilities/[id]/index.ts b/pages/api/availabilities/[id]/index.ts index 7d10930907..8e2573df69 100644 --- a/pages/api/availabilities/[id]/index.ts +++ b/pages/api/availabilities/[id]/index.ts @@ -1,9 +1,12 @@ -import prisma from "@calcom/prisma"; - -import { Availability } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; +import { Availability } from "@calcom/prisma/client"; + +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: Availability; @@ -14,7 +17,7 @@ type ResponseData = { export async function availability(req: NextApiRequest, res: NextApiResponse) { const { query, method } = req; const safe = await schemaQueryIdParseInt.safeParse(query); - + if (method === "GET" && safe.success) { const availability = await prisma.availability.findUnique({ where: { id: safe.data.id } }); @@ -24,5 +27,4 @@ export async function availability(req: NextApiRequest, res: NextApiResponse res.status(201).json({ data: availability })) - .catch((error) => res.status(400).json({ message: "Could not create availability type", error: error })); + .catch((error) => + res.status(400).json({ message: "Could not create availability type", error: error }) + ); } } else { // Reject any other HTTP method than POST diff --git a/pages/api/booking-references/[id]/delete.ts b/pages/api/booking-references/[id]/delete.ts index 13798382ba..6f7685854f 100644 --- a/pages/api/booking-references/[id]/delete.ts +++ b/pages/api/booking-references/[id]/delete.ts @@ -1,9 +1,11 @@ -import prisma from "@calcom/prisma"; - import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { message?: string; @@ -14,12 +16,12 @@ export async function deleteBookingReference(req: NextApiRequest, res: NextApiRe const { query, method } = req; const safe = await schemaQueryIdParseInt.safeParse(query); if (method === "DELETE" && safe.success && safe.data) { - const bookingReference = await prisma.bookingReference - .delete({ where: { id: safe.data.id } }) + const bookingReference = await prisma.bookingReference.delete({ where: { id: safe.data.id } }); // We only remove the bookingReference type from the database if there's an existing resource. - if (bookingReference) res.status(200).json({ message: `bookingReference with id: ${safe.data.id} deleted successfully` }); + if (bookingReference) + res.status(200).json({ message: `bookingReference with id: ${safe.data.id} deleted successfully` }); // This catches the error thrown by prisma.bookingReference.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); + else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` }); // Reject any other HTTP method than POST } else res.status(405).json({ message: "Only DELETE Method allowed" }); } diff --git a/pages/api/booking-references/[id]/edit.ts b/pages/api/booking-references/[id]/edit.ts index 834574a3a1..b1ecfcee35 100644 --- a/pages/api/booking-references/[id]/edit.ts +++ b/pages/api/booking-references/[id]/edit.ts @@ -1,10 +1,13 @@ -import prisma from "@calcom/prisma"; - -import { BookingReference } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; +import prisma from "@calcom/prisma"; +import { BookingReference } from "@calcom/prisma/client"; + import { schemaBookingReference, withValidBookingReference } from "@lib/validations/booking-reference"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: BookingReference; @@ -18,15 +21,18 @@ export async function editBookingReference(req: NextApiRequest, res: NextApiResp const safeBody = await schemaBookingReference.safeParse(body); if (method === "PATCH" && safeQuery.success && safeBody.success) { - const data = await prisma.bookingReference.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) + const data = await prisma.bookingReference.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); if (data) res.status(200).json({ data }); - else res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated` }) + else + res + .status(404) + .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated` }); // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only PATCH Method allowed for updating bookingReferences" }); + } else res.status(405).json({ message: "Only PATCH Method allowed for updating bookingReferences" }); } export default withValidQueryIdTransformParseInt(withValidBookingReference(editBookingReference)); diff --git a/pages/api/booking-references/[id]/index.ts b/pages/api/booking-references/[id]/index.ts index 8a649fb4d9..4e8483b797 100644 --- a/pages/api/booking-references/[id]/index.ts +++ b/pages/api/booking-references/[id]/index.ts @@ -1,9 +1,12 @@ -import prisma from "@calcom/prisma"; - -import { BookingReference } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; +import { BookingReference } from "@calcom/prisma/client"; + +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: BookingReference; @@ -23,5 +26,4 @@ export async function bookingReference(req: NextApiRequest, res: NextApiResponse } else res.status(405).json({ message: "Only GET Method allowed" }); } - export default withValidQueryIdTransformParseInt(bookingReference); diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index 460d681ca7..f0244da6bb 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -1,8 +1,8 @@ -import prisma from "@calcom/prisma"; - -import { BookingReference } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; +import prisma from "@calcom/prisma"; +import { BookingReference } from "@calcom/prisma/client"; + type ResponseData = { data?: BookingReference[]; error?: unknown; diff --git a/pages/api/booking-references/new.ts b/pages/api/booking-references/new.ts index e792e3f1c7..319e80404e 100644 --- a/pages/api/booking-references/new.ts +++ b/pages/api/booking-references/new.ts @@ -1,8 +1,8 @@ -import prisma from "@calcom/prisma"; - -import { BookingReference } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; +import prisma from "@calcom/prisma"; +import { BookingReference } from "@calcom/prisma/client"; + import { schemaBookingReference, withValidBookingReference } from "@lib/validations/booking-reference"; type ResponseData = { @@ -15,11 +15,13 @@ async function createBookingReference(req: NextApiRequest, res: NextApiResponse< const { body, method } = req; const safe = schemaBookingReference.safeParse(body); if (method === "POST" && safe.success) { - await prisma.bookingReference - .create({ data: safe.data }) - .then((data) => res.status(201).json({ data })) - .catch((error) => res.status(400).json({ message: "Could not create bookingReference type", error: error })); - // Reject any other HTTP method than POST + await prisma.bookingReference + .create({ data: safe.data }) + .then((data) => res.status(201).json({ data })) + .catch((error) => + res.status(400).json({ message: "Could not create bookingReference type", error: error }) + ); + // Reject any other HTTP method than POST } else res.status(405).json({ error: "Only POST Method allowed" }); } diff --git a/pages/api/bookings/[id]/delete.ts b/pages/api/bookings/[id]/delete.ts index 4150a66613..a2dad90c7e 100644 --- a/pages/api/bookings/[id]/delete.ts +++ b/pages/api/bookings/[id]/delete.ts @@ -1,9 +1,11 @@ -import prisma from "@calcom/prisma"; - import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { message?: string; @@ -14,14 +16,14 @@ export async function deleteBooking(req: NextApiRequest, res: NextApiResponse { - res.status(200).json({ data: booking }); - }).catch(error => { - res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) - }); + await prisma.booking + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((booking) => { + res.status(200).json({ data: booking }); + }) + .catch((error) => { + res + .status(404) + .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); + }); } } else { // Reject any other HTTP method than POST - res.status(405).json({ message: "Only PATCH Method allowed for updating bookings" }); + res.status(405).json({ message: "Only PATCH Method allowed for updating bookings" }); } } diff --git a/pages/api/bookings/[id]/index.ts b/pages/api/bookings/[id]/index.ts index dbe47a5f91..8311dea842 100644 --- a/pages/api/bookings/[id]/index.ts +++ b/pages/api/bookings/[id]/index.ts @@ -1,9 +1,12 @@ -import prisma from "@calcom/prisma"; - -import { Booking } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; +import { Booking } from "@calcom/prisma/client"; + +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: Booking; @@ -26,5 +29,4 @@ export async function booking(req: NextApiRequest, res: NextApiResponse res.status(201).json({ data })) - .catch((error) => res.status(400).json({ message: "Could not create credential type", error: error })); - // Reject any other HTTP method than POST + await prisma.credential + .create({ data: safe.data }) + .then((data) => res.status(201).json({ data })) + .catch((error) => res.status(400).json({ message: "Could not create credential type", error: error })); + // Reject any other HTTP method than POST } else res.status(405).json({ error: "Only POST Method allowed" }); } diff --git a/pages/api/daily-event-references/[id]/delete.ts b/pages/api/daily-event-references/[id]/delete.ts index 2a43ab2d7e..77c97782a6 100644 --- a/pages/api/daily-event-references/[id]/delete.ts +++ b/pages/api/daily-event-references/[id]/delete.ts @@ -1,10 +1,12 @@ -import prisma from "@calcom/prisma"; - import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; -import { withMiddleware } from "@lib/helpers/withMiddleware"; +import prisma from "@calcom/prisma"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { message?: string; @@ -14,19 +16,17 @@ type ResponseData = { export async function deleteDailyEventReference(req: NextApiRequest, res: NextApiResponse) { const safe = await schemaQueryIdParseInt.safeParse(req.query); if (safe.success) { - const deletedDailyEventReference = await prisma.dailyEventReference - .delete({ where: { id: safe.data.id } }) + const deletedDailyEventReference = await prisma.dailyEventReference.delete({ + where: { id: safe.data.id }, + }); // We only remove the dailyEventReference type from the database if there's an existing resource. - if (deletedDailyEventReference) res.status(200).json({ message: `dailyEventReference with id: ${safe.data.id} deleted successfully` }); + if (deletedDailyEventReference) + res.status(200).json({ message: `dailyEventReference with id: ${safe.data.id} deleted successfully` }); // This catches the error thrown by prisma.dailyEventReference.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); + else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` }); // Reject any other HTTP method than POST } else res.status(405).json({ message: "Only DELETE Method allowed" }); } // export default withValidQueryIdTransformParseInt(deleteDailyEventReference); -export default withMiddleware("deleteOnly")( - withValidQueryIdTransformParseInt( - deleteDailyEventReference - ) -); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteDailyEventReference)); diff --git a/pages/api/daily-event-references/[id]/edit.ts b/pages/api/daily-event-references/[id]/edit.ts index 30c5bbca78..372e258163 100644 --- a/pages/api/daily-event-references/[id]/edit.ts +++ b/pages/api/daily-event-references/[id]/edit.ts @@ -1,10 +1,16 @@ -import prisma from "@calcom/prisma"; - -import { DailyEventReference } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaDailyEventReference, withValidDailyEventReference } from "@lib/validations/daily-event-reference"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; +import { DailyEventReference } from "@calcom/prisma/client"; + +import { + schemaDailyEventReference, + withValidDailyEventReference, +} from "@lib/validations/daily-event-reference"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: DailyEventReference; @@ -18,15 +24,18 @@ export async function editDailyEventReference(req: NextApiRequest, res: NextApiR const safeBody = await schemaDailyEventReference.safeParse(body); if (method === "PATCH" && safeQuery.success && safeBody.success) { - const data = await prisma.dailyEventReference.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) + const data = await prisma.dailyEventReference.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); if (data) res.status(200).json({ data }); - else res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + else + res + .status(404) + .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only PATCH Method allowed for updating dailyEventReferences" }); + } else res.status(405).json({ message: "Only PATCH Method allowed for updating dailyEventReferences" }); } export default withValidQueryIdTransformParseInt(withValidDailyEventReference(editDailyEventReference)); diff --git a/pages/api/daily-event-references/[id]/index.ts b/pages/api/daily-event-references/[id]/index.ts index 166a661dcc..459c4f5381 100644 --- a/pages/api/daily-event-references/[id]/index.ts +++ b/pages/api/daily-event-references/[id]/index.ts @@ -1,9 +1,12 @@ -import prisma from "@calcom/prisma"; - -import { DailyEventReference } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; +import { DailyEventReference } from "@calcom/prisma/client"; + +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: DailyEventReference; @@ -23,5 +26,4 @@ export async function dailyEventReference(req: NextApiRequest, res: NextApiRespo } else res.status(405).json({ message: "Only GET Method allowed" }); } - export default withValidQueryIdTransformParseInt(dailyEventReference); diff --git a/pages/api/daily-event-references/index.ts b/pages/api/daily-event-references/index.ts index 7d25bba8f1..a5509f8a90 100644 --- a/pages/api/daily-event-references/index.ts +++ b/pages/api/daily-event-references/index.ts @@ -1,8 +1,8 @@ -import prisma from "@calcom/prisma"; - -import { DailyEventReference } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; +import prisma from "@calcom/prisma"; +import { DailyEventReference } from "@calcom/prisma/client"; + type ResponseData = { data?: DailyEventReference[]; error?: unknown; diff --git a/pages/api/daily-event-references/new.ts b/pages/api/daily-event-references/new.ts index 153742739a..5bbc67fb2c 100644 --- a/pages/api/daily-event-references/new.ts +++ b/pages/api/daily-event-references/new.ts @@ -1,9 +1,12 @@ -import prisma from "@calcom/prisma"; - -import { DailyEventReference } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaDailyEventReference, withValidDailyEventReference } from "@lib/validations/daily-event-reference"; +import prisma from "@calcom/prisma"; +import { DailyEventReference } from "@calcom/prisma/client"; + +import { + schemaDailyEventReference, + withValidDailyEventReference, +} from "@lib/validations/daily-event-reference"; type ResponseData = { data?: DailyEventReference; @@ -15,11 +18,13 @@ async function createDailyEventReference(req: NextApiRequest, res: NextApiRespon const { body, method } = req; const safe = schemaDailyEventReference.safeParse(body); if (method === "POST" && safe.success) { - await prisma.dailyEventReference - .create({ data: safe.data }) - .then((data) => res.status(201).json({ data })) - .catch((error) => res.status(400).json({ message: "Could not create dailyEventReference type", error: error })); - // Reject any other HTTP method than POST + await prisma.dailyEventReference + .create({ data: safe.data }) + .then((data) => res.status(201).json({ data })) + .catch((error) => + res.status(400).json({ message: "Could not create dailyEventReference type", error: error }) + ); + // Reject any other HTTP method than POST } else res.status(405).json({ error: "Only POST Method allowed" }); } diff --git a/pages/api/destination-calendars/[id]/delete.ts b/pages/api/destination-calendars/[id]/delete.ts index 246d5a58eb..b734fbdf9b 100644 --- a/pages/api/destination-calendars/[id]/delete.ts +++ b/pages/api/destination-calendars/[id]/delete.ts @@ -1,9 +1,11 @@ -import prisma from "@calcom/prisma"; - import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { message?: string; @@ -14,12 +16,12 @@ export async function deleteDestinationCalendar(req: NextApiRequest, res: NextAp const { query, method } = req; const safe = await schemaQueryIdParseInt.safeParse(query); if (method === "DELETE" && safe.success && safe.data) { - const destinationCalendar = await prisma.destinationCalendar - .delete({ where: { id: safe.data.id } }) + const destinationCalendar = await prisma.destinationCalendar.delete({ where: { id: safe.data.id } }); // We only remove the destinationCalendar type from the database if there's an existing resource. - if (destinationCalendar) res.status(200).json({ message: `destinationCalendar with id: ${safe.data.id} deleted successfully` }); + if (destinationCalendar) + res.status(200).json({ message: `destinationCalendar with id: ${safe.data.id} deleted successfully` }); // This catches the error thrown by prisma.destinationCalendar.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); + else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` }); // Reject any other HTTP method than POST } else res.status(405).json({ message: "Only DELETE Method allowed" }); } diff --git a/pages/api/destination-calendars/[id]/edit.ts b/pages/api/destination-calendars/[id]/edit.ts index 5495656d70..09c042b7e1 100644 --- a/pages/api/destination-calendars/[id]/edit.ts +++ b/pages/api/destination-calendars/[id]/edit.ts @@ -1,10 +1,16 @@ -import prisma from "@calcom/prisma"; - -import { DestinationCalendar } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaDestinationCalendar, withValidDestinationCalendar } from "@lib/validations/destination-calendar"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; +import { DestinationCalendar } from "@calcom/prisma/client"; + +import { + schemaDestinationCalendar, + withValidDestinationCalendar, +} from "@lib/validations/destination-calendar"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: DestinationCalendar; @@ -18,15 +24,18 @@ export async function editDestinationCalendar(req: NextApiRequest, res: NextApiR const safeBody = await schemaDestinationCalendar.safeParse(body); if (method === "PATCH" && safeQuery.success && safeBody.success) { - const data = await prisma.destinationCalendar.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) + const data = await prisma.destinationCalendar.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); if (data) res.status(200).json({ data }); - else res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + else + res + .status(404) + .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only PATCH Method allowed for updating destinationCalendars" }); + } else res.status(405).json({ message: "Only PATCH Method allowed for updating destinationCalendars" }); } export default withValidQueryIdTransformParseInt(withValidDestinationCalendar(editDestinationCalendar)); diff --git a/pages/api/destination-calendars/[id]/index.ts b/pages/api/destination-calendars/[id]/index.ts index 95a44a5edf..fde198f77f 100644 --- a/pages/api/destination-calendars/[id]/index.ts +++ b/pages/api/destination-calendars/[id]/index.ts @@ -1,9 +1,12 @@ -import prisma from "@calcom/prisma"; - -import { DestinationCalendar } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; +import { DestinationCalendar } from "@calcom/prisma/client"; + +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: DestinationCalendar; @@ -23,5 +26,4 @@ export async function destinationCalendar(req: NextApiRequest, res: NextApiRespo } else res.status(405).json({ message: "Only GET Method allowed" }); } - export default withValidQueryIdTransformParseInt(destinationCalendar); diff --git a/pages/api/destination-calendars/index.ts b/pages/api/destination-calendars/index.ts index 3877dbc08a..933ef20568 100644 --- a/pages/api/destination-calendars/index.ts +++ b/pages/api/destination-calendars/index.ts @@ -1,8 +1,8 @@ -import prisma from "@calcom/prisma"; - -import { DestinationCalendar } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; +import prisma from "@calcom/prisma"; +import { DestinationCalendar } from "@calcom/prisma/client"; + type ResponseData = { data?: DestinationCalendar[]; error?: unknown; diff --git a/pages/api/destination-calendars/new.ts b/pages/api/destination-calendars/new.ts index 485219322d..483ff56de1 100644 --- a/pages/api/destination-calendars/new.ts +++ b/pages/api/destination-calendars/new.ts @@ -1,9 +1,12 @@ -import prisma from "@calcom/prisma"; - -import { DestinationCalendar } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaDestinationCalendar, withValidDestinationCalendar } from "@lib/validations/destination-calendar"; +import prisma from "@calcom/prisma"; +import { DestinationCalendar } from "@calcom/prisma/client"; + +import { + schemaDestinationCalendar, + withValidDestinationCalendar, +} from "@lib/validations/destination-calendar"; type ResponseData = { data?: DestinationCalendar; @@ -15,11 +18,13 @@ async function createDestinationCalendar(req: NextApiRequest, res: NextApiRespon const { body, method } = req; const safe = schemaDestinationCalendar.safeParse(body); if (method === "POST" && safe.success) { - await prisma.destinationCalendar - .create({ data: safe.data }) - .then((data) => res.status(201).json({ data })) - .catch((error) => res.status(400).json({ message: "Could not create destinationCalendar type", error: error })); - // Reject any other HTTP method than POST + await prisma.destinationCalendar + .create({ data: safe.data }) + .then((data) => res.status(201).json({ data })) + .catch((error) => + res.status(400).json({ message: "Could not create destinationCalendar type", error: error }) + ); + // Reject any other HTTP method than POST } else res.status(405).json({ error: "Only POST Method allowed" }); } diff --git a/pages/api/event-type-custom-inputs/[id]/delete.ts b/pages/api/event-type-custom-inputs/[id]/delete.ts index d4e8431f51..acccbac7d7 100644 --- a/pages/api/event-type-custom-inputs/[id]/delete.ts +++ b/pages/api/event-type-custom-inputs/[id]/delete.ts @@ -1,9 +1,11 @@ -import prisma from "@calcom/prisma"; - import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { message?: string; @@ -14,12 +16,12 @@ export async function deleteEventTypeCustomInput(req: NextApiRequest, res: NextA const { query, method } = req; const safe = await schemaQueryIdParseInt.safeParse(query); if (method === "DELETE" && safe.success && safe.data) { - const eventTypeCustomInput = await prisma.eventTypeCustomInput - .delete({ where: { id: safe.data.id } }) + const eventTypeCustomInput = await prisma.eventTypeCustomInput.delete({ where: { id: safe.data.id } }); // We only remove the eventTypeCustomInput type from the database if there's an existing resource. - if (eventTypeCustomInput) res.status(200).json({ message: `eventTypeCustomInput with id: ${safe.data.id} deleted successfully` }); + if (eventTypeCustomInput) + res.status(200).json({ message: `eventTypeCustomInput with id: ${safe.data.id} deleted successfully` }); // This catches the error thrown by prisma.eventTypeCustomInput.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); + else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` }); // Reject any other HTTP method than POST } else res.status(405).json({ message: "Only DELETE Method allowed" }); } diff --git a/pages/api/event-type-custom-inputs/[id]/edit.ts b/pages/api/event-type-custom-inputs/[id]/edit.ts index fcb650c906..1c632034c2 100644 --- a/pages/api/event-type-custom-inputs/[id]/edit.ts +++ b/pages/api/event-type-custom-inputs/[id]/edit.ts @@ -1,10 +1,16 @@ -import prisma from "@calcom/prisma"; - -import { EventTypeCustomInput } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaEventTypeCustomInput, withValidEventTypeCustomInput } from "@lib/validations/eventTypeCustomInput"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; +import { EventTypeCustomInput } from "@calcom/prisma/client"; + +import { + schemaEventTypeCustomInput, + withValidEventTypeCustomInput, +} from "@lib/validations/eventTypeCustomInput"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: EventTypeCustomInput; @@ -18,15 +24,18 @@ export async function editEventTypeCustomInput(req: NextApiRequest, res: NextApi const safeBody = await schemaEventTypeCustomInput.safeParse(body); if (method === "PATCH" && safeQuery.success && safeBody.success) { - const data = await prisma.eventTypeCustomInput.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) + const data = await prisma.eventTypeCustomInput.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); if (data) res.status(200).json({ data }); - else res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + else + res + .status(404) + .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only PATCH Method allowed for updating eventTypeCustomInputs" }); + } else res.status(405).json({ message: "Only PATCH Method allowed for updating eventTypeCustomInputs" }); } export default withValidQueryIdTransformParseInt(withValidEventTypeCustomInput(editEventTypeCustomInput)); diff --git a/pages/api/event-type-custom-inputs/[id]/index.ts b/pages/api/event-type-custom-inputs/[id]/index.ts index c53b2e4c06..47170af37d 100644 --- a/pages/api/event-type-custom-inputs/[id]/index.ts +++ b/pages/api/event-type-custom-inputs/[id]/index.ts @@ -1,9 +1,12 @@ -import prisma from "@calcom/prisma"; - -import { EventTypeCustomInput } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; +import { EventTypeCustomInput } from "@calcom/prisma/client"; + +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: EventTypeCustomInput; @@ -23,5 +26,4 @@ export async function eventTypeCustomInput(req: NextApiRequest, res: NextApiResp } else res.status(405).json({ message: "Only GET Method allowed" }); } - export default withValidQueryIdTransformParseInt(eventTypeCustomInput); diff --git a/pages/api/event-type-custom-inputs/index.ts b/pages/api/event-type-custom-inputs/index.ts index 733539064e..b39cd14bca 100644 --- a/pages/api/event-type-custom-inputs/index.ts +++ b/pages/api/event-type-custom-inputs/index.ts @@ -1,8 +1,8 @@ -import prisma from "@calcom/prisma"; - -import { EventTypeCustomInput } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; +import prisma from "@calcom/prisma"; +import { EventTypeCustomInput } from "@calcom/prisma/client"; + type ResponseData = { data?: EventTypeCustomInput[]; error?: unknown; diff --git a/pages/api/event-type-custom-inputs/new.ts b/pages/api/event-type-custom-inputs/new.ts index abdb410070..e2a4078a59 100644 --- a/pages/api/event-type-custom-inputs/new.ts +++ b/pages/api/event-type-custom-inputs/new.ts @@ -1,9 +1,12 @@ -import prisma from "@calcom/prisma"; - -import { EventTypeCustomInput } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaEventTypeCustomInput, withValidEventTypeCustomInput } from "@lib/validations/eventTypeCustomInput"; +import prisma from "@calcom/prisma"; +import { EventTypeCustomInput } from "@calcom/prisma/client"; + +import { + schemaEventTypeCustomInput, + withValidEventTypeCustomInput, +} from "@lib/validations/eventTypeCustomInput"; type ResponseData = { data?: EventTypeCustomInput; @@ -15,11 +18,13 @@ async function createEventTypeCustomInput(req: NextApiRequest, res: NextApiRespo const { body, method } = req; const safe = schemaEventTypeCustomInput.safeParse(body); if (method === "POST" && safe.success) { - await prisma.eventTypeCustomInput - .create({ data: safe.data }) - .then((data) => res.status(201).json({ data })) - .catch((error) => res.status(400).json({ message: "Could not create eventTypeCustomInput type", error: error })); - // Reject any other HTTP method than POST + await prisma.eventTypeCustomInput + .create({ data: safe.data }) + .then((data) => res.status(201).json({ data })) + .catch((error) => + res.status(400).json({ message: "Could not create eventTypeCustomInput type", error: error }) + ); + // Reject any other HTTP method than POST } else res.status(405).json({ error: "Only POST Method allowed" }); } diff --git a/pages/api/event-types/[id]/delete.ts b/pages/api/event-types/[id]/delete.ts index d94dc611a2..4155c87ce4 100644 --- a/pages/api/event-types/[id]/delete.ts +++ b/pages/api/event-types/[id]/delete.ts @@ -1,9 +1,11 @@ -import prisma from "@calcom/prisma"; - import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { message?: string; @@ -14,14 +16,15 @@ export async function deleteEventType(req: NextApiRequest, res: NextApiResponse< const { query, method } = req; const safe = await schemaQueryIdParseInt.safeParse(query); if (method === "DELETE" && safe.success && safe.data) { - const eventType = await prisma.eventType - .delete({ where: { id: safe.data.id } }) + const eventType = await prisma.eventType.delete({ where: { id: safe.data.id } }); // We only remove the eventType type from the database if there's an existing resource. - if (eventType) res.status(200).json({ message: `eventType with id: ${safe.data.id} deleted successfully` }); + if (eventType) + res.status(200).json({ message: `eventType with id: ${safe.data.id} deleted successfully` }); // This catches the error thrown by prisma.eventType.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); + else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` }); // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only DELETE Method allowed in /availabilities/[id]/delete endpoint" }); + } else + res.status(405).json({ message: "Only DELETE Method allowed in /availabilities/[id]/delete endpoint" }); } export default withValidQueryIdTransformParseInt(deleteEventType); diff --git a/pages/api/event-types/[id]/edit.ts b/pages/api/event-types/[id]/edit.ts index becd6b5255..6ebe32f026 100644 --- a/pages/api/event-types/[id]/edit.ts +++ b/pages/api/event-types/[id]/edit.ts @@ -1,10 +1,13 @@ -import prisma from "@calcom/prisma"; - -import { EventType } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; +import prisma from "@calcom/prisma"; +import { EventType } from "@calcom/prisma/client"; + import { schemaEventType, withValidEventType } from "@lib/validations/eventType"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: EventType; @@ -19,18 +22,23 @@ export async function editEventType(req: NextApiRequest, res: NextApiResponse { - res.status(200).json({ data: event }); - }).catch(error => { - res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) - }); + await prisma.eventType + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((event) => { + res.status(200).json({ data: event }); + }) + .catch((error) => { + res + .status(404) + .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); + }); } } else { // Reject any other HTTP method than POST - res.status(405).json({ message: "Only PATCH Method allowed for updating event-types" }); + res.status(405).json({ message: "Only PATCH Method allowed for updating event-types" }); } } diff --git a/pages/api/event-types/[id]/index.ts b/pages/api/event-types/[id]/index.ts index 9b8a159ab3..3e8b642379 100644 --- a/pages/api/event-types/[id]/index.ts +++ b/pages/api/event-types/[id]/index.ts @@ -1,9 +1,12 @@ -import prisma from "@calcom/prisma"; - -import { EventType } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; +import { EventType } from "@calcom/prisma/client"; + +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: EventType; @@ -26,5 +29,4 @@ export async function eventType(req: NextApiRequest, res: NextApiResponse res.status(201).json({ data })) - .catch((error) => res.status(400).json({ message: "Could not create membership type", error: error })); - // Reject any other HTTP method than POST + await prisma.membership + .create({ data: safe.data }) + .then((data) => res.status(201).json({ data })) + .catch((error) => res.status(400).json({ message: "Could not create membership type", error: error })); + // Reject any other HTTP method than POST } else res.status(405).json({ error: "Only POST Method allowed" }); } diff --git a/pages/api/schedules/[id]/delete.ts b/pages/api/schedules/[id]/delete.ts index 0dcaf7910a..17aba616cf 100644 --- a/pages/api/schedules/[id]/delete.ts +++ b/pages/api/schedules/[id]/delete.ts @@ -1,9 +1,11 @@ -import prisma from "@calcom/prisma"; - import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { message?: string; @@ -14,12 +16,11 @@ export async function deleteSchedule(req: NextApiRequest, res: NextApiResponse res.status(201).json({ data })) - .catch((error) => res.status(400).json({ message: "Could not create schedule type", error: error })); - // Reject any other HTTP method than POST + await prisma.schedule + .create({ data: safe.data }) + .then((data) => res.status(201).json({ data })) + .catch((error) => res.status(400).json({ message: "Could not create schedule type", error: error })); + // Reject any other HTTP method than POST } else res.status(405).json({ error: "Only POST Method allowed" }); } diff --git a/pages/api/selected-calendars/[id]/delete.ts b/pages/api/selected-calendars/[id]/delete.ts index 06a0c5a156..a3de0e715b 100644 --- a/pages/api/selected-calendars/[id]/delete.ts +++ b/pages/api/selected-calendars/[id]/delete.ts @@ -1,9 +1,11 @@ -import prisma from "@calcom/prisma"; - import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { message?: string; @@ -14,12 +16,12 @@ export async function deleteSelectedCalendar(req: NextApiRequest, res: NextApiRe const { query, method } = req; const safe = await schemaQueryIdParseInt.safeParse(query); if (method === "DELETE" && safe.success && safe.data) { - const selectedCalendar = await prisma.selectedCalendar - .delete({ where: { id: safe.data.id } }) + const selectedCalendar = await prisma.selectedCalendar.delete({ where: { id: safe.data.id } }); // We only remove the selectedCalendar type from the database if there's an existing resource. - if (selectedCalendar) res.status(200).json({ message: `selectedCalendar with id: ${safe.data.id} deleted successfully` }); + if (selectedCalendar) + res.status(200).json({ message: `selectedCalendar with id: ${safe.data.id} deleted successfully` }); // This catches the error thrown by prisma.selectedCalendar.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found`}); + else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` }); // Reject any other HTTP method than POST } else res.status(405).json({ message: "Only DELETE Method allowed" }); } diff --git a/pages/api/selected-calendars/[id]/edit.ts b/pages/api/selected-calendars/[id]/edit.ts index 10d5bfde02..0854ffd44f 100644 --- a/pages/api/selected-calendars/[id]/edit.ts +++ b/pages/api/selected-calendars/[id]/edit.ts @@ -1,10 +1,13 @@ -import prisma from "@calcom/prisma"; - -import { SelectedCalendar } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; +import prisma from "@calcom/prisma"; +import { SelectedCalendar } from "@calcom/prisma/client"; + import { schemaSelectedCalendar, withValidSelectedCalendar } from "@lib/validations/selected-calendar"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: SelectedCalendar; @@ -18,15 +21,18 @@ export async function editSelectedCalendar(req: NextApiRequest, res: NextApiResp const safeBody = await schemaSelectedCalendar.safeParse(body); if (method === "PATCH" && safeQuery.success && safeBody.success) { - const data = await prisma.selectedCalendar.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) + const data = await prisma.selectedCalendar.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); if (data) res.status(200).json({ data }); - else res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) + else + res + .status(404) + .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only PATCH Method allowed for updating selectedCalendars" }); + } else res.status(405).json({ message: "Only PATCH Method allowed for updating selectedCalendars" }); } export default withValidQueryIdTransformParseInt(withValidSelectedCalendar(editSelectedCalendar)); diff --git a/pages/api/selected-calendars/[id]/index.ts b/pages/api/selected-calendars/[id]/index.ts index 6afe9d3135..84a290ae20 100644 --- a/pages/api/selected-calendars/[id]/index.ts +++ b/pages/api/selected-calendars/[id]/index.ts @@ -1,9 +1,12 @@ -import prisma from "@calcom/prisma"; - -import { SelectedCalendar } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; +import { SelectedCalendar } from "@calcom/prisma/client"; + +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: SelectedCalendar; @@ -23,5 +26,4 @@ export async function selectedCalendar(req: NextApiRequest, res: NextApiResponse } else res.status(405).json({ message: "Only GET Method allowed" }); } - export default withValidQueryIdTransformParseInt(selectedCalendar); diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index d6a29e3dd3..0a4bbd5012 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -1,8 +1,8 @@ -import prisma from "@calcom/prisma"; - -import { SelectedCalendar } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; +import prisma from "@calcom/prisma"; +import { SelectedCalendar } from "@calcom/prisma/client"; + type ResponseData = { data?: SelectedCalendar[]; error?: unknown; diff --git a/pages/api/selected-calendars/new.ts b/pages/api/selected-calendars/new.ts index ee17fcf477..712a936733 100644 --- a/pages/api/selected-calendars/new.ts +++ b/pages/api/selected-calendars/new.ts @@ -1,8 +1,8 @@ -import prisma from "@calcom/prisma"; - -import { SelectedCalendar } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; +import prisma from "@calcom/prisma"; +import { SelectedCalendar } from "@calcom/prisma/client"; + import { schemaSelectedCalendar, withValidSelectedCalendar } from "@lib/validations/selected-calendar"; type ResponseData = { @@ -15,11 +15,13 @@ async function createSelectedCalendar(req: NextApiRequest, res: NextApiResponse< const { body, method } = req; const safe = schemaSelectedCalendar.safeParse(body); if (method === "POST" && safe.success) { - await prisma.selectedCalendar - .create({ data: safe.data }) - .then((data) => res.status(201).json({ data })) - .catch((error) => res.status(400).json({ message: "Could not create selectedCalendar type", error: error })); - // Reject any other HTTP method than POST + await prisma.selectedCalendar + .create({ data: safe.data }) + .then((data) => res.status(201).json({ data })) + .catch((error) => + res.status(400).json({ message: "Could not create selectedCalendar type", error: error }) + ); + // Reject any other HTTP method than POST } else res.status(405).json({ error: "Only POST Method allowed" }); } diff --git a/pages/api/teams/[id]/delete.ts b/pages/api/teams/[id]/delete.ts index 0593313440..3c88c02d28 100644 --- a/pages/api/teams/[id]/delete.ts +++ b/pages/api/teams/[id]/delete.ts @@ -1,29 +1,31 @@ - import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; + import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { - message?: string; - error?: unknown; + message: string; + error?: object; }; export async function deleteTeam(req: NextApiRequest, res: NextApiResponse) { const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (safe.success) { - const data = await prisma.team - .delete({ where: { id: safe.data.id } }) - // We only remove the team type from the database if there's an existing resource. - if (data) res.status(200).json({ message: `Team with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.team.delete() if the resource is not found. - else res.status(400).json({ message: `Team with id: ${safe.data.id} was not able to be processed` }); - } + if (!safe.success) throw new Error("Invalid request query"); + + const data = await prisma.team.delete({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ message: `Team with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `Team with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withMiddleware("deleteOnly", "addRequestId")( - withValidQueryIdTransformParseInt( - deleteTeam - ) -); +export default withMiddleware("HTTP_DELETE", "addRequestId")(withValidQueryIdTransformParseInt(deleteTeam)); diff --git a/pages/api/teams/[id]/edit.ts b/pages/api/teams/[id]/edit.ts index 96e2fa5d3a..f413f7c455 100644 --- a/pages/api/teams/[id]/edit.ts +++ b/pages/api/teams/[id]/edit.ts @@ -1,36 +1,41 @@ -import prisma from "@calcom/prisma"; - -import { Team } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaTeam, withValidTeam } from "@lib/validations/team"; +import prisma from "@calcom/prisma"; +import { Team } from "@calcom/prisma/client"; + import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaTeam, withValidTeam } from "@lib/validations/team"; type ResponseData = { data?: Team; message?: string; - error?: unknown; + error?: object; }; export async function editTeam(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaTeam.safeParse(body); + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaTeam.safeParse(req.body); - if (safeQuery.success && safeBody.success) { - const data = await prisma.team.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - if (data) res.status(200).json({ data }); - else (error: unknown) => res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) - } + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const data = await prisma.team.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, + error, + }); } -export default withMiddleware("patchOnly","addRequestId")( - withValidQueryIdTransformParseInt( - withValidTeam( - editTeam) - ) -); +export default withMiddleware( + "HTTP_PATCH", + "addRequestId" +)(withValidQueryIdTransformParseInt(withValidTeam(editTeam))); diff --git a/pages/api/teams/[id]/index.ts b/pages/api/teams/[id]/index.ts index 9868c043fd..aebfbf36a6 100644 --- a/pages/api/teams/[id]/index.ts +++ b/pages/api/teams/[id]/index.ts @@ -1,30 +1,33 @@ -import prisma from "@calcom/prisma"; - -import { Team } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; +import { Team } from "@calcom/prisma/client"; + import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; type ResponseData = { data?: Team; message?: string; - error?: unknown; + error?: object; }; export async function teamById(req: NextApiRequest, res: NextApiResponse) { const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (safe.success) { - const data = await prisma.team.findUnique({ where: { id: safe.data.id } }); + if (!safe.success) throw new Error("Invalid request query"); - if (data) res.status(200).json({ data }); - else res.status(404).json({ message: "Team was not found" }); - } + const data = await prisma.team.findUnique({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "Team was not found", + error, + }); } - -export default withMiddleware("addRequestId","getOnly")( - withValidQueryIdTransformParseInt( - teamById - ) -); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(teamById)); diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index 1fd88d492f..ce090dd0a5 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -1,19 +1,26 @@ -import prisma from "@calcom/prisma"; - -import { Team } from "@calcom/prisma/client"; -import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { NextApiRequest, NextApiResponse } from "next"; +import prisma from "@calcom/prisma"; +import { Team } from "@calcom/prisma/client"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; + type ResponseData = { data?: Team[]; - error?: unknown; + message?: string; + error?: object; }; async function allTeams(req: NextApiRequest, res: NextApiResponse) { const data = await prisma.team.findMany(); if (data) res.status(200).json({ data }); - else res.status(400).json({ error: "No data found" }); + else + (error: Error) => + res.status(400).json({ + message: "No Teams were found", + error, + }); } -export default withMiddleware("addRequestId","getOnly")(allTeams); \ No newline at end of file +export default withMiddleware("HTTP_GET")(allTeams); diff --git a/pages/api/teams/new.ts b/pages/api/teams/new.ts index 7ae4d0034e..a3412a7631 100644 --- a/pages/api/teams/new.ts +++ b/pages/api/teams/new.ts @@ -2,10 +2,10 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { Team } from "@calcom/prisma/client"; + import { withMiddleware } from "@lib/helpers/withMiddleware"; import { schemaTeam, withValidTeam } from "@lib/validations/team"; - type ResponseData = { data?: Team; error?: object; @@ -13,16 +13,19 @@ type ResponseData = { async function createTeam(req: NextApiRequest, res: NextApiResponse) { const safe = schemaTeam.safeParse(req.body); - if (safe.success) { - const data = await prisma.team - .create({ data: safe.data }) - if (data) res.status(201).json({ data }) - else (error: unknown) => res.status(400).json({ error: { message: "Could not create team type", error: error } }); - } + if (!safe.success) throw new Error("Invalid request body"); + + const data = await prisma.team.create({ data: safe.data }); + + if (data) res.status(201).json({ data }); + else + (error: Error) => + res.status(400).json({ + error: { + message: "Could not create new team", + error, + }, + }); } -export default withMiddleware("addRequestId","postOnly")( - withValidTeam( - createTeam - ) -); +export default withMiddleware("addRequestId", "HTTP_POST")(withValidTeam(createTeam)); diff --git a/pages/api/users/[id]/delete.ts b/pages/api/users/[id]/delete.ts index 6542b99134..f35f50a36c 100644 --- a/pages/api/users/[id]/delete.ts +++ b/pages/api/users/[id]/delete.ts @@ -1,29 +1,27 @@ - import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; + import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import type { BaseResponse } from "@lib/types"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - message?: string; - error?: unknown; -}; - -export async function deleteUser(req: NextApiRequest, res: NextApiResponse) { +export async function deleteUser(req: NextApiRequest, res: NextApiResponse) { const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (safe.success) { - const data = await prisma.user - .delete({ where: { id: safe.data.id } }) - // We only remove the user type from the database if there's an existing resource. - if (data) res.status(200).json({ message: `User with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.user.delete() if the resource is not found. - else res.status(400).json({ message: `User with id: ${safe.data.id} was not able to be processed` }); - } + if (!safe.success) throw new Error("Invalid request query", safe.error); + + const data = await prisma.user.delete({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ message: `User with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `User with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withMiddleware("deleteOnly", "addRequestId")( - withValidQueryIdTransformParseInt( - deleteUser - ) -); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteUser)); diff --git a/pages/api/users/[id]/edit.ts b/pages/api/users/[id]/edit.ts index 3e5425b3d9..bd0ed675de 100644 --- a/pages/api/users/[id]/edit.ts +++ b/pages/api/users/[id]/edit.ts @@ -1,36 +1,33 @@ -import prisma from "@calcom/prisma"; - -import { User } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaUser, withValidUser } from "@lib/validations/user"; +import prisma from "@calcom/prisma"; + import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import type { UserResponse } from "@lib/types"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaUserBodyParams, schemaUserPublic, withValidUser } from "@lib/validations/user"; -type ResponseData = { - data?: User; - message?: string; - error?: unknown; -}; +export async function editUser(req: NextApiRequest, res: NextApiResponse) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaUserBodyParams.safeParse(req.body); -export async function editUser(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaUser.safeParse(body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const user = await prisma.user.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaUserPublic.parse(user); - if (safeQuery.success && safeBody.success) { - const data = await prisma.user.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - if (data) res.status(200).json({ data }); - else (error: unknown) => res.status(404).json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }) - } + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, + error, + }); } -export default withMiddleware("patchOnly","addRequestId")( - withValidQueryIdTransformParseInt( - withValidUser( - editUser) - ) -); +export default withMiddleware("HTTP_PATCH")(withValidQueryIdTransformParseInt(withValidUser(editUser))); diff --git a/pages/api/users/[id]/index.ts b/pages/api/users/[id]/index.ts index 6264acd115..7e7c7cb8ff 100644 --- a/pages/api/users/[id]/index.ts +++ b/pages/api/users/[id]/index.ts @@ -1,30 +1,29 @@ -import prisma from "@calcom/prisma"; - -import { User } from "@calcom/prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import prisma from "@calcom/prisma"; + import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { UserResponse } from "@lib/types"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaUserPublic } from "@lib/validations/user"; -type ResponseData = { - data?: User; - message?: string; - error?: unknown; -}; - -export async function userById(req: NextApiRequest, res: NextApiResponse) { +export async function userById(req: NextApiRequest, res: NextApiResponse) { const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (safe.success) { - const data = await prisma.user.findUnique({ where: { id: safe.data.id } }); + if (!safe.success) throw new Error("Invalid request query"); - if (data) res.status(200).json({ data }); - else res.status(404).json({ message: "User was not found" }); - } + const user = await prisma.user.findUnique({ where: { id: safe.data.id } }); + const data = schemaUserPublic.parse(user); + + if (user) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "User was not found", + error, + }); } - -export default withMiddleware("addRequestId","getOnly")( - withValidQueryIdTransformParseInt( - userById - ) -); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(userById)); diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index ef75e93cc7..365abe4df3 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -1,19 +1,22 @@ -import prisma from "@calcom/prisma"; - -import { User } from "@calcom/prisma/client"; -import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { NextApiRequest, NextApiResponse } from "next"; -type ResponseData = { - data?: User[]; - error?: unknown; -}; +import prisma from "@calcom/prisma"; -async function allUsers(req: NextApiRequest, res: NextApiResponse) { - const data = await prisma.user.findMany(); +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { UsersResponse } from "@lib/types"; +import { schemaUserPublic } from "@lib/validations/user"; + +async function allUsers(_: NextApiRequest, res: NextApiResponse) { + const users = await prisma.user.findMany(); + const data = users.map((user) => schemaUserPublic.parse(user)); if (data) res.status(200).json({ data }); - else res.status(400).json({ error: "No data found" }); + else + (error: Error) => + res.status(400).json({ + message: "No Users were found", + error, + }); } -export default withMiddleware("addRequestId","getOnly")(allUsers); \ No newline at end of file +export default withMiddleware("HTTP_GET")(allUsers); diff --git a/pages/api/users/new.ts b/pages/api/users/new.ts index 6ce94b5df0..adcf5d7658 100644 --- a/pages/api/users/new.ts +++ b/pages/api/users/new.ts @@ -1,28 +1,25 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { User } from "@calcom/prisma/client"; + import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { schemaUser, withValidUser } from "@lib/validations/user"; +import type { UserResponse } from "@lib/types"; +import { schemaUserBodyParams, schemaUserPublic, withValidUser } from "@lib/validations/user"; +async function createUser(req: NextApiRequest, res: NextApiResponse) { + const safe = schemaUserBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -type ResponseData = { - data?: User; - error?: object; -}; + const user = await prisma.user.create({ data: safe.data }); + const data = schemaUserPublic.parse(user); -async function createUser(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaUser.safeParse(req.body); - if (safe.success) { - const data = await prisma.user - .create({ data: safe.data }) - if (data) res.status(201).json({ data }) - else (error: unknown) => res.status(400).json({ error: { message: "Could not create user type", error: error } }); - } + if (data) res.status(201).json({ data, message: "User created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new user", + error, + }); } -export default withMiddleware("addRequestId","postOnly")( - withValidUser( - createUser - ) -); +export default withMiddleware("HTTP_POST")(withValidUser(createUser)); diff --git a/prettier.rc.js b/prettier.rc.js new file mode 100644 index 0000000000..aa497c0ac5 --- /dev/null +++ b/prettier.rc.js @@ -0,0 +1,7 @@ +module.exports = { + semi: false, + singleQuote: true, + arrowParens: "avoid", + trailingComma: "none", + endOfLine: "auto", +}; diff --git a/tests/api-keys/[id]/api-key.id.delete.test.ts b/tests/api-keys/[id]/api-key.id.delete.test.ts index fed838a16b..d2abfecb7a 100644 --- a/tests/api-keys/[id]/api-key.id.delete.test.ts +++ b/tests/api-keys/[id]/api-key.id.delete.test.ts @@ -5,7 +5,7 @@ import prisma from "@calcom/prisma"; describe("DELETE /api/api-keys/[id]/delete with valid id as string returns an apiKey", () => { it("returns a message with the specified apiKeys", async () => { - const apiKey = await prisma.apiKey.findFirst() + const apiKey = await prisma.apiKey.findFirst(); const { req, res } = createMocks({ method: "DELETE", query: { @@ -15,7 +15,9 @@ describe("DELETE /api/api-keys/[id]/delete with valid id as string returns an ap // const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.id} }); await handleDeleteApiKey(req, res); expect(res._getStatusCode()).toBe(204); - expect(JSON.parse(res._getData())).toEqual({message: `api-key with id: ${apiKey?.id} deleted successfully`}); + expect(JSON.parse(res._getData())).toEqual({ + message: `api-key with id: ${apiKey?.id} deleted successfully`, + }); }); }); @@ -56,15 +58,15 @@ describe("DELETE /api/api-keys/[id]/delete an id not present in db like 0, throw expect(res._getStatusCode()).toBe(404); expect(JSON.parse(res._getData())).toStrictEqual({ - "error": { - "clientVersion": "3.10.0", - "code": "P2025", - "meta": { - "cause": "Record to delete does not exist.", - }, - }, - "message": "Resource with id:0 was not found", - }); + error: { + clientVersion: "3.10.0", + code: "P2025", + meta: { + cause: "Record to delete does not exist.", + }, + }, + message: "Resource with id:0 was not found", + }); }); }); @@ -82,5 +84,3 @@ describe("POST /api/api-keys/[id]/delete fails, only DELETE allowed", () => { expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only DELETE Method allowed" }); }); }); - - diff --git a/tests/api-keys/[id]/api-key.id.edit.test.ts b/tests/api-keys/[id]/api-key.id.edit.test.ts index c0d2e3631c..1007181179 100644 --- a/tests/api-keys/[id]/api-key.id.edit.test.ts +++ b/tests/api-keys/[id]/api-key.id.edit.test.ts @@ -2,7 +2,8 @@ import handleapiKeyEdit from "@api/api-keys/[id]/edit"; import { createMocks } from "node-mocks-http"; import prisma from "@calcom/prisma"; -import {stringifyISODate} from "@lib/utils/stringifyISODate"; + +import { stringifyISODate } from "@lib/utils/stringifyISODate"; describe("PATCH /api/api-keys/[id]/edit with valid id and body with note", () => { it("returns a 200 and the updated apiKey note", async () => { @@ -19,7 +20,13 @@ describe("PATCH /api/api-keys/[id]/edit with valid id and body with note", () => await handleapiKeyEdit(req, res); expect(res._getStatusCode()).toBe(200); - expect(JSON.parse(res._getData())).toEqual({ data: {...apiKey, createdAt: stringifyISODate(apiKey?.createdAt), expiresAt: stringifyISODate(apiKey?.expiresAt)} }); + expect(JSON.parse(res._getData())).toEqual({ + data: { + ...apiKey, + createdAt: stringifyISODate(apiKey?.createdAt), + expiresAt: stringifyISODate(apiKey?.expiresAt), + }, + }); }); }); @@ -39,20 +46,22 @@ describe("PATCH /api/api-keys/[id]/edit with invalid id returns 404", () => { expect(res._getStatusCode()).toBe(404); if (apiKey) apiKey.note = "Updated note"; - expect(JSON.parse(res._getData())).toStrictEqual({ "error": { - "clientVersion": "3.10.0", - "code": "P2025", - "meta": { - "cause": "Record to update not found.", - }, + expect(JSON.parse(res._getData())).toStrictEqual({ + error: { + clientVersion: "3.10.0", + code: "P2025", + meta: { + cause: "Record to update not found.", + }, }, - "message": "apiKey with ID cl16zg6860000wwylnsgva00a not found and wasn't updated", }); + message: "apiKey with ID cl16zg6860000wwylnsgva00a not found and wasn't updated", + }); }); }); describe("PATCH /api/api-keys/[id]/edit with valid id and no body returns 200 with an apiKey with no note and default expireAt", () => { it("returns a message with the specified apiKeys", async () => { - const apiKey = await prisma.apiKey.create({data:{} }); + const apiKey = await prisma.apiKey.create({ data: {} }); const { req, res } = createMocks({ method: "PATCH", query: { @@ -63,8 +72,13 @@ describe("PATCH /api/api-keys/[id]/edit with valid id and no body returns 200 wi expect(apiKey?.note).toBeNull(); expect(res._getStatusCode()).toBe(200); - expect(JSON.parse(res._getData())).toEqual({ data: {...apiKey, createdAt: stringifyISODate(apiKey?.createdAt), expiresAt: stringifyISODate(apiKey?.expiresAt)} }); - + expect(JSON.parse(res._getData())).toEqual({ + data: { + ...apiKey, + createdAt: stringifyISODate(apiKey?.createdAt), + expiresAt: stringifyISODate(apiKey?.expiresAt), + }, + }); }); }); @@ -82,8 +96,8 @@ describe("POST /api/api-keys/[id]/edit fails, only PATCH allowed", () => { await handleapiKeyEdit(req, res); expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only PATCH Method allowed for updating API keys" }); + expect(JSON.parse(res._getData())).toStrictEqual({ + message: "Only PATCH Method allowed for updating API keys", + }); }); }); - - diff --git a/tests/api-keys/[id]/api-key.id.index.test.ts b/tests/api-keys/[id]/api-key.id.index.test.ts index bdd8996b47..8d3c2655af 100644 --- a/tests/api-keys/[id]/api-key.id.index.test.ts +++ b/tests/api-keys/[id]/api-key.id.index.test.ts @@ -2,7 +2,8 @@ import handleApiKey from "@api/api-keys/[id]"; import { createMocks } from "node-mocks-http"; import prisma from "@calcom/prisma"; -import {stringifyISODate} from "@lib/utils/stringifyISODate"; + +import { stringifyISODate } from "@lib/utils/stringifyISODate"; describe("GET /api/api-keys/[id] with valid id as string returns an apiKey", () => { it("returns a message with the specified apiKeys", async () => { @@ -12,11 +13,17 @@ describe("GET /api/api-keys/[id] with valid id as string returns an apiKey", () id: "cl16zg6860000wwylnsgva00b", }, }); - const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.id} }); + const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.id } }); await handleApiKey(req, res); expect(res._getStatusCode()).toBe(200); - expect(JSON.parse(res._getData())).toEqual({ data: {...apiKey, createdAt: stringifyISODate(apiKey?.createdAt), expiresAt: stringifyISODate(apiKey?.expiresAt)} }); + expect(JSON.parse(res._getData())).toEqual({ + data: { + ...apiKey, + createdAt: stringifyISODate(apiKey?.createdAt), + expiresAt: stringifyISODate(apiKey?.expiresAt), + }, + }); }); }); @@ -74,5 +81,3 @@ describe("POST /api/api-keys/[id] fails, only GET allowed", () => { expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); }); }); - - diff --git a/tests/api-keys/api-key.index.test.ts b/tests/api-keys/api-key.index.test.ts index 87e1bd24b5..957b749b88 100644 --- a/tests/api-keys/api-key.index.test.ts +++ b/tests/api-keys/api-key.index.test.ts @@ -2,7 +2,8 @@ import handleApiKeys from "@api/api-keys"; import { createMocks } from "node-mocks-http"; import prisma from "@calcom/prisma"; -import {stringifyISODate} from "@lib/utils/stringifyISODate"; + +import { stringifyISODate } from "@lib/utils/stringifyISODate"; describe("GET /api/api-keys without any params", () => { it("returns a message with the specified apiKeys", async () => { @@ -14,8 +15,15 @@ describe("GET /api/api-keys without any params", () => { await handleApiKeys(req, res); expect(res._getStatusCode()).toBe(200); - apiKeys = apiKeys.map(apiKey => (apiKey = {...apiKey, createdAt: stringifyISODate(apiKey?.createdAt), expiresAt: stringifyISODate(apiKey?.expiresAt)})); - expect(JSON.parse(res._getData())).toStrictEqual(JSON.parse(JSON.stringify({ data: {...apiKeys} }))); + apiKeys = apiKeys.map( + (apiKey) => + (apiKey = { + ...apiKey, + createdAt: stringifyISODate(apiKey?.createdAt), + expiresAt: stringifyISODate(apiKey?.expiresAt), + }) + ); + expect(JSON.parse(res._getData())).toStrictEqual(JSON.parse(JSON.stringify({ data: { ...apiKeys } }))); }); }); diff --git a/tests/api-keys/api-key.new.test.ts b/tests/api-keys/api-key.new.test.ts index 9507bdbd71..339b4c146b 100644 --- a/tests/api-keys/api-key.new.test.ts +++ b/tests/api-keys/api-key.new.test.ts @@ -28,13 +28,17 @@ describe("POST /api/api-keys/new with a slug param", () => { await handleNewApiKey(req, res); expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual( - [{"code": "unrecognized_keys", "keys": ["slug"], "message": "Unrecognized key(s) in object: 'slug'", "path": []}] - ); + expect(JSON.parse(res._getData())).toStrictEqual([ + { + code: "unrecognized_keys", + keys: ["slug"], + message: "Unrecognized key(s) in object: 'slug'", + path: [], + }, + ]); }); }); - describe("GET /api/api-keys/new fails, only POST allowed", () => { it("returns a message with the specified apiKeys", async () => { const { req, res } = createMocks({ @@ -47,14 +51,13 @@ describe("GET /api/api-keys/new fails, only POST allowed", () => { }); }); - // FIXME: test 405 when prisma fails look for how to test prisma errors describe("GET /api/api-keys/new fails, only POST allowed", () => { it("returns a message with the specified apiKeys", async () => { const { req, res } = createMocks({ method: "POST", // This POST method is not allowed body: { - nonExistentParam: true + nonExistentParam: true, // note: '123', // slug: 12, }, @@ -62,10 +65,13 @@ describe("GET /api/api-keys/new fails, only POST allowed", () => { await handleNewApiKey(req, res); expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([{ - "code": "unrecognized_keys", - "keys": ["nonExistentParam"], - "message": "Unrecognized key(s) in object: 'nonExistentParam'", "path": [] - }]); + expect(JSON.parse(res._getData())).toStrictEqual([ + { + code: "unrecognized_keys", + keys: ["nonExistentParam"], + message: "Unrecognized key(s) in object: 'nonExistentParam'", + path: [], + }, + ]); }); -}); \ No newline at end of file +}); diff --git a/tests/bookings/[id]/booking.id.edit.test.ts b/tests/bookings/[id]/booking.id.edit.test.ts index 5b7c1ec73f..8bf32eb0e5 100644 --- a/tests/bookings/[id]/booking.id.edit.test.ts +++ b/tests/bookings/[id]/booking.id.edit.test.ts @@ -43,14 +43,16 @@ describe("PATCH /api/bookings/[id]/edit with invalid id returns 404", () => { expect(res._getStatusCode()).toBe(404); if (booking) booking.title = "Updated title"; - expect(JSON.parse(res._getData())).toStrictEqual({ "error": { - "clientVersion": "3.10.0", - "code": "P2025", - "meta": { - "cause": "Record to update not found.", - }, + expect(JSON.parse(res._getData())).toStrictEqual({ + error: { + clientVersion: "3.10.0", + code: "P2025", + meta: { + cause: "Record to update not found.", + }, }, - "message": "Event type with ID 0 not found and wasn't updated", }); + message: "Event type with ID 0 not found and wasn't updated", + }); }); }); @@ -65,7 +67,29 @@ describe("PATCH /api/bookings/[id]/edit with valid id and no body returns 400 er await handleBookingEdit(req, res); expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([{"code": "invalid_type", "expected": "string", "message": "Required", "path": ["title"], "received": "undefined"}, {"code": "invalid_type", "expected": "string", "message": "Required", "path": ["slug"], "received": "undefined"}, {"code": "invalid_type", "expected": "number", "message": "Required", "path": ["length"], "received": "undefined"}]); + expect(JSON.parse(res._getData())).toStrictEqual([ + { + code: "invalid_type", + expected: "string", + message: "Required", + path: ["title"], + received: "undefined", + }, + { + code: "invalid_type", + expected: "string", + message: "Required", + path: ["slug"], + received: "undefined", + }, + { + code: "invalid_type", + expected: "number", + message: "Required", + path: ["length"], + received: "undefined", + }, + ]); }); }); @@ -85,8 +109,8 @@ describe("POST /api/bookings/[id]/edit fails, only PATCH allowed", () => { await handleBookingEdit(req, res); expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only PATCH Method allowed for updating bookings" }); + expect(JSON.parse(res._getData())).toStrictEqual({ + message: "Only PATCH Method allowed for updating bookings", + }); }); }); - - diff --git a/tests/bookings/[id]/booking.id.index.test.ts b/tests/bookings/[id]/booking.id.index.test.ts index d4edede123..4a2ff0ca0c 100644 --- a/tests/bookings/[id]/booking.id.index.test.ts +++ b/tests/bookings/[id]/booking.id.index.test.ts @@ -2,6 +2,7 @@ import handleBooking from "@api/bookings/[id]"; import { createMocks } from "node-mocks-http"; import prisma from "@calcom/prisma"; + import { stringifyISODate } from "@lib/utils/stringifyISODate"; describe("GET /api/bookings/[id] with valid id as string returns an booking", () => { @@ -21,8 +22,8 @@ describe("GET /api/bookings/[id] with valid id as string returns an booking", () ...booking, createdAt: stringifyISODate(booking?.createdAt), startTime: stringifyISODate(booking?.startTime), - endTime: stringifyISODate(booking?.endTime) - } + endTime: stringifyISODate(booking?.endTime), + }, }); }); }); @@ -81,5 +82,3 @@ describe("POST /api/bookings/[id] fails, only GET allowed", () => { expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); }); }); - - diff --git a/tests/bookings/booking.index.test.ts b/tests/bookings/booking.index.test.ts index 87e1bd24b5..957b749b88 100644 --- a/tests/bookings/booking.index.test.ts +++ b/tests/bookings/booking.index.test.ts @@ -2,7 +2,8 @@ import handleApiKeys from "@api/api-keys"; import { createMocks } from "node-mocks-http"; import prisma from "@calcom/prisma"; -import {stringifyISODate} from "@lib/utils/stringifyISODate"; + +import { stringifyISODate } from "@lib/utils/stringifyISODate"; describe("GET /api/api-keys without any params", () => { it("returns a message with the specified apiKeys", async () => { @@ -14,8 +15,15 @@ describe("GET /api/api-keys without any params", () => { await handleApiKeys(req, res); expect(res._getStatusCode()).toBe(200); - apiKeys = apiKeys.map(apiKey => (apiKey = {...apiKey, createdAt: stringifyISODate(apiKey?.createdAt), expiresAt: stringifyISODate(apiKey?.expiresAt)})); - expect(JSON.parse(res._getData())).toStrictEqual(JSON.parse(JSON.stringify({ data: {...apiKeys} }))); + apiKeys = apiKeys.map( + (apiKey) => + (apiKey = { + ...apiKey, + createdAt: stringifyISODate(apiKey?.createdAt), + expiresAt: stringifyISODate(apiKey?.expiresAt), + }) + ); + expect(JSON.parse(res._getData())).toStrictEqual(JSON.parse(JSON.stringify({ data: { ...apiKeys } }))); }); }); diff --git a/tests/bookings/booking.new.test.ts b/tests/bookings/booking.new.test.ts index 9507bdbd71..339b4c146b 100644 --- a/tests/bookings/booking.new.test.ts +++ b/tests/bookings/booking.new.test.ts @@ -28,13 +28,17 @@ describe("POST /api/api-keys/new with a slug param", () => { await handleNewApiKey(req, res); expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual( - [{"code": "unrecognized_keys", "keys": ["slug"], "message": "Unrecognized key(s) in object: 'slug'", "path": []}] - ); + expect(JSON.parse(res._getData())).toStrictEqual([ + { + code: "unrecognized_keys", + keys: ["slug"], + message: "Unrecognized key(s) in object: 'slug'", + path: [], + }, + ]); }); }); - describe("GET /api/api-keys/new fails, only POST allowed", () => { it("returns a message with the specified apiKeys", async () => { const { req, res } = createMocks({ @@ -47,14 +51,13 @@ describe("GET /api/api-keys/new fails, only POST allowed", () => { }); }); - // FIXME: test 405 when prisma fails look for how to test prisma errors describe("GET /api/api-keys/new fails, only POST allowed", () => { it("returns a message with the specified apiKeys", async () => { const { req, res } = createMocks({ method: "POST", // This POST method is not allowed body: { - nonExistentParam: true + nonExistentParam: true, // note: '123', // slug: 12, }, @@ -62,10 +65,13 @@ describe("GET /api/api-keys/new fails, only POST allowed", () => { await handleNewApiKey(req, res); expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([{ - "code": "unrecognized_keys", - "keys": ["nonExistentParam"], - "message": "Unrecognized key(s) in object: 'nonExistentParam'", "path": [] - }]); + expect(JSON.parse(res._getData())).toStrictEqual([ + { + code: "unrecognized_keys", + keys: ["nonExistentParam"], + message: "Unrecognized key(s) in object: 'nonExistentParam'", + path: [], + }, + ]); }); -}); \ No newline at end of file +}); diff --git a/tests/event-types/[id]/event-type.id.edit.test.ts b/tests/event-types/[id]/event-type.id.edit.test.ts index b3cd506a37..e88bcb9b49 100644 --- a/tests/event-types/[id]/event-type.id.edit.test.ts +++ b/tests/event-types/[id]/event-type.id.edit.test.ts @@ -43,14 +43,16 @@ describe("PATCH /api/event-types/[id]/edit with invalid id returns 404", () => { expect(res._getStatusCode()).toBe(404); if (event) event.title = "Updated title"; - expect(JSON.parse(res._getData())).toStrictEqual({ "error": { - "clientVersion": "3.10.0", - "code": "P2025", - "meta": { - "cause": "Record to update not found.", - }, + expect(JSON.parse(res._getData())).toStrictEqual({ + error: { + clientVersion: "3.10.0", + code: "P2025", + meta: { + cause: "Record to update not found.", + }, }, - "message": "Event type with ID 0 not found and wasn't updated", }); + message: "Event type with ID 0 not found and wasn't updated", + }); }); }); @@ -65,7 +67,29 @@ describe("PATCH /api/event-types/[id]/edit with valid id and no body returns 400 await handleEventTypeEdit(req, res); expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([{"code": "invalid_type", "expected": "string", "message": "Required", "path": ["title"], "received": "undefined"}, {"code": "invalid_type", "expected": "string", "message": "Required", "path": ["slug"], "received": "undefined"}, {"code": "invalid_type", "expected": "number", "message": "Required", "path": ["length"], "received": "undefined"}]); + expect(JSON.parse(res._getData())).toStrictEqual([ + { + code: "invalid_type", + expected: "string", + message: "Required", + path: ["title"], + received: "undefined", + }, + { + code: "invalid_type", + expected: "string", + message: "Required", + path: ["slug"], + received: "undefined", + }, + { + code: "invalid_type", + expected: "number", + message: "Required", + path: ["length"], + received: "undefined", + }, + ]); }); }); @@ -85,8 +109,8 @@ describe("POST /api/event-types/[id]/edit fails, only PATCH allowed", () => { await handleEventTypeEdit(req, res); expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only PATCH Method allowed for updating event-types" }); + expect(JSON.parse(res._getData())).toStrictEqual({ + message: "Only PATCH Method allowed for updating event-types", + }); }); }); - - diff --git a/tests/event-types/[id]/event-type.id.index.test.ts b/tests/event-types/[id]/event-type.id.index.test.ts index 46b4e0af21..bb54d5963f 100644 --- a/tests/event-types/[id]/event-type.id.index.test.ts +++ b/tests/event-types/[id]/event-type.id.index.test.ts @@ -73,5 +73,3 @@ describe("POST /api/event-types/[id] fails, only GET allowed", () => { expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); }); }); - - diff --git a/tests/event-types/event-type.index.test.ts b/tests/event-types/event-type.index.test.ts index 668d88a9d7..7a63a59a5d 100644 --- a/tests/event-types/event-type.index.test.ts +++ b/tests/event-types/event-type.index.test.ts @@ -2,6 +2,7 @@ import handleApiKeys from "@api/event-types"; import { createMocks } from "node-mocks-http"; import prisma from "@calcom/prisma"; + // import {stringifyISODate} from "@lib/utils/stringifyISODate"; describe("GET /api/event-types without any params", () => { @@ -15,7 +16,7 @@ describe("GET /api/event-types without any params", () => { expect(res._getStatusCode()).toBe(200); // eventTypes = eventTypes.map(eventType => (eventType = {...eventType, createdAt: stringifyISODate(eventType?.createdAt), expiresAt: stringifyISODate(eventType?.expiresAt)})); - expect(JSON.parse(res._getData())).toStrictEqual(JSON.parse(JSON.stringify({ data: {...eventTypes} }))); + expect(JSON.parse(res._getData())).toStrictEqual(JSON.parse(JSON.stringify({ data: { ...eventTypes } }))); }); }); diff --git a/tests/event-types/event-type.new.test.ts b/tests/event-types/event-type.new.test.ts index 01dab107a9..a79209ec03 100644 --- a/tests/event-types/event-type.new.test.ts +++ b/tests/event-types/event-type.new.test.ts @@ -16,7 +16,6 @@ describe("POST /api/api-keys/new with a note", () => { }); }); - describe("POST /api/api-keys/new with a slug param", () => { it("returns error 400, and the details about invalid slug body param", async () => { const { req, res } = createMocks({ @@ -29,13 +28,17 @@ describe("POST /api/api-keys/new with a slug param", () => { await handleNewApiKey(req, res); expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual( - [{"code": "unrecognized_keys", "keys": ["slug"], "message": "Unrecognized key(s) in object: 'slug'", "path": []}] - ); + expect(JSON.parse(res._getData())).toStrictEqual([ + { + code: "unrecognized_keys", + keys: ["slug"], + message: "Unrecognized key(s) in object: 'slug'", + path: [], + }, + ]); }); }); - describe("GET /api/api-keys/new fails, only POST allowed", () => { it("returns a message with the specified apiKeys", async () => { const { req, res } = createMocks({ @@ -48,7 +51,6 @@ describe("GET /api/api-keys/new fails, only POST allowed", () => { }); }); - // FIXME: test 405 when prisma fails look for how to test prisma errors // describe("GET /api/api-keys/new fails, only POST allowed", () => { // it("returns a message with the specified apiKeys", async () => { @@ -65,4 +67,4 @@ describe("GET /api/api-keys/new fails, only POST allowed", () => { // expect(res._getStatusCode()).toBe(400); // expect(JSON.parse(res._getData())).toStrictEqual({ error: "Only POST Method allowed" }); // }); -// }); \ No newline at end of file +// }); diff --git a/tests/teams/[id]/team.id.edit.test.ts b/tests/teams/[id]/team.id.edit.test.ts index 43df801088..101deaa06e 100644 --- a/tests/teams/[id]/team.id.edit.test.ts +++ b/tests/teams/[id]/team.id.edit.test.ts @@ -40,14 +40,16 @@ describe("PATCH /api/teams/[id]/edit with invalid id returns 404", () => { await handleTeamEdit(req, res); expect(res._getStatusCode()).toBe(404); - expect(JSON.parse(res._getData())).toStrictEqual({ "error": { - "clientVersion": "3.10.0", - "code": "P2025", - "meta": { - "cause": "Record to update not found.", - }, + expect(JSON.parse(res._getData())).toStrictEqual({ + error: { + clientVersion: "3.10.0", + code: "P2025", + meta: { + cause: "Record to update not found.", + }, }, - "message": "Event type with ID 0 not found and wasn't updated", }); + message: "Event type with ID 0 not found and wasn't updated", + }); }); }); @@ -64,7 +66,22 @@ describe("PATCH /api/teams/[id]/edit with valid id and no body returns 400 error expect(res._getStatusCode()).toBe(400); // Ugly parsing of zod validation errors, not for final production but works for testing - expect(JSON.parse(res._getData())).toStrictEqual([{"code": "invalid_type", "expected": "string", "message": "Required", "path": ["slug"], "received": "undefined"}, {"code": "invalid_type", "expected": "string", "message": "Required", "path": ["name"], "received": "undefined"}]); + expect(JSON.parse(res._getData())).toStrictEqual([ + { + code: "invalid_type", + expected: "string", + message: "Required", + path: ["slug"], + received: "undefined", + }, + { + code: "invalid_type", + expected: "string", + message: "Required", + path: ["name"], + received: "undefined", + }, + ]); }); }); @@ -83,8 +100,8 @@ describe("POST /api/teams/[id]/edit fails, only PATCH allowed", () => { await handleTeamEdit(req, res); expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only PATCH Method allowed for updating teams" }); + expect(JSON.parse(res._getData())).toStrictEqual({ + message: "Only PATCH Method allowed for updating teams", + }); }); }); - - diff --git a/tests/teams/[id]/team.id.index.test.ts b/tests/teams/[id]/team.id.index.test.ts index 1f0aec27f9..016f7ec604 100644 --- a/tests/teams/[id]/team.id.index.test.ts +++ b/tests/teams/[id]/team.id.index.test.ts @@ -73,5 +73,3 @@ describe("POST /api/teams/[id] fails, only GET allowed", () => { expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); }); }); - - diff --git a/tests/users/[id]/user.id.edit.test.ts b/tests/users/[id]/user.id.edit.test.ts index b3cd506a37..e88bcb9b49 100644 --- a/tests/users/[id]/user.id.edit.test.ts +++ b/tests/users/[id]/user.id.edit.test.ts @@ -43,14 +43,16 @@ describe("PATCH /api/event-types/[id]/edit with invalid id returns 404", () => { expect(res._getStatusCode()).toBe(404); if (event) event.title = "Updated title"; - expect(JSON.parse(res._getData())).toStrictEqual({ "error": { - "clientVersion": "3.10.0", - "code": "P2025", - "meta": { - "cause": "Record to update not found.", - }, + expect(JSON.parse(res._getData())).toStrictEqual({ + error: { + clientVersion: "3.10.0", + code: "P2025", + meta: { + cause: "Record to update not found.", + }, }, - "message": "Event type with ID 0 not found and wasn't updated", }); + message: "Event type with ID 0 not found and wasn't updated", + }); }); }); @@ -65,7 +67,29 @@ describe("PATCH /api/event-types/[id]/edit with valid id and no body returns 400 await handleEventTypeEdit(req, res); expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([{"code": "invalid_type", "expected": "string", "message": "Required", "path": ["title"], "received": "undefined"}, {"code": "invalid_type", "expected": "string", "message": "Required", "path": ["slug"], "received": "undefined"}, {"code": "invalid_type", "expected": "number", "message": "Required", "path": ["length"], "received": "undefined"}]); + expect(JSON.parse(res._getData())).toStrictEqual([ + { + code: "invalid_type", + expected: "string", + message: "Required", + path: ["title"], + received: "undefined", + }, + { + code: "invalid_type", + expected: "string", + message: "Required", + path: ["slug"], + received: "undefined", + }, + { + code: "invalid_type", + expected: "number", + message: "Required", + path: ["length"], + received: "undefined", + }, + ]); }); }); @@ -85,8 +109,8 @@ describe("POST /api/event-types/[id]/edit fails, only PATCH allowed", () => { await handleEventTypeEdit(req, res); expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only PATCH Method allowed for updating event-types" }); + expect(JSON.parse(res._getData())).toStrictEqual({ + message: "Only PATCH Method allowed for updating event-types", + }); }); }); - - diff --git a/tests/users/[id]/user.id.index.test.ts b/tests/users/[id]/user.id.index.test.ts index 512677981a..bf79c38143 100644 --- a/tests/users/[id]/user.id.index.test.ts +++ b/tests/users/[id]/user.id.index.test.ts @@ -2,6 +2,7 @@ import handleUser from "@api/users/[id]"; import { createMocks } from "node-mocks-http"; import prisma from "@calcom/prisma"; + import { stringifyISODate } from "@lib/utils/stringifyISODate"; describe("GET /api/users/[id] with valid id as string returns an user-type", () => { @@ -16,7 +17,13 @@ describe("GET /api/users/[id] with valid id as string returns an user-type", () await handleUser(req, res); expect(res._getStatusCode()).toBe(200); - expect(JSON.parse(res._getData())).toEqual({ data: {...user, createdDate: stringifyISODate(user?.createdDate), emailVerified: stringifyISODate(user?.emailVerified)} }); + expect(JSON.parse(res._getData())).toEqual({ + data: { + ...user, + createdDate: stringifyISODate(user?.createdDate), + emailVerified: stringifyISODate(user?.emailVerified), + }, + }); }); }); @@ -74,5 +81,3 @@ describe("POST /api/users/[id] fails, only GET allowed", () => { expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); }); }); - - diff --git a/tsconfig.json b/tsconfig.json index 93bbf8be81..7859f5e38e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,18 +1,12 @@ { "extends": "@calcom/tsconfig/base.json", - "exclude": [ - "node_modules" - ], + "exclude": ["node_modules"], "compilerOptions": { "strictNullChecks": true, "baseUrl": ".", - + "target": "es5", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], + "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "noEmit": true, "incremental": true, @@ -20,11 +14,10 @@ "resolveJsonModule": true, "jsx": "preserve", "paths": { - "@api/*": ["pages/api/*"], - "@lib/*": ["lib/*"], - "@/*": ["*"] - -}, + "@api/*": ["pages/api/*"], + "@lib/*": ["lib/*"], + "@/*": ["*"] + } }, "include": ["./**/*.ts"] } From 367621ea5177c37aff8ea015464a4855542fadac Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 30 Mar 2022 16:56:24 +0200 Subject: [PATCH 046/658] feat: users, teams, selectedCalendars w new code/docs --- lib/helpers/captureErrors.ts | 5 +- lib/helpers/verifyApiKey.ts | 5 +- lib/types.ts | 18 +++++- lib/validations/selected-calendar.ts | 14 +++-- lib/validations/shared/baseApiParams.ts | 2 +- lib/validations/team.ts | 22 +++---- package.json | 4 +- pages/{ => api}/_middleware.ts | 13 ++-- pages/api/docs.ts | 13 ++++ pages/api/selected-calendars/[id]/delete.ts | 47 ++++++++------ pages/api/selected-calendars/[id]/edit.ts | 68 +++++++++++++-------- pages/api/selected-calendars/[id]/index.ts | 48 ++++++++++----- pages/api/selected-calendars/index.ts | 38 +++++++++--- pages/api/selected-calendars/new.ts | 55 +++++++++++------ pages/api/teams/[id]/delete.ts | 26 +++++--- pages/api/teams/[id]/edit.ts | 36 ++++++----- pages/api/teams/[id]/index.ts | 29 ++++++--- pages/api/teams/index.ts | 29 ++++++--- pages/api/teams/new.ts | 42 +++++++------ pages/api/users/[id]/delete.ts | 14 +++++ pages/api/users/[id]/edit.ts | 14 +++++ pages/api/users/[id]/index.ts | 13 ++++ pages/api/users/index.ts | 15 ++++- pages/api/users/new.ts | 14 +++++ 24 files changed, 406 insertions(+), 178 deletions(-) rename pages/{ => api}/_middleware.ts (56%) create mode 100644 pages/api/docs.ts diff --git a/lib/helpers/captureErrors.ts b/lib/helpers/captureErrors.ts index 9229ad92d8..109e4e2254 100644 --- a/lib/helpers/captureErrors.ts +++ b/lib/helpers/captureErrors.ts @@ -8,7 +8,8 @@ export const captureErrors: NextMiddleware = async (_req, res, next) => { await next(); } catch (err) { Sentry.captureException(err); - res.status(500); - res.json({ error: err }); + console.log(err); + res.status(400).json({ message: "Something went wrong", error: err }); + // res.json({ error: err }); } }; diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 0da9a2090b..45f8acd9ce 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -11,13 +11,14 @@ const dateInPast = function (firstDate: Date, secondDate: Date) { const today = new Date(); export const verifyApiKey: NextMiddleware = async (req, res, next) => { + if (!req.query.apiKey) res.status(401).json({ message: "No API key provided" }); const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.apiKey as string } }); if (!apiKey) { - res.status(400).json({ error: "Your api key is not valid" }); + res.status(401).json({ error: "Your api key is not valid" }); throw new Error("No api key found"); } if (apiKey.expiresAt && apiKey.userId && dateInPast(apiKey.expiresAt, today)) { res.setHeader("Calcom-User-ID", apiKey.userId); await next(); - } else res.status(400).json({ error: "Your api key is not valid" }); + } else res.status(401).json({ error: "Your api key is not valid" }); }; diff --git a/lib/types.ts b/lib/types.ts index fde9ba7e87..bef7b32e4a 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -1,4 +1,4 @@ -import { User, ApiKey } from "@calcom/prisma/client"; +import { User, ApiKey, Team, SelectedCalendar } from "@calcom/prisma/client"; // Base response, used for all responses export type BaseResponse = { @@ -20,3 +20,19 @@ export type ApiKeyResponse = BaseResponse & { export type ApiKeysResponse = BaseResponse & { data?: Partial[]; }; + +// API Key +export type TeamResponse = BaseResponse & { + data?: Partial; +}; +export type TeamsResponse = BaseResponse & { + data?: Partial[]; +}; + +// API Key +export type SelectedCalendarResponse = BaseResponse & { + data?: Partial; +}; +export type SelectedCalendarsResponse = BaseResponse & { + data?: Partial[]; +}; diff --git a/lib/validations/selected-calendar.ts b/lib/validations/selected-calendar.ts index 29ffdb9c11..2c8d871d52 100644 --- a/lib/validations/selected-calendar.ts +++ b/lib/validations/selected-calendar.ts @@ -1,11 +1,13 @@ import { withValidation } from "next-validations"; -import { z } from "zod"; -const schemaSelectedCalendar = z.object({}).strict(); -const withValidSelectedCalendar = withValidation({ - schema: schemaSelectedCalendar, +import { _SelectedCalendarModel as SelectedCalendar } from "@calcom/prisma/zod"; + +export const schemaSelectedCalendarBodyParams = SelectedCalendar.omit({}); + +export const schemaSelectedCalendarPublic = SelectedCalendar.omit({ userId: true }); + +export const withValidSelectedCalendar = withValidation({ + schema: schemaSelectedCalendarBodyParams, type: "Zod", mode: "body", }); - -export { schemaSelectedCalendar, withValidSelectedCalendar }; diff --git a/lib/validations/shared/baseApiParams.ts b/lib/validations/shared/baseApiParams.ts index 03b13838ee..a7791a5b9d 100644 --- a/lib/validations/shared/baseApiParams.ts +++ b/lib/validations/shared/baseApiParams.ts @@ -6,7 +6,7 @@ export const baseApiParams = z .object({ // since we added apiKey as query param this is required by next-validations helper // for query params to work properly and not fail. - apiKey: z.string().cuid(), + apiKey: z.string().cuid().optional(), // version required for supporting /v1/ redirect to query in api as *?version=1 version: z.string().optional(), }) diff --git a/lib/validations/team.ts b/lib/validations/team.ts index 44cb1329a8..20b79ac1c4 100644 --- a/lib/validations/team.ts +++ b/lib/validations/team.ts @@ -1,19 +1,13 @@ import { withValidation } from "next-validations"; -import { z } from "zod"; -const schemaTeam = z - .object({ - slug: z.string().min(3), - name: z.string().min(3), - hideBranding: z.boolean().default(false), - bio: z.string().min(3).optional(), - logo: z.string().optional(), - }) - .strict(); -const withValidTeam = withValidation({ - schema: schemaTeam, +import { _TeamModel as Team } from "@calcom/prisma/zod"; + +export const schemaTeamBodyParams = Team.omit({ id: true }); + +export const schemaTeamPublic = Team.omit({}); + +export const withValidTeam = withValidation({ + schema: schemaTeamBodyParams, type: "Zod", mode: "body", }); - -export { schemaTeam, withValidTeam }; diff --git a/package.json b/package.json index 79ed5ea648..8f496b55e7 100644 --- a/package.json +++ b/package.json @@ -28,12 +28,14 @@ "babel-jest": "^27.5.1", "husky": "^7.0.4", "jest": "^27.5.1", - "node-mocks-http": "^1.11.0" + "node-mocks-http": "^1.11.0", + "prettier": "^2.6.1" }, "dependencies": { "@sentry/nextjs": "^6.19.2", "next": "^12.1.0", "next-api-middleware": "^1.0.1", + "next-swagger-doc": "^0.2.1", "next-transpile-modules": "^9.0.0", "next-validations": "^0.1.11", "typescript": "^4.6.3", diff --git a/pages/_middleware.ts b/pages/api/_middleware.ts similarity index 56% rename from pages/_middleware.ts rename to pages/api/_middleware.ts index 59f0b1501f..6a3038451a 100644 --- a/pages/_middleware.ts +++ b/pages/api/_middleware.ts @@ -1,17 +1,22 @@ +// import { NextApiResponse } from "next"; import { NextRequest, NextResponse } from "next/server"; // Not much useful yet as prisma.client can't be used in the middlewares (client is not available) // For now we just throw early if no apiKey is passed, // but we could also check if the apiKey is valid if we had prisma here. -export default async function requireApiKeyAsQueryParams({ nextUrl }: NextRequest) { +export default async function requireApiKeyAsQueryParams({ nextUrl }: NextRequest, res: NextResponse) { const response = NextResponse.next(); const apiKey = nextUrl.searchParams.get("apiKey"); if (apiKey) return response; - // if no apiKey is passed, we throw early + // if no apiKey is passed, we throw early a 401 unauthorized else - throw new Error( - "You need to pass an apiKey as query param: https://api.cal.com/resource?apiKey=" + new NextResponse( + JSON.stringify({ + message: + "You need to pass an apiKey as query param: https://api.cal.com/resource?apiKey=", + }), + { status: 401, statusText: "Unauthorized" } ); } diff --git a/pages/api/docs.ts b/pages/api/docs.ts new file mode 100644 index 0000000000..e855eacfd8 --- /dev/null +++ b/pages/api/docs.ts @@ -0,0 +1,13 @@ +import { withSwagger } from "next-swagger-doc"; + +const swaggerHandler = withSwagger({ + definition: { + openapi: "3.0.0", + info: { + title: "Cal.com Public API", + version: "1.0.0", + }, + }, + apiFolder: "pages/api", +}); +export default swaggerHandler(); diff --git a/pages/api/selected-calendars/[id]/delete.ts b/pages/api/selected-calendars/[id]/delete.ts index a3de0e715b..249912dce9 100644 --- a/pages/api/selected-calendars/[id]/delete.ts +++ b/pages/api/selected-calendars/[id]/delete.ts @@ -2,28 +2,41 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BaseResponse } from "@lib/types"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/selectedCalendars/:id/delete: + * delete: + * description: Remove an existing selectedCalendar + * responses: + * 201: + * description: OK, selectedCalendar removed successfuly + * model: SelectedCalendar + * 400: + * description: Bad request. SelectedCalendar id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteSelectedCalendar(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query", safe.error); -export async function deleteSelectedCalendar(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const selectedCalendar = await prisma.selectedCalendar.delete({ where: { id: safe.data.id } }); - // We only remove the selectedCalendar type from the database if there's an existing resource. - if (selectedCalendar) - res.status(200).json({ message: `selectedCalendar with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.selectedCalendar.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only DELETE Method allowed" }); + const data = await prisma.selectedCalendar.delete({ where: { id: safe.data.id } }); + + if (data) + res.status(200).json({ message: `SelectedCalendar with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `SelectedCalendar with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withValidQueryIdTransformParseInt(deleteSelectedCalendar); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteSelectedCalendar)); diff --git a/pages/api/selected-calendars/[id]/edit.ts b/pages/api/selected-calendars/[id]/edit.ts index 0854ffd44f..96c9f08675 100644 --- a/pages/api/selected-calendars/[id]/edit.ts +++ b/pages/api/selected-calendars/[id]/edit.ts @@ -1,38 +1,56 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { SelectedCalendar } from "@calcom/prisma/client"; -import { schemaSelectedCalendar, withValidSelectedCalendar } from "@lib/validations/selected-calendar"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { SelectedCalendarResponse } from "@lib/types"; +import { + schemaSelectedCalendarBodyParams, + schemaSelectedCalendarPublic, + withValidSelectedCalendar, +} from "@lib/validations/selected-calendar"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: SelectedCalendar; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/selectedCalendars/:id/edit: + * patch: + * description: Edits an existing selectedCalendar + * responses: + * 201: + * description: OK, selectedCalendar edited successfuly + * model: SelectedCalendar + * 400: + * description: Bad request. SelectedCalendar body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editSelectedCalendar( + req: NextApiRequest, + res: NextApiResponse +) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaSelectedCalendarBodyParams.safeParse(req.body); -export async function editSelectedCalendar(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaSelectedCalendar.safeParse(body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const selectedCalendar = await prisma.selectedCalendar.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaSelectedCalendarPublic.parse(selectedCalendar); - if (method === "PATCH" && safeQuery.success && safeBody.success) { - const data = await prisma.selectedCalendar.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - if (data) res.status(200).json({ data }); - else - res - .status(404) - .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); - - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only PATCH Method allowed for updating selectedCalendars" }); + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, + error, + }); } -export default withValidQueryIdTransformParseInt(withValidSelectedCalendar(editSelectedCalendar)); +export default withMiddleware("HTTP_PATCH")( + withValidQueryIdTransformParseInt(withValidSelectedCalendar(editSelectedCalendar)) +); diff --git a/pages/api/selected-calendars/[id]/index.ts b/pages/api/selected-calendars/[id]/index.ts index 84a290ae20..cf932ac5a2 100644 --- a/pages/api/selected-calendars/[id]/index.ts +++ b/pages/api/selected-calendars/[id]/index.ts @@ -1,29 +1,45 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { SelectedCalendar } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { SelectedCalendarResponse } from "@lib/types"; +import { schemaSelectedCalendarPublic } from "@lib/validations/selected-calendar"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: SelectedCalendar; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/selectedCalendars/:id: + * get: + * description: find selectedCalendar by ID + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: SelectedCalendar was not found + */ +export async function selectedCalendarById( + req: NextApiRequest, + res: NextApiResponse +) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); -export async function selectedCalendar(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "GET" && safe.success) { - const data = await prisma.selectedCalendar.findUnique({ where: { id: safe.data.id } }); + const selectedCalendar = await prisma.selectedCalendar.findUnique({ where: { id: safe.data.id } }); + const data = schemaSelectedCalendarPublic.parse(selectedCalendar); - if (data) res.status(200).json({ data }); - else res.status(404).json({ message: "Event type not found" }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only GET Method allowed" }); + if (selectedCalendar) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "SelectedCalendar was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(selectedCalendar); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(selectedCalendarById)); diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index 0a4bbd5012..ab80b3aa0f 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -1,15 +1,37 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { SelectedCalendar } from "@calcom/prisma/client"; -type ResponseData = { - data?: SelectedCalendar[]; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { SelectedCalendarsResponse } from "@lib/types"; +import { schemaSelectedCalendarPublic } from "@lib/validations/selected-calendar"; + +/** + * @swagger + * /api/selectedCalendars: + * get: + * description: Returns all selected calendars + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No selectedCalendars were found + */ +async function allSelectedCalendars(_: NextApiRequest, res: NextApiResponse) { + const selectedCalendars = await prisma.selectedCalendar.findMany(); + const data = selectedCalendars.map((selectedCalendar) => + schemaSelectedCalendarPublic.parse(selectedCalendar) + ); -export default async function selectedCalendar(req: NextApiRequest, res: NextApiResponse) { - const data = await prisma.selectedCalendar.findMany(); if (data) res.status(200).json({ data }); - else res.status(400).json({ error: "No data found" }); + else + (error: Error) => + res.status(404).json({ + message: "No SelectedCalendars were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allSelectedCalendars); diff --git a/pages/api/selected-calendars/new.ts b/pages/api/selected-calendars/new.ts index 712a936733..22ae2a8657 100644 --- a/pages/api/selected-calendars/new.ts +++ b/pages/api/selected-calendars/new.ts @@ -1,28 +1,43 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { SelectedCalendar } from "@calcom/prisma/client"; -import { schemaSelectedCalendar, withValidSelectedCalendar } from "@lib/validations/selected-calendar"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { SelectedCalendarResponse } from "@lib/types"; +import { + schemaSelectedCalendarBodyParams, + schemaSelectedCalendarPublic, + withValidSelectedCalendar, +} from "@lib/validations/selected-calendar"; -type ResponseData = { - data?: SelectedCalendar; - message?: string; - error?: string; -}; +/** + * @swagger + * /api/selectedCalendars/new: + * post: + * description: Creates a new selected calendar + * responses: + * 201: + * description: OK, selected calendar created + * model: SelectedCalendar + * 400: + * description: Bad request. SelectedCalendar body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createSelectedCalendar(req: NextApiRequest, res: NextApiResponse) { + const safe = schemaSelectedCalendarBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createSelectedCalendar(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - const safe = schemaSelectedCalendar.safeParse(body); - if (method === "POST" && safe.success) { - await prisma.selectedCalendar - .create({ data: safe.data }) - .then((data) => res.status(201).json({ data })) - .catch((error) => - res.status(400).json({ message: "Could not create selectedCalendar type", error: error }) - ); - // Reject any other HTTP method than POST - } else res.status(405).json({ error: "Only POST Method allowed" }); + const selectedCalendar = await prisma.selectedCalendar.create({ data: safe.data }); + const data = schemaSelectedCalendarPublic.parse(selectedCalendar); + + if (data) res.status(201).json({ data, message: "SelectedCalendar created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new selectedCalendar", + error, + }); } -export default withValidSelectedCalendar(createSelectedCalendar); +export default withMiddleware("HTTP_POST")(withValidSelectedCalendar(createSelectedCalendar)); diff --git a/pages/api/teams/[id]/delete.ts b/pages/api/teams/[id]/delete.ts index 3c88c02d28..cf3825fd96 100644 --- a/pages/api/teams/[id]/delete.ts +++ b/pages/api/teams/[id]/delete.ts @@ -3,19 +3,29 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BaseResponse } from "@lib/types"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - message: string; - error?: object; -}; - -export async function deleteTeam(req: NextApiRequest, res: NextApiResponse) { +/** + * @swagger + * /api/teams/:id/delete: + * delete: + * description: Remove an existing team + * responses: + * 201: + * description: OK, team removed successfuly + * model: Team + * 400: + * description: Bad request. Team id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteTeam(req: NextApiRequest, res: NextApiResponse) { const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query"); + if (!safe.success) throw new Error("Invalid request query", safe.error); const data = await prisma.team.delete({ where: { id: safe.data.id } }); @@ -28,4 +38,4 @@ export async function deleteTeam(req: NextApiRequest, res: NextApiResponse) { +/** + * @swagger + * /api/teams/:id/edit: + * patch: + * description: Edits an existing team + * responses: + * 201: + * description: OK, team edited successfuly + * model: Team + * 400: + * description: Bad request. Team body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editTeam(req: NextApiRequest, res: NextApiResponse) { const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); - const safeBody = await schemaTeam.safeParse(req.body); + const safeBody = await schemaTeamBodyParams.safeParse(req.body); if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); - const data = await prisma.team.update({ + const team = await prisma.team.update({ where: { id: safeQuery.data.id }, data: safeBody.data, }); + const data = schemaTeamPublic.parse(team); if (data) res.status(200).json({ data }); else @@ -35,7 +44,4 @@ export async function editTeam(req: NextApiRequest, res: NextApiResponse) { +/** + * @swagger + * /api/teams/:id: + * get: + * description: find team by ID + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Team was not found + */ +export async function teamById(req: NextApiRequest, res: NextApiResponse) { const safe = await schemaQueryIdParseInt.safeParse(req.query); if (!safe.success) throw new Error("Invalid request query"); - const data = await prisma.team.findUnique({ where: { id: safe.data.id } }); + const team = await prisma.team.findUnique({ where: { id: safe.data.id } }); + const data = schemaTeamPublic.parse(team); - if (data) res.status(200).json({ data }); + if (team) res.status(200).json({ data }); else (error: Error) => res.status(404).json({ diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index ce090dd0a5..7497539eeb 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -1,23 +1,32 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Team } from "@calcom/prisma/client"; import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { TeamsResponse } from "@lib/types"; +import { schemaTeamPublic } from "@lib/validations/team"; -type ResponseData = { - data?: Team[]; - message?: string; - error?: object; -}; - -async function allTeams(req: NextApiRequest, res: NextApiResponse) { - const data = await prisma.team.findMany(); +/** + * @swagger + * /api/teams: + * get: + * description: Returns all teams + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No teams were found + */ +async function allTeams(_: NextApiRequest, res: NextApiResponse) { + const teams = await prisma.team.findMany(); + const data = teams.map((team) => schemaTeamPublic.parse(team)); if (data) res.status(200).json({ data }); else (error: Error) => - res.status(400).json({ + res.status(404).json({ message: "No Teams were found", error, }); diff --git a/pages/api/teams/new.ts b/pages/api/teams/new.ts index a3412a7631..b78759d249 100644 --- a/pages/api/teams/new.ts +++ b/pages/api/teams/new.ts @@ -1,31 +1,39 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Team } from "@calcom/prisma/client"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { schemaTeam, withValidTeam } from "@lib/validations/team"; +import type { TeamResponse } from "@lib/types"; +import { schemaTeamBodyParams, schemaTeamPublic, withValidTeam } from "@lib/validations/team"; -type ResponseData = { - data?: Team; - error?: object; -}; +/** + * @swagger + * /api/teams/new: + * post: + * description: Creates a new team + * responses: + * 201: + * description: OK, team created + * model: Team + * 400: + * description: Bad request. Team body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createTeam(req: NextApiRequest, res: NextApiResponse) { + const safe = schemaTeamBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createTeam(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaTeam.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body"); + const team = await prisma.team.create({ data: safe.data }); + const data = schemaTeamPublic.parse(team); - const data = await prisma.team.create({ data: safe.data }); - - if (data) res.status(201).json({ data }); + if (data) res.status(201).json({ data, message: "Team created successfully" }); else (error: Error) => res.status(400).json({ - error: { - message: "Could not create new team", - error, - }, + message: "Could not create new team", + error, }); } -export default withMiddleware("addRequestId", "HTTP_POST")(withValidTeam(createTeam)); +export default withMiddleware("HTTP_POST")(withValidTeam(createTeam)); diff --git a/pages/api/users/[id]/delete.ts b/pages/api/users/[id]/delete.ts index f35f50a36c..51b6e36cf6 100644 --- a/pages/api/users/[id]/delete.ts +++ b/pages/api/users/[id]/delete.ts @@ -9,6 +9,20 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; +/** + * @swagger + * /api/users/:id/delete: + * delete: + * description: Remove an existing user + * responses: + * 201: + * description: OK, user removed successfuly + * model: User + * 400: + * description: Bad request. User id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ export async function deleteUser(req: NextApiRequest, res: NextApiResponse) { const safe = await schemaQueryIdParseInt.safeParse(req.query); if (!safe.success) throw new Error("Invalid request query", safe.error); diff --git a/pages/api/users/[id]/edit.ts b/pages/api/users/[id]/edit.ts index bd0ed675de..b78cb1f83c 100644 --- a/pages/api/users/[id]/edit.ts +++ b/pages/api/users/[id]/edit.ts @@ -10,6 +10,20 @@ import { } from "@lib/validations/shared/queryIdTransformParseInt"; import { schemaUserBodyParams, schemaUserPublic, withValidUser } from "@lib/validations/user"; +/** + * @swagger + * /api/users/:id/edit: + * patch: + * description: Edits an existing user + * responses: + * 201: + * description: OK, user edited successfuly + * model: User + * 400: + * description: Bad request. User body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ export async function editUser(req: NextApiRequest, res: NextApiResponse) { const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); const safeBody = await schemaUserBodyParams.safeParse(req.body); diff --git a/pages/api/users/[id]/index.ts b/pages/api/users/[id]/index.ts index 7e7c7cb8ff..04be633d5d 100644 --- a/pages/api/users/[id]/index.ts +++ b/pages/api/users/[id]/index.ts @@ -10,6 +10,19 @@ import { } from "@lib/validations/shared/queryIdTransformParseInt"; import { schemaUserPublic } from "@lib/validations/user"; +/** + * @swagger + * /api/users/:id: + * get: + * description: find user by ID + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: User was not found + */ export async function userById(req: NextApiRequest, res: NextApiResponse) { const safe = await schemaQueryIdParseInt.safeParse(req.query); if (!safe.success) throw new Error("Invalid request query"); diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 365abe4df3..a748315a4a 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -6,6 +6,19 @@ import { withMiddleware } from "@lib/helpers/withMiddleware"; import { UsersResponse } from "@lib/types"; import { schemaUserPublic } from "@lib/validations/user"; +/** + * @swagger + * /api/users: + * get: + * description: Returns all users + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No users were found + */ async function allUsers(_: NextApiRequest, res: NextApiResponse) { const users = await prisma.user.findMany(); const data = users.map((user) => schemaUserPublic.parse(user)); @@ -13,7 +26,7 @@ async function allUsers(_: NextApiRequest, res: NextApiResponse) if (data) res.status(200).json({ data }); else (error: Error) => - res.status(400).json({ + res.status(404).json({ message: "No Users were found", error, }); diff --git a/pages/api/users/new.ts b/pages/api/users/new.ts index adcf5d7658..fd717213e0 100644 --- a/pages/api/users/new.ts +++ b/pages/api/users/new.ts @@ -6,6 +6,20 @@ import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { UserResponse } from "@lib/types"; import { schemaUserBodyParams, schemaUserPublic, withValidUser } from "@lib/validations/user"; +/** + * @swagger + * /api/users/new: + * post: + * description: Creates a new user + * responses: + * 201: + * description: OK, user created + * model: User + * 400: + * description: Bad request. User body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ async function createUser(req: NextApiRequest, res: NextApiResponse) { const safe = schemaUserBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body", safe.error); From 9aa4b0e30dc717e79125427c088fa5c03d200593 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 30 Mar 2022 17:37:51 +0200 Subject: [PATCH 047/658] feat: inherit all validations from auto-generated zod --- lib/types.ts | 118 ++++++++++++++++++++++- lib/validations/attendee.ts | 23 ++--- lib/validations/availability.ts | 24 ++--- lib/validations/booking-reference.ts | 14 +-- lib/validations/booking.ts | 28 ++---- lib/validations/credential.ts | 14 +-- lib/validations/daily-event-reference.ts | 14 +-- lib/validations/destination-calendar.ts | 14 +-- lib/validations/eventType.ts | 21 ++-- lib/validations/membership.ts | 14 +-- lib/validations/payment.ts | 14 +-- lib/validations/schedule.ts | 14 +-- lib/validations/webhook.ts | 13 +-- pages/api/_middleware.ts | 3 +- pages/api/event-types/[id]/delete.ts | 47 +++++---- pages/api/event-types/[id]/edit.ts | 72 ++++++++------ pages/api/event-types/[id]/index.ts | 48 +++++---- pages/api/event-types/index.ts | 44 ++++++--- pages/api/event-types/new.ts | 57 ++++++----- 19 files changed, 372 insertions(+), 224 deletions(-) diff --git a/lib/types.ts b/lib/types.ts index bef7b32e4a..100fde2b61 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -1,4 +1,20 @@ -import { User, ApiKey, Team, SelectedCalendar } from "@calcom/prisma/client"; +import { + User, + ApiKey, + Team, + SelectedCalendar, + EventType, + Attendee, + Availability, + BookingReference, + Booking, + DailyEventReference, + Webhook, + DestinationCalendar, + Membership, + Payment, + Schedule, +} from "@calcom/prisma/client"; // Base response, used for all responses export type BaseResponse = { @@ -21,7 +37,7 @@ export type ApiKeysResponse = BaseResponse & { data?: Partial[]; }; -// API Key +// Team export type TeamResponse = BaseResponse & { data?: Partial; }; @@ -29,10 +45,106 @@ export type TeamsResponse = BaseResponse & { data?: Partial[]; }; -// API Key +// SelectedCalendar export type SelectedCalendarResponse = BaseResponse & { data?: Partial; }; export type SelectedCalendarsResponse = BaseResponse & { data?: Partial[]; }; + +// Attendee +export type AttendeeResponse = BaseResponse & { + data?: Partial; +}; +export type AttendeesResponse = BaseResponse & { + data?: Partial[]; +}; + +// Availability +export type AvailabilityResponse = BaseResponse & { + data?: Partial; +}; +export type AvailabilitysResponse = BaseResponse & { + data?: Partial[]; +}; + +// BookingReference +export type BookingReferenceResponse = BaseResponse & { + data?: Partial; +}; +export type BookingReferencesResponse = BaseResponse & { + data?: Partial[]; +}; + +// Booking +export type BookingResponse = BaseResponse & { + data?: Partial; +}; +export type BookingsResponse = BaseResponse & { + data?: Partial[]; +}; + +// Credential +export type CredentialResponse = BaseResponse & { + data?: Partial; +}; +export type CredentialsResponse = BaseResponse & { + data?: Partial[]; +}; + +// DailyEventReference +export type DailyEventReferenceResponse = BaseResponse & { + data?: Partial; +}; +export type DailyEventReferencesResponse = BaseResponse & { + data?: Partial[]; +}; + +// DestinationCalendar +export type DestinationCalendarResponse = BaseResponse & { + data?: Partial; +}; +export type DestinationCalendarsResponse = BaseResponse & { + data?: Partial[]; +}; + +// Membership +export type MembershipResponse = BaseResponse & { + data?: Partial; +}; +export type MembershipsResponse = BaseResponse & { + data?: Partial[]; +}; + +// EventType +export type EventTypeResponse = BaseResponse & { + data?: Partial; +}; +export type EventTypesResponse = BaseResponse & { + data?: Partial[]; +}; + +// Payment +export type PaymentResponse = BaseResponse & { + data?: Partial; +}; +export type PaymentsResponse = BaseResponse & { + data?: Partial[]; +}; + +// Schedule +export type ScheduleResponse = BaseResponse & { + data?: Partial; +}; +export type SchedulesResponse = BaseResponse & { + data?: Partial[]; +}; + +// Webhook +export type WebhookResponse = BaseResponse & { + data?: Partial; +}; +export type WebhooksResponse = BaseResponse & { + data?: Partial[]; +}; diff --git a/lib/validations/attendee.ts b/lib/validations/attendee.ts index 290b337779..bd55fb9361 100644 --- a/lib/validations/attendee.ts +++ b/lib/validations/attendee.ts @@ -1,20 +1,13 @@ import { withValidation } from "next-validations"; -import { z } from "zod"; -const schemaAttendee = z - .object({ - id: z.number(), - email: z.string().min(3), - name: z.string().min(3).email(), - timeZone: z.string().default("Europe/London"), - locale: z.string().optional(), - bookingId: z.number(), - }) - .strict(); -const withValidAttendee = withValidation({ - schema: schemaAttendee, +import { _AttendeeModel as Attendee } from "@calcom/prisma/zod"; + +export const schemaAttendeeBodyParams = Attendee.omit({ id: true }); + +export const schemaAttendeePublic = Attendee.omit({}); + +export const withValidAttendee = withValidation({ + schema: schemaAttendeeBodyParams, type: "Zod", mode: "body", }); - -export { schemaAttendee, withValidAttendee }; diff --git a/lib/validations/availability.ts b/lib/validations/availability.ts index 24f692118b..cd747bdf73 100644 --- a/lib/validations/availability.ts +++ b/lib/validations/availability.ts @@ -1,23 +1,13 @@ import { withValidation } from "next-validations"; -import { z } from "zod"; -const schemaAvailability = z - .object({ - id: z.number(), - userId: z.number(), - eventTypeId: z.number(), - scheduleId: z.number(), +import { _AvailabilityModel as Availability } from "@calcom/prisma/zod"; - days: z.array(z.number()), - date: z.date().or(z.string()), - startTime: z.string(), - endTime: z.string(), - }) - .strict(); -const withValidAvailability = withValidation({ - schema: schemaAvailability, +export const schemaAvailabilityBodyParams = Availability.omit({ id: true }); + +export const schemaAvailabilityPublic = Availability.omit({}); + +export const withValidAvailability = withValidation({ + schema: schemaAvailabilityBodyParams, type: "Zod", mode: "body", }); - -export { schemaAvailability, withValidAvailability }; diff --git a/lib/validations/booking-reference.ts b/lib/validations/booking-reference.ts index fc1fe225c6..c73be296bc 100644 --- a/lib/validations/booking-reference.ts +++ b/lib/validations/booking-reference.ts @@ -1,11 +1,13 @@ import { withValidation } from "next-validations"; -import { z } from "zod"; -const schemaBookingReference = z.object({}).strict(); -const withValidBookingReference = withValidation({ - schema: schemaBookingReference, +import { _BookingReferenceModel as BookingReference } from "@calcom/prisma/zod"; + +export const schemaBookingReferenceBodyParams = BookingReference.omit({ id: true }); + +export const schemaBookingReferencePublic = BookingReference.omit({}); + +export const withValidBookingReference = withValidation({ + schema: schemaBookingReferenceBodyParams, type: "Zod", mode: "body", }); - -export { schemaBookingReference, withValidBookingReference }; diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index 74834e9e0e..e7528764ab 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -1,25 +1,13 @@ import { withValidation } from "next-validations"; -import { z } from "zod"; -const schemaBooking = z - .object({ - uid: z.string().min(3), - title: z.string().min(3), - description: z.string().min(3).optional(), - startTime: z.date().or(z.string()), - endTime: z.date(), - location: z.string().min(3).optional(), - createdAt: z.date().or(z.string()), - updatedAt: z.date().or(z.string()), - confirmed: z.boolean().default(true), - rejected: z.boolean().default(false), - paid: z.boolean().default(false), - }) - .strict(); -const withValidBooking = withValidation({ - schema: schemaBooking, +import { _BookingModel as Booking } from "@calcom/prisma/zod"; + +export const schemaBookingBodyParams = Booking.omit({ id: true }); + +export const schemaBookingPublic = Booking.omit({}); + +export const withValidBooking = withValidation({ + schema: schemaBookingBodyParams, type: "Zod", mode: "body", }); - -export { schemaBooking, withValidBooking }; diff --git a/lib/validations/credential.ts b/lib/validations/credential.ts index 4f371491d4..001e4870f6 100644 --- a/lib/validations/credential.ts +++ b/lib/validations/credential.ts @@ -1,11 +1,13 @@ import { withValidation } from "next-validations"; -import { z } from "zod"; -const schemaCredential = z.object({}).strict(); -const withValidCredential = withValidation({ - schema: schemaCredential, +import { _CredentialModel as Credential } from "@calcom/prisma/zod"; + +export const schemaCredentialBodyParams = Credential.omit({ id: true }); + +export const schemaCredentialPublic = Credential.omit({}); + +export const withValidCredential = withValidation({ + schema: schemaCredentialBodyParams, type: "Zod", mode: "body", }); - -export { schemaCredential, withValidCredential }; diff --git a/lib/validations/daily-event-reference.ts b/lib/validations/daily-event-reference.ts index 3fcdcb2553..da24927310 100644 --- a/lib/validations/daily-event-reference.ts +++ b/lib/validations/daily-event-reference.ts @@ -1,11 +1,13 @@ import { withValidation } from "next-validations"; -import { z } from "zod"; -const schemaDailyEventReference = z.object({}).strict(); -const withValidDailyEventReference = withValidation({ - schema: schemaDailyEventReference, +import { _DailyEventReferenceModel as DailyEventReference } from "@calcom/prisma/zod"; + +export const schemaDailyEventReferenceBodyParams = DailyEventReference.omit({ id: true }); + +export const schemaDailyEventReferencePublic = DailyEventReference.omit({}); + +export const withValidDailyEventReference = withValidation({ + schema: schemaDailyEventReferenceBodyParams, type: "Zod", mode: "body", }); - -export { schemaDailyEventReference, withValidDailyEventReference }; diff --git a/lib/validations/destination-calendar.ts b/lib/validations/destination-calendar.ts index 541d9db59f..002d68d097 100644 --- a/lib/validations/destination-calendar.ts +++ b/lib/validations/destination-calendar.ts @@ -1,11 +1,13 @@ import { withValidation } from "next-validations"; -import { z } from "zod"; -const schemaDestinationCalendar = z.object({}).strict(); -const withValidDestinationCalendar = withValidation({ - schema: schemaDestinationCalendar, +import { _DestinationCalendarModel as DestinationCalendar } from "@calcom/prisma/zod"; + +export const schemaDestinationCalendarBodyParams = DestinationCalendar.omit({ id: true }); + +export const schemaDestinationCalendarPublic = DestinationCalendar.omit({}); + +export const withValidDestinationCalendar = withValidation({ + schema: schemaDestinationCalendarBodyParams, type: "Zod", mode: "body", }); - -export { schemaDestinationCalendar, withValidDestinationCalendar }; diff --git a/lib/validations/eventType.ts b/lib/validations/eventType.ts index 7d96883133..f257a4d0a8 100644 --- a/lib/validations/eventType.ts +++ b/lib/validations/eventType.ts @@ -1,18 +1,13 @@ import { withValidation } from "next-validations"; -import { z } from "zod"; -const schemaEventType = z - .object({ - title: z.string().min(3), - slug: z.string().min(3), - length: z.number().min(1).max(1440), // max is a full day. - description: z.string().min(3).optional(), - }) - .strict(); -const withValidEventType = withValidation({ - schema: schemaEventType, +import { _EventTypeModel as EventType } from "@calcom/prisma/zod"; + +export const schemaEventTypeBodyParams = EventType.omit({ id: true }); + +export const schemaEventTypePublic = EventType.omit({}); + +export const withValidEventType = withValidation({ + schema: schemaEventTypeBodyParams, type: "Zod", mode: "body", }); - -export { schemaEventType, withValidEventType }; diff --git a/lib/validations/membership.ts b/lib/validations/membership.ts index 4b4a5a0c33..46444e6f86 100644 --- a/lib/validations/membership.ts +++ b/lib/validations/membership.ts @@ -1,11 +1,13 @@ import { withValidation } from "next-validations"; -import { z } from "zod"; -const schemaMembership = z.object({}).strict(); -const withValidMembership = withValidation({ - schema: schemaMembership, +import { _MembershipModel as Membership } from "@calcom/prisma/zod"; + +export const schemaMembershipBodyParams = Membership.omit({}); + +export const schemaMembershipPublic = Membership.omit({}); + +export const withValidMembership = withValidation({ + schema: schemaMembershipBodyParams, type: "Zod", mode: "body", }); - -export { schemaMembership, withValidMembership }; diff --git a/lib/validations/payment.ts b/lib/validations/payment.ts index f1ed09dcde..7a9a138a13 100644 --- a/lib/validations/payment.ts +++ b/lib/validations/payment.ts @@ -1,11 +1,13 @@ import { withValidation } from "next-validations"; -import { z } from "zod"; -const schemaPayment = z.object({}).strict(); -const withValidPayment = withValidation({ - schema: schemaPayment, +import { _PaymentModel as Payment } from "@calcom/prisma/zod"; + +export const schemaPaymentBodyParams = Payment.omit({ id: true }); + +export const schemaPaymentPublic = Payment.omit({}); + +export const withValidPayment = withValidation({ + schema: schemaPaymentBodyParams, type: "Zod", mode: "body", }); - -export { schemaPayment, withValidPayment }; diff --git a/lib/validations/schedule.ts b/lib/validations/schedule.ts index 5c8e887271..ad6d403b00 100644 --- a/lib/validations/schedule.ts +++ b/lib/validations/schedule.ts @@ -1,11 +1,13 @@ import { withValidation } from "next-validations"; -import { z } from "zod"; -const schemaSchedule = z.object({}).strict(); -const withValidSchedule = withValidation({ - schema: schemaSchedule, +import { _ScheduleModel as Schedule } from "@calcom/prisma/zod"; + +export const schemaScheduleBodyParams = Schedule.omit({ id: true }); + +export const schemaSchedulePublic = Schedule.omit({}); + +export const withValidSchedule = withValidation({ + schema: schemaScheduleBodyParams, type: "Zod", mode: "body", }); - -export { schemaSchedule, withValidSchedule }; diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 457a818815..198f4797a8 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -1,12 +1,13 @@ import { withValidation } from "next-validations"; -import { z } from "zod"; -const schemaWebhook = z.object({}).strict(); +import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; -const withValidWebhook = withValidation({ - schema: schemaWebhook, +export const schemaWebhookBodyParams = Webhook.omit({ id: true }); + +export const schemaWebhookPublic = Webhook.omit({}); + +export const withValidWebhook = withValidation({ + schema: schemaWebhookBodyParams, type: "Zod", mode: "body", }); - -export { schemaWebhook, withValidWebhook }; diff --git a/pages/api/_middleware.ts b/pages/api/_middleware.ts index 6a3038451a..bd5d664589 100644 --- a/pages/api/_middleware.ts +++ b/pages/api/_middleware.ts @@ -1,11 +1,10 @@ -// import { NextApiResponse } from "next"; import { NextRequest, NextResponse } from "next/server"; // Not much useful yet as prisma.client can't be used in the middlewares (client is not available) // For now we just throw early if no apiKey is passed, // but we could also check if the apiKey is valid if we had prisma here. -export default async function requireApiKeyAsQueryParams({ nextUrl }: NextRequest, res: NextResponse) { +export default async function requireApiKeyAsQueryParams({ nextUrl }: NextRequest) { const response = NextResponse.next(); const apiKey = nextUrl.searchParams.get("apiKey"); diff --git a/pages/api/event-types/[id]/delete.ts b/pages/api/event-types/[id]/delete.ts index 4155c87ce4..8b9add8c87 100644 --- a/pages/api/event-types/[id]/delete.ts +++ b/pages/api/event-types/[id]/delete.ts @@ -2,29 +2,40 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BaseResponse } from "@lib/types"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/eventTypes/:id/delete: + * delete: + * description: Remove an existing eventType + * responses: + * 201: + * description: OK, eventType removed successfuly + * model: EventType + * 400: + * description: Bad request. EventType id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteEventType(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query", safe.error); -export async function deleteEventType(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const eventType = await prisma.eventType.delete({ where: { id: safe.data.id } }); - // We only remove the eventType type from the database if there's an existing resource. - if (eventType) - res.status(200).json({ message: `eventType with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.eventType.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` }); - // Reject any other HTTP method than POST - } else - res.status(405).json({ message: "Only DELETE Method allowed in /availabilities/[id]/delete endpoint" }); + const data = await prisma.eventType.delete({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ message: `EventType with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `EventType with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withValidQueryIdTransformParseInt(deleteEventType); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteEventType)); diff --git a/pages/api/event-types/[id]/edit.ts b/pages/api/event-types/[id]/edit.ts index 6ebe32f026..ecf8a42f76 100644 --- a/pages/api/event-types/[id]/edit.ts +++ b/pages/api/event-types/[id]/edit.ts @@ -1,45 +1,53 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { EventType } from "@calcom/prisma/client"; -import { schemaEventType, withValidEventType } from "@lib/validations/eventType"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { EventTypeResponse } from "@lib/types"; +import { + schemaEventTypeBodyParams, + schemaEventTypePublic, + withValidEventType, +} from "@lib/validations/eventType"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: EventType; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/eventTypes/:id/edit: + * patch: + * description: Edits an existing eventType + * responses: + * 201: + * description: OK, eventType edited successfuly + * model: EventType + * 400: + * description: Bad request. EventType body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editEventType(req: NextApiRequest, res: NextApiResponse) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaEventTypeBodyParams.safeParse(req.body); -export async function editEventType(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaEventType.safeParse(body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const eventType = await prisma.eventType.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaEventTypePublic.parse(eventType); - if (method === "PATCH") { - if (safeQuery.success && safeBody.success) { - await prisma.eventType - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((event) => { - res.status(200).json({ data: event }); - }) - .catch((error) => { - res - .status(404) - .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); - }); - } - } else { - // Reject any other HTTP method than POST - res.status(405).json({ message: "Only PATCH Method allowed for updating event-types" }); - } + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, + error, + }); } -export default withValidQueryIdTransformParseInt(withValidEventType(editEventType)); +export default withMiddleware("HTTP_PATCH")( + withValidQueryIdTransformParseInt(withValidEventType(editEventType)) +); diff --git a/pages/api/event-types/[id]/index.ts b/pages/api/event-types/[id]/index.ts index 3e8b642379..cc9838dbb7 100644 --- a/pages/api/event-types/[id]/index.ts +++ b/pages/api/event-types/[id]/index.ts @@ -1,32 +1,42 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { EventType } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { EventTypeResponse } from "@lib/types"; +import { schemaEventTypePublic } from "@lib/validations/eventType"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: EventType; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/eventTypes/:id: + * get: + * description: find eventType by ID + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: EventType was not found + */ +export async function eventTypeById(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); -export async function eventType(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); + const eventType = await prisma.eventType.findUnique({ where: { id: safe.data.id } }); + const data = schemaEventTypePublic.parse(eventType); - if (method === "GET" && safe.success) { - const event = await prisma.eventType.findUnique({ where: { id: safe.data.id } }); - - if (event) res.status(200).json({ data: event }); - if (!event) res.status(404).json({ message: "Event type not found" }); - } else { - // Reject any other HTTP method than POST - res.status(405).json({ message: "Only GET Method allowed" }); - } + if (eventType) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "EventType was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(eventType); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(eventTypeById)); diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index e50a8cf6da..a6ef52c501 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -1,21 +1,35 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { EventType } from "@calcom/prisma/client"; -type ResponseData = { - data?: EventType[]; - message?: string; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { EventTypesResponse } from "@lib/types"; +import { schemaEventTypePublic } from "@lib/validations/eventType"; -export default async function eventType(req: NextApiRequest, res: NextApiResponse) { - const { method } = req; - if (method === "GET") { - const data = await prisma.eventType.findMany(); - res.status(200).json({ data }); - } else { - // Reject any other HTTP method than POST - res.status(405).json({ message: "Only GET Method allowed" }); - } +/** + * @swagger + * /api/eventTypes: + * get: + * description: Returns all eventTypes + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No eventTypes were found + */ +async function allEventTypes(_: NextApiRequest, res: NextApiResponse) { + const eventTypes = await prisma.eventType.findMany(); + const data = eventTypes.map((eventType) => schemaEventTypePublic.parse(eventType)); + + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "No EventTypes were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allEventTypes); diff --git a/pages/api/event-types/new.ts b/pages/api/event-types/new.ts index 7e87e30418..17d2e06190 100644 --- a/pages/api/event-types/new.ts +++ b/pages/api/event-types/new.ts @@ -1,30 +1,43 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { EventType } from "@calcom/prisma/client"; -import { schemaEventType, withValidEventType } from "@lib/validations/eventType"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { EventTypeResponse } from "@lib/types"; +import { + schemaEventTypeBodyParams, + schemaEventTypePublic, + withValidEventType, +} from "@lib/validations/eventType"; -type ResponseData = { - data?: EventType; - message?: string; - error?: string; -}; +/** + * @swagger + * /api/eventTypes/new: + * post: + * description: Creates a new eventType + * responses: + * 201: + * description: OK, eventType created + * model: EventType + * 400: + * description: Bad request. EventType body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createEventType(req: NextApiRequest, res: NextApiResponse) { + const safe = schemaEventTypeBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createEventType(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - if (method === "POST") { - const safe = schemaEventType.safeParse(body); - if (safe.success && safe.data) { - await prisma.eventType - .create({ data: safe.data }) - .then((event) => res.status(201).json({ data: event })) - .catch((error) => res.status(400).json({ message: "Could not create event type", error: error })); - } - } else { - // Reject any other HTTP method than POST - res.status(405).json({ error: "Only POST Method allowed" }); - } + const eventType = await prisma.eventType.create({ data: safe.data }); + const data = schemaEventTypePublic.parse(eventType); + + if (data) res.status(201).json({ data, message: "EventType created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new eventType", + error, + }); } -export default withValidEventType(createEventType); +export default withMiddleware("HTTP_POST")(withValidEventType(createEventType)); From 12de89294dd7ed3cc2b5400fe773f53fe65e07f8 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 31 Mar 2022 22:14:37 +0200 Subject: [PATCH 048/658] swagger docs add params, memberships handle compoundId --- lib/types.ts | 2 + pages/api/_middleware.ts | 2 +- pages/api/docs.ts | 6 +- pages/api/event-types/[id]/delete.ts | 2 +- pages/api/event-types/[id]/edit.ts | 2 +- pages/api/event-types/[id]/index.ts | 11 +++- pages/api/event-types/index.ts | 2 +- pages/api/event-types/new.ts | 2 +- pages/api/memberships/[id]/delete.ts | 67 +++++++++++++------- pages/api/memberships/[id]/edit.ts | 69 ++++++++++++--------- pages/api/memberships/[id]/index.ts | 68 ++++++++++++++------ pages/api/memberships/index.ts | 38 +++++++++--- pages/api/memberships/new.ts | 55 ++++++++++------ pages/api/schedules/[id]/delete.ts | 47 +++++++++----- pages/api/schedules/[id]/edit.ts | 63 +++++++++++-------- pages/api/schedules/[id]/index.ts | 54 +++++++++++----- pages/api/schedules/index.ts | 38 +++++++++--- pages/api/schedules/new.ts | 51 +++++++++------ pages/api/selected-calendars/[id]/delete.ts | 2 +- pages/api/selected-calendars/[id]/edit.ts | 2 +- pages/api/selected-calendars/[id]/index.ts | 13 +++- pages/api/selected-calendars/index.ts | 2 +- pages/api/selected-calendars/new.ts | 2 +- pages/api/teams/[id]/delete.ts | 4 +- pages/api/teams/[id]/edit.ts | 4 +- pages/api/teams/[id]/index.ts | 4 +- pages/api/teams/index.ts | 4 +- pages/api/teams/new.ts | 4 +- pages/api/users/[id]/delete.ts | 13 +++- pages/api/users/[id]/edit.ts | 4 +- pages/api/users/[id]/index.ts | 13 +++- pages/api/users/index.ts | 4 +- pages/api/users/new.ts | 11 +++- 33 files changed, 460 insertions(+), 205 deletions(-) diff --git a/lib/types.ts b/lib/types.ts index 100fde2b61..cec3f65c0b 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -21,10 +21,12 @@ export type BaseResponse = { message?: string; error?: Error; }; + // User export type UserResponse = BaseResponse & { data?: Partial; }; + export type UsersResponse = BaseResponse & { data?: Partial[]; }; diff --git a/pages/api/_middleware.ts b/pages/api/_middleware.ts index bd5d664589..35529757ba 100644 --- a/pages/api/_middleware.ts +++ b/pages/api/_middleware.ts @@ -9,7 +9,7 @@ export default async function requireApiKeyAsQueryParams({ nextUrl }: NextReques const apiKey = nextUrl.searchParams.get("apiKey"); if (apiKey) return response; - // if no apiKey is passed, we throw early a 401 unauthorized + // if no apiKey is passed, we throw early a 401 unauthorized asking for a valid apiKey else new NextResponse( JSON.stringify({ diff --git a/pages/api/docs.ts b/pages/api/docs.ts index e855eacfd8..8e489785bd 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -1,12 +1,14 @@ +import pjson from "@/package.json"; import { withSwagger } from "next-swagger-doc"; const swaggerHandler = withSwagger({ definition: { openapi: "3.0.0", info: { - title: "Cal.com Public API", - version: "1.0.0", + title: `${pjson.name}: ${pjson.description}`, + version: pjson.version, }, + tags: ["users", "teams"], }, apiFolder: "pages/api", }); diff --git a/pages/api/event-types/[id]/delete.ts b/pages/api/event-types/[id]/delete.ts index 8b9add8c87..4ac7f612dc 100644 --- a/pages/api/event-types/[id]/delete.ts +++ b/pages/api/event-types/[id]/delete.ts @@ -13,7 +13,7 @@ import { * @swagger * /api/eventTypes/:id/delete: * delete: - * description: Remove an existing eventType + * summary: Remove an existing eventType * responses: * 201: * description: OK, eventType removed successfuly diff --git a/pages/api/event-types/[id]/edit.ts b/pages/api/event-types/[id]/edit.ts index ecf8a42f76..08458274e3 100644 --- a/pages/api/event-types/[id]/edit.ts +++ b/pages/api/event-types/[id]/edit.ts @@ -18,7 +18,7 @@ import { * @swagger * /api/eventTypes/:id/edit: * patch: - * description: Edits an existing eventType + * summary: Edits an existing eventType * responses: * 201: * description: OK, eventType edited successfuly diff --git a/pages/api/event-types/[id]/index.ts b/pages/api/event-types/[id]/index.ts index cc9838dbb7..9a7236577b 100644 --- a/pages/api/event-types/[id]/index.ts +++ b/pages/api/event-types/[id]/index.ts @@ -12,9 +12,16 @@ import { /** * @swagger - * /api/eventTypes/:id: + * /api/eventTypes/{id}: * get: - * description: find eventType by ID + * summary: find eventType by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the event type to get * responses: * 200: * description: OK diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index a6ef52c501..a9bd50bce7 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -10,7 +10,7 @@ import { schemaEventTypePublic } from "@lib/validations/eventType"; * @swagger * /api/eventTypes: * get: - * description: Returns all eventTypes + * summary: Returns all eventTypes * responses: * 200: * description: OK diff --git a/pages/api/event-types/new.ts b/pages/api/event-types/new.ts index 17d2e06190..e0a6bf4707 100644 --- a/pages/api/event-types/new.ts +++ b/pages/api/event-types/new.ts @@ -14,7 +14,7 @@ import { * @swagger * /api/eventTypes/new: * post: - * description: Creates a new eventType + * summary: Creates a new eventType * responses: * 201: * description: OK, eventType created diff --git a/pages/api/memberships/[id]/delete.ts b/pages/api/memberships/[id]/delete.ts index 5cbd96fca4..b33148e6d6 100644 --- a/pages/api/memberships/[id]/delete.ts +++ b/pages/api/memberships/[id]/delete.ts @@ -2,28 +2,53 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BaseResponse } from "@lib/types"; +import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; -type ResponseData = { - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/memberships/{userId}_{teamId}/delete: + * delete: + * summary: Remove an existing membership + * parameters: + * - in: path + * - name: userId + * schema: + * type: integer + * required: true + * description: Numeric ID of the user to get the membership of + * * - name: teamId + * schema: + * type: integer + * required: true + * description: Numeric ID of the team to get the membership of + * tags: + * - memberships + * responses: + * 201: + * description: OK, membership removed successfuly + * model: Membership + * 400: + * description: Bad request. Membership id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteMembership(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdAsString.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query", safe.error); + const [userId, teamId] = safe.data.id.split("_"); + const data = await prisma.membership.delete({ + where: { userId_teamId: { userId: parseInt(userId), teamId: parseInt(teamId) } }, + }); -export async function deleteMembership(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const membership = await prisma.membership.delete({ where: { id: safe.data.id } }); - // We only remove the membership type from the database if there's an existing resource. - if (membership) - res.status(200).json({ message: `membership with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.membership.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only DELETE Method allowed" }); + if (data) res.status(200).json({ message: `Membership with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `Membership with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withValidQueryIdTransformParseInt(deleteMembership); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdString(deleteMembership)); diff --git a/pages/api/memberships/[id]/edit.ts b/pages/api/memberships/[id]/edit.ts index 990c63914e..66c6ccec24 100644 --- a/pages/api/memberships/[id]/edit.ts +++ b/pages/api/memberships/[id]/edit.ts @@ -1,38 +1,51 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Membership } from "@calcom/prisma/client"; -import { schemaMembership, withValidMembership } from "@lib/validations/membership"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { MembershipResponse } from "@lib/types"; import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; + schemaMembershipBodyParams, + schemaMembershipPublic, + withValidMembership, +} from "@lib/validations/membership"; +import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; -type ResponseData = { - data?: Membership; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/memberships/{id}/edit: + * patch: + * summary: Edits an existing membership + * tags: + * - memberships + * responses: + * 201: + * description: OK, membership edited successfuly + * model: Membership + * 400: + * description: Bad request. Membership body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editMembership(req: NextApiRequest, res: NextApiResponse) { + const safeQuery = await schemaQueryIdAsString.safeParse(req.query); + const safeBody = await schemaMembershipBodyParams.safeParse(req.body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const [userId, teamId] = safeQuery.data.id.split("_"); -export async function editMembership(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaMembership.safeParse(body); + const membership = await prisma.membership.update({ + where: { userId_teamId: { userId: parseInt(userId), teamId: parseInt(teamId) } }, + data: safeBody.data, + }); + const data = schemaMembershipPublic.parse(membership); - if (method === "PATCH" && safeQuery.success && safeBody.success) { - const data = await prisma.membership.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - if (data) res.status(200).json({ data }); - else - res - .status(404) - .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); - - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only PATCH Method allowed for updating memberships" }); + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, + error, + }); } -export default withValidQueryIdTransformParseInt(withValidMembership(editMembership)); +export default withMiddleware("HTTP_PATCH")(withValidQueryIdString(withValidMembership(editMembership))); diff --git a/pages/api/memberships/[id]/index.ts b/pages/api/memberships/[id]/index.ts index 6aef005fa9..5bc5f79496 100644 --- a/pages/api/memberships/[id]/index.ts +++ b/pages/api/memberships/[id]/index.ts @@ -1,29 +1,57 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Membership } from "@calcom/prisma/client"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { MembershipResponse } from "@lib/types"; +import { schemaMembershipPublic } from "@lib/validations/membership"; +import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; -type ResponseData = { - data?: Membership; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/memberships/{userId}_{teamId}: + * get: + * summary: find membership by userID and teamID + * parameters: + * - in: path + * name: userId + * schema: + * type: integer + * required: true + * description: Numeric userId of the membership to get + * - in: path + * name: teamId + * schema: + * type: integer + * required: true + * description: Numeric teamId of the membership to get + * tags: + * - memberships + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Membership was not found + */ +export async function membershipById(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdAsString.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); + const [userId, teamId] = safe.data.id.split("_"); -export async function membership(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "GET" && safe.success) { - const data = await prisma.membership.findUnique({ where: { id: safe.data.id } }); + const membership = await prisma.membership.findUnique({ + where: { userId_teamId: { userId: parseInt(userId), teamId: parseInt(teamId) } }, + }); + const data = schemaMembershipPublic.parse(membership); - if (data) res.status(200).json({ data }); - else res.status(404).json({ message: "Event type not found" }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only GET Method allowed" }); + if (membership) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "Membership was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(membership); +export default withMiddleware("HTTP_GET")(withValidQueryIdString(membershipById)); diff --git a/pages/api/memberships/index.ts b/pages/api/memberships/index.ts index 59e5c21b5c..d53670ce92 100644 --- a/pages/api/memberships/index.ts +++ b/pages/api/memberships/index.ts @@ -1,15 +1,37 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Membership } from "@calcom/prisma/client"; -type ResponseData = { - data?: Membership[]; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { MembershipsResponse } from "@lib/types"; +import { schemaMembershipPublic } from "@lib/validations/membership"; + +/** + * @swagger + * /api/memberships: + * get: + * summary: Returns all memberships + * tags: + * - memberships + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No memberships were found + */ +async function allMemberships(_: NextApiRequest, res: NextApiResponse) { + const memberships = await prisma.membership.findMany(); + const data = memberships.map((membership) => schemaMembershipPublic.parse(membership)); -export default async function membership(req: NextApiRequest, res: NextApiResponse) { - const data = await prisma.membership.findMany(); if (data) res.status(200).json({ data }); - else res.status(400).json({ error: "No data found" }); + else + (error: Error) => + res.status(404).json({ + message: "No Memberships were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allMemberships); diff --git a/pages/api/memberships/new.ts b/pages/api/memberships/new.ts index 8df61fc964..e3b9dbe02f 100644 --- a/pages/api/memberships/new.ts +++ b/pages/api/memberships/new.ts @@ -1,26 +1,45 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Membership } from "@calcom/prisma/client"; -import { schemaMembership, withValidMembership } from "@lib/validations/membership"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { MembershipResponse } from "@lib/types"; +import { + schemaMembershipBodyParams, + schemaMembershipPublic, + withValidMembership, +} from "@lib/validations/membership"; -type ResponseData = { - data?: Membership; - message?: string; - error?: string; -}; +/** + * @swagger + * /api/memberships/new: + * post: + * summary: Creates a new membership + * tags: + * - memberships + * responses: + * 201: + * description: OK, membership created + * model: Membership + * 400: + * description: Bad request. Membership body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createMembership(req: NextApiRequest, res: NextApiResponse) { + const safe = schemaMembershipBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createMembership(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - const safe = schemaMembership.safeParse(body); - if (method === "POST" && safe.success) { - await prisma.membership - .create({ data: safe.data }) - .then((data) => res.status(201).json({ data })) - .catch((error) => res.status(400).json({ message: "Could not create membership type", error: error })); - // Reject any other HTTP method than POST - } else res.status(405).json({ error: "Only POST Method allowed" }); + const membership = await prisma.membership.create({ data: safe.data }); + const data = schemaMembershipPublic.parse(membership); + + if (data) res.status(201).json({ data, message: "Membership created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new membership", + error, + }); } -export default withValidMembership(createMembership); +export default withMiddleware("HTTP_POST")(withValidMembership(createMembership)); diff --git a/pages/api/schedules/[id]/delete.ts b/pages/api/schedules/[id]/delete.ts index 17aba616cf..4b037be9d2 100644 --- a/pages/api/schedules/[id]/delete.ts +++ b/pages/api/schedules/[id]/delete.ts @@ -2,27 +2,42 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BaseResponse } from "@lib/types"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/schedules/:id/delete: + * delete: + * summary: Remove an existing schedule + * tags: + * - schedules + * responses: + * 201: + * description: OK, schedule removed successfuly + * model: Schedule + * 400: + * description: Bad request. Schedule id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteSchedule(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query", safe.error); -export async function deleteSchedule(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const schedule = await prisma.schedule.delete({ where: { id: safe.data.id } }); - // We only remove the schedule type from the database if there's an existing resource. - if (schedule) res.status(200).json({ message: `schedule with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.schedule.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only DELETE Method allowed" }); + const data = await prisma.schedule.delete({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ message: `Schedule with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `Schedule with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withValidQueryIdTransformParseInt(deleteSchedule); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteSchedule)); diff --git a/pages/api/schedules/[id]/edit.ts b/pages/api/schedules/[id]/edit.ts index b40923504e..2f750536f8 100644 --- a/pages/api/schedules/[id]/edit.ts +++ b/pages/api/schedules/[id]/edit.ts @@ -1,38 +1,51 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Schedule } from "@calcom/prisma/client"; -import { schemaSchedule, withValidSchedule } from "@lib/validations/schedule"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { ScheduleResponse } from "@lib/types"; +import { schemaScheduleBodyParams, schemaSchedulePublic, withValidSchedule } from "@lib/validations/schedule"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: Schedule; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/schedules/:id/edit: + * patch: + * summary: Edits an existing schedule + * tags: + * - schedules + * responses: + * 201: + * description: OK, schedule edited successfuly + * model: Schedule + * 400: + * description: Bad request. Schedule body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editSchedule(req: NextApiRequest, res: NextApiResponse) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaScheduleBodyParams.safeParse(req.body); -export async function editSchedule(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaSchedule.safeParse(body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const schedule = await prisma.schedule.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaSchedulePublic.parse(schedule); - if (method === "PATCH" && safeQuery.success && safeBody.success) { - const data = await prisma.schedule.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - if (data) res.status(200).json({ data }); - else - res - .status(404) - .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); - - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only PATCH Method allowed for updating schedules" }); + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, + error, + }); } -export default withValidQueryIdTransformParseInt(withValidSchedule(editSchedule)); +export default withMiddleware("HTTP_PATCH")( + withValidQueryIdTransformParseInt(withValidSchedule(editSchedule)) +); diff --git a/pages/api/schedules/[id]/index.ts b/pages/api/schedules/[id]/index.ts index 482267fcbe..1a8675d53f 100644 --- a/pages/api/schedules/[id]/index.ts +++ b/pages/api/schedules/[id]/index.ts @@ -1,29 +1,51 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Schedule } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { ScheduleResponse } from "@lib/types"; +import { schemaSchedulePublic } from "@lib/validations/schedule"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: Schedule; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/schedules/{id}: + * get: + * summary: Get schedule by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the schedule to delete + * tags: + * - schedules + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Schedule was not found + */ +export async function scheduleById(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); -export async function schedule(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "GET" && safe.success) { - const data = await prisma.schedule.findUnique({ where: { id: safe.data.id } }); + const schedule = await prisma.schedule.findUnique({ where: { id: safe.data.id } }); + const data = schemaSchedulePublic.parse(schedule); - if (data) res.status(200).json({ data }); - else res.status(404).json({ message: "Event type not found" }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only GET Method allowed" }); + if (schedule) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "Schedule was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(schedule); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(scheduleById)); diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index fc22c4e2e0..cd09534c99 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -1,15 +1,37 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Schedule } from "@calcom/prisma/client"; -type ResponseData = { - data?: Schedule[]; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { SchedulesResponse } from "@lib/types"; +import { schemaSchedulePublic } from "@lib/validations/schedule"; + +/** + * @swagger + * /api/schedules: + * get: + * summary: Returns all schedules + * tags: + * - schedules + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No schedules were found + */ +async function allSchedules(_: NextApiRequest, res: NextApiResponse) { + const schedules = await prisma.schedule.findMany(); + const data = schedules.map((schedule) => schemaSchedulePublic.parse(schedule)); -export default async function schedule(req: NextApiRequest, res: NextApiResponse) { - const data = await prisma.schedule.findMany(); if (data) res.status(200).json({ data }); - else res.status(400).json({ error: "No data found" }); + else + (error: Error) => + res.status(404).json({ + message: "No Schedules were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allSchedules); diff --git a/pages/api/schedules/new.ts b/pages/api/schedules/new.ts index 081acc9a5c..d4a3ea4416 100644 --- a/pages/api/schedules/new.ts +++ b/pages/api/schedules/new.ts @@ -1,26 +1,41 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Schedule } from "@calcom/prisma/client"; -import { schemaSchedule, withValidSchedule } from "@lib/validations/schedule"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { ScheduleResponse } from "@lib/types"; +import { schemaScheduleBodyParams, schemaSchedulePublic, withValidSchedule } from "@lib/validations/schedule"; -type ResponseData = { - data?: Schedule; - message?: string; - error?: string; -}; +/** + * @swagger + * /api/schedules/new: + * post: + * summary: Creates a new schedule + * tags: + * - schedules + * responses: + * 201: + * description: OK, schedule created + * model: Schedule + * 400: + * description: Bad request. Schedule body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createSchedule(req: NextApiRequest, res: NextApiResponse) { + const safe = schemaScheduleBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createSchedule(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - const safe = schemaSchedule.safeParse(body); - if (method === "POST" && safe.success) { - await prisma.schedule - .create({ data: safe.data }) - .then((data) => res.status(201).json({ data })) - .catch((error) => res.status(400).json({ message: "Could not create schedule type", error: error })); - // Reject any other HTTP method than POST - } else res.status(405).json({ error: "Only POST Method allowed" }); + const schedule = await prisma.schedule.create({ data: safe.data }); + const data = schemaSchedulePublic.parse(schedule); + + if (data) res.status(201).json({ data, message: "Schedule created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new schedule", + error, + }); } -export default withValidSchedule(createSchedule); +export default withMiddleware("HTTP_POST")(withValidSchedule(createSchedule)); diff --git a/pages/api/selected-calendars/[id]/delete.ts b/pages/api/selected-calendars/[id]/delete.ts index 249912dce9..d4f0fac746 100644 --- a/pages/api/selected-calendars/[id]/delete.ts +++ b/pages/api/selected-calendars/[id]/delete.ts @@ -13,7 +13,7 @@ import { * @swagger * /api/selectedCalendars/:id/delete: * delete: - * description: Remove an existing selectedCalendar + * summary: Remove an existing selectedCalendar * responses: * 201: * description: OK, selectedCalendar removed successfuly diff --git a/pages/api/selected-calendars/[id]/edit.ts b/pages/api/selected-calendars/[id]/edit.ts index 96c9f08675..950c4c04eb 100644 --- a/pages/api/selected-calendars/[id]/edit.ts +++ b/pages/api/selected-calendars/[id]/edit.ts @@ -18,7 +18,7 @@ import { * @swagger * /api/selectedCalendars/:id/edit: * patch: - * description: Edits an existing selectedCalendar + * summary: Edits an existing selectedCalendar * responses: * 201: * description: OK, selectedCalendar edited successfuly diff --git a/pages/api/selected-calendars/[id]/index.ts b/pages/api/selected-calendars/[id]/index.ts index cf932ac5a2..3867c3834a 100644 --- a/pages/api/selected-calendars/[id]/index.ts +++ b/pages/api/selected-calendars/[id]/index.ts @@ -12,9 +12,18 @@ import { /** * @swagger - * /api/selectedCalendars/:id: + * /api/selectedCalendars/{id}: * get: - * description: find selectedCalendar by ID + * summary: find selectedCalendar by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the user to delete + * tags: + * - selected-calendars * responses: * 200: * description: OK diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index ab80b3aa0f..cb13635eec 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -10,7 +10,7 @@ import { schemaSelectedCalendarPublic } from "@lib/validations/selected-calendar * @swagger * /api/selectedCalendars: * get: - * description: Returns all selected calendars + * summary: Returns all selected calendars * responses: * 200: * description: OK diff --git a/pages/api/selected-calendars/new.ts b/pages/api/selected-calendars/new.ts index 22ae2a8657..dbca6d85a0 100644 --- a/pages/api/selected-calendars/new.ts +++ b/pages/api/selected-calendars/new.ts @@ -14,7 +14,7 @@ import { * @swagger * /api/selectedCalendars/new: * post: - * description: Creates a new selected calendar + * summary: Creates a new selected calendar * responses: * 201: * description: OK, selected calendar created diff --git a/pages/api/teams/[id]/delete.ts b/pages/api/teams/[id]/delete.ts index cf3825fd96..657e9628ce 100644 --- a/pages/api/teams/[id]/delete.ts +++ b/pages/api/teams/[id]/delete.ts @@ -13,7 +13,9 @@ import { * @swagger * /api/teams/:id/delete: * delete: - * description: Remove an existing team + * summary: Remove an existing team + * tags: + * - teams * responses: * 201: * description: OK, team removed successfuly diff --git a/pages/api/teams/[id]/edit.ts b/pages/api/teams/[id]/edit.ts index 4b1696d207..2b0411cdf8 100644 --- a/pages/api/teams/[id]/edit.ts +++ b/pages/api/teams/[id]/edit.ts @@ -14,7 +14,9 @@ import { schemaTeamBodyParams, schemaTeamPublic, withValidTeam } from "@lib/vali * @swagger * /api/teams/:id/edit: * patch: - * description: Edits an existing team + * summary: Edits an existing team + * tags: + * - teams * responses: * 201: * description: OK, team edited successfuly diff --git a/pages/api/teams/[id]/index.ts b/pages/api/teams/[id]/index.ts index 1047a479ef..0dedf16159 100644 --- a/pages/api/teams/[id]/index.ts +++ b/pages/api/teams/[id]/index.ts @@ -14,7 +14,9 @@ import { schemaTeamPublic } from "@lib/validations/team"; * @swagger * /api/teams/:id: * get: - * description: find team by ID + * summary: find team by ID + * tags: + * - teams * responses: * 200: * description: OK diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index 7497539eeb..a4ed336c38 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -10,7 +10,9 @@ import { schemaTeamPublic } from "@lib/validations/team"; * @swagger * /api/teams: * get: - * description: Returns all teams + * summary: Returns all teams + * tags: + * - teams * responses: * 200: * description: OK diff --git a/pages/api/teams/new.ts b/pages/api/teams/new.ts index b78759d249..6100b5c42d 100644 --- a/pages/api/teams/new.ts +++ b/pages/api/teams/new.ts @@ -10,7 +10,9 @@ import { schemaTeamBodyParams, schemaTeamPublic, withValidTeam } from "@lib/vali * @swagger * /api/teams/new: * post: - * description: Creates a new team + * summary: Creates a new team + * tags: + * - teams * responses: * 201: * description: OK, team created diff --git a/pages/api/users/[id]/delete.ts b/pages/api/users/[id]/delete.ts index 51b6e36cf6..b8b5a7a59f 100644 --- a/pages/api/users/[id]/delete.ts +++ b/pages/api/users/[id]/delete.ts @@ -11,9 +11,18 @@ import { /** * @swagger - * /api/users/:id/delete: + * /api/users/{id}/delete: * delete: - * description: Remove an existing user + * summary: Remove an existing user + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the user to delete + * tags: + * - users * responses: * 201: * description: OK, user removed successfuly diff --git a/pages/api/users/[id]/edit.ts b/pages/api/users/[id]/edit.ts index b78cb1f83c..3f37b36d77 100644 --- a/pages/api/users/[id]/edit.ts +++ b/pages/api/users/[id]/edit.ts @@ -14,7 +14,9 @@ import { schemaUserBodyParams, schemaUserPublic, withValidUser } from "@lib/vali * @swagger * /api/users/:id/edit: * patch: - * description: Edits an existing user + * summary: Edits an existing user + * tags: + * - users * responses: * 201: * description: OK, user edited successfuly diff --git a/pages/api/users/[id]/index.ts b/pages/api/users/[id]/index.ts index 04be633d5d..59987519b7 100644 --- a/pages/api/users/[id]/index.ts +++ b/pages/api/users/[id]/index.ts @@ -12,9 +12,18 @@ import { schemaUserPublic } from "@lib/validations/user"; /** * @swagger - * /api/users/:id: + * /api/users/{id}: * get: - * description: find user by ID + * summary: Get a user by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the user to get + * tags: + * - users * responses: * 200: * description: OK diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index a748315a4a..6bb3763a88 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -10,7 +10,9 @@ import { schemaUserPublic } from "@lib/validations/user"; * @swagger * /api/users: * get: - * description: Returns all users + * summary: Get all users + * tags: + * - users * responses: * 200: * description: OK diff --git a/pages/api/users/new.ts b/pages/api/users/new.ts index fd717213e0..70e6497b9b 100644 --- a/pages/api/users/new.ts +++ b/pages/api/users/new.ts @@ -10,7 +10,16 @@ import { schemaUserBodyParams, schemaUserPublic, withValidUser } from "@lib/vali * @swagger * /api/users/new: * post: - * description: Creates a new user + * summary: Creates a new user + * requestBody: + description: Optional description in *Markdown* + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/User' + * tags: + * - users * responses: * 201: * description: OK, user created From e284707250c3441dabdb46852dbff5595415a2ce Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 1 Apr 2022 17:53:52 +0200 Subject: [PATCH 049/658] initail work on paid booking, improve validations --- lib/helpers/withCost.ts | 25 +++++++++++ lib/helpers/withMiddleware.ts | 5 +-- lib/validations/apiKey.ts | 2 +- lib/validations/attendee.ts | 2 +- lib/validations/booking.ts | 14 ++++++- lib/validations/schedule.ts | 2 +- lib/validations/selected-calendar.ts | 2 +- lib/validations/team.ts | 2 +- lib/validations/user.ts | 2 +- lib/validations/webhook.ts | 2 +- package.json | 3 +- pages/api/bookings/new.ts | 63 ++++++++++++++++++---------- pages/api/teams/[id]/index.ts | 9 +++- pages/api/users/new.ts | 12 +++--- 14 files changed, 103 insertions(+), 42 deletions(-) create mode 100644 lib/helpers/withCost.ts diff --git a/lib/helpers/withCost.ts b/lib/helpers/withCost.ts new file mode 100644 index 0000000000..55f8e06ee5 --- /dev/null +++ b/lib/helpers/withCost.ts @@ -0,0 +1,25 @@ +// Make a middleware that adds a cost to running the request +// by calling stripeSubscription addCost() * pricePerBooking +// Initially to test out 0,5 cent per booking via API call +// withCost(5)(endpoint) +// Should add a charge of 0.5 cent per booking to the subscription of the user making the request +// Should be called in the middleware of the e +// +import { NextMiddleware } from "next-api-middleware"; + +export const withCost = (priceInCents: number): NextMiddleware => { + return async function (req, res, next) { + console.log(req.headers); + if ( + priceInCents > 0 + // && stripeCustomerId && stripeSubscriptionId + ) { + console.log(priceInCents); + // if (req.method === allowedHttpMethod || req.method == "OPTIONS") { + await next(); + } else { + res.status(405).json({ message: `We weren't able to process the payment for this transaction` }); + res.end(); + } + }; +}; diff --git a/lib/helpers/withMiddleware.ts b/lib/helpers/withMiddleware.ts index c410882081..e15c388d51 100644 --- a/lib/helpers/withMiddleware.ts +++ b/lib/helpers/withMiddleware.ts @@ -2,7 +2,7 @@ import { label } from "next-api-middleware"; import { addRequestId } from "./addRequestid"; import { captureErrors } from "./captureErrors"; -import { HTTP_POST, HTTP_DELETE, HTTP_PATCH, HTTP_GET, httpMethod } from "./httpMethods"; +import { HTTP_POST, HTTP_DELETE, HTTP_PATCH, HTTP_GET } from "./httpMethods"; import { verifyApiKey } from "./verifyApiKey"; const withMiddleware = label( @@ -14,9 +14,8 @@ const withMiddleware = label( addRequestId, verifyApiKey, sentry: captureErrors, - httpMethod: httpMethod("GET" || "DELETE" || "PATCH" || "POST"), }, - ["sentry", "verifyApiKey", "httpMethod", "addRequestId"] // <-- Provide a list of middleware to call automatically + ["sentry", "verifyApiKey", "addRequestId"] // <-- Provide a list of middleware to call automatically ); export { withMiddleware }; diff --git a/lib/validations/apiKey.ts b/lib/validations/apiKey.ts index 2d93b31e09..e12a50cefa 100644 --- a/lib/validations/apiKey.ts +++ b/lib/validations/apiKey.ts @@ -2,7 +2,7 @@ import { withValidation } from "next-validations"; import { _ApiKeyModel as ApiKey } from "@calcom/prisma/zod"; -export const schemaApiKeyBodyParams = ApiKey.omit({ id: true, userId: true, createdAt: true }); +export const schemaApiKeyBodyParams = ApiKey.omit({ id: true, userId: true, createdAt: true }).partial(); export const schemaApiKeyPublic = ApiKey.omit({ id: true, diff --git a/lib/validations/attendee.ts b/lib/validations/attendee.ts index bd55fb9361..5e62be3580 100644 --- a/lib/validations/attendee.ts +++ b/lib/validations/attendee.ts @@ -2,7 +2,7 @@ import { withValidation } from "next-validations"; import { _AttendeeModel as Attendee } from "@calcom/prisma/zod"; -export const schemaAttendeeBodyParams = Attendee.omit({ id: true }); +export const schemaAttendeeBodyParams = Attendee.omit({ id: true }).partial(); export const schemaAttendeePublic = Attendee.omit({}); diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index e7528764ab..df5293e053 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -1,8 +1,20 @@ import { withValidation } from "next-validations"; +import { z } from "zod"; import { _BookingModel as Booking } from "@calcom/prisma/zod"; -export const schemaBookingBodyParams = Booking.omit({ id: true }); +// Here we remove any parameters that are not needed for the API with omit. +const schemaBookingBaseBodyParams = Booking.omit({ id: true }).partial(); +// Here we redeclare the required ones after removing the ones we don't need. +// and making the rest optional with .partial() +const schemaBookingRequiredParams = z.object({ + uid: z.string(), + title: z.string(), + startTime: z.date(), + endTime: z.date(), +}); + +export const schemaBookingBodyParams = schemaBookingBaseBodyParams.merge(schemaBookingRequiredParams); export const schemaBookingPublic = Booking.omit({}); diff --git a/lib/validations/schedule.ts b/lib/validations/schedule.ts index ad6d403b00..dca4a77345 100644 --- a/lib/validations/schedule.ts +++ b/lib/validations/schedule.ts @@ -2,7 +2,7 @@ import { withValidation } from "next-validations"; import { _ScheduleModel as Schedule } from "@calcom/prisma/zod"; -export const schemaScheduleBodyParams = Schedule.omit({ id: true }); +export const schemaScheduleBodyParams = Schedule.omit({ id: true }).partial(); export const schemaSchedulePublic = Schedule.omit({}); diff --git a/lib/validations/selected-calendar.ts b/lib/validations/selected-calendar.ts index 2c8d871d52..f1bb0483ae 100644 --- a/lib/validations/selected-calendar.ts +++ b/lib/validations/selected-calendar.ts @@ -2,7 +2,7 @@ import { withValidation } from "next-validations"; import { _SelectedCalendarModel as SelectedCalendar } from "@calcom/prisma/zod"; -export const schemaSelectedCalendarBodyParams = SelectedCalendar.omit({}); +export const schemaSelectedCalendarBodyParams = SelectedCalendar.omit({}).partial(); export const schemaSelectedCalendarPublic = SelectedCalendar.omit({ userId: true }); diff --git a/lib/validations/team.ts b/lib/validations/team.ts index 20b79ac1c4..010d73282a 100644 --- a/lib/validations/team.ts +++ b/lib/validations/team.ts @@ -2,7 +2,7 @@ import { withValidation } from "next-validations"; import { _TeamModel as Team } from "@calcom/prisma/zod"; -export const schemaTeamBodyParams = Team.omit({ id: true }); +export const schemaTeamBodyParams = Team.omit({ id: true }).partial(); export const schemaTeamPublic = Team.omit({}); diff --git a/lib/validations/user.ts b/lib/validations/user.ts index 2058a20c2e..a626456145 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -8,7 +8,7 @@ export const schemaUserBodyParams = User.omit({ password: true, twoFactorEnabled: true, twoFactorSecret: true, -}); +}).partial(); export const schemaUserPublic = User.omit({ identityProvider: true, diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 198f4797a8..746443213d 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -2,7 +2,7 @@ import { withValidation } from "next-validations"; import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; -export const schemaWebhookBodyParams = Webhook.omit({ id: true }); +export const schemaWebhookBodyParams = Webhook.omit({ id: true }).partial(); export const schemaWebhookPublic = Webhook.omit({}); diff --git a/package.json b/package.json index 8f496b55e7..8507464bf3 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,6 @@ "next-swagger-doc": "^0.2.1", "next-transpile-modules": "^9.0.0", "next-validations": "^0.1.11", - "typescript": "^4.6.3", - "zod": "^3.14.2" + "typescript": "^4.6.3" } } diff --git a/pages/api/bookings/new.ts b/pages/api/bookings/new.ts index 50dc9ffbf2..fcc5f89efc 100644 --- a/pages/api/bookings/new.ts +++ b/pages/api/bookings/new.ts @@ -1,30 +1,49 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Booking } from "@calcom/prisma/client"; -import { schemaBooking, withValidBooking } from "@lib/validations/booking"; +import { withCost } from "@lib/helpers/withCost"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BookingResponse } from "@lib/types"; +import { schemaBookingBodyParams, schemaBookingPublic, withValidBooking } from "@lib/validations/booking"; -type ResponseData = { - data?: Booking; - message?: string; - error?: string; -}; +/** + * @swagger + * /api/bookings/new: + * post: + * summary: Creates a new booking + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/Booking' + * tags: + * - bookings + * responses: + * 201: + * description: OK, booking created + * model: Booking + * 400: + * description: Bad request. Booking body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createBooking(req: NextApiRequest, res: NextApiResponse) { + const safe = schemaBookingBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createBooking(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - if (method === "POST") { - const safe = schemaBooking.safeParse(body); - if (safe.success && safe.data) { - await prisma.booking - .create({ data: safe.data }) - .then((booking) => res.status(201).json({ data: booking })) - .catch((error) => res.status(400).json({ message: "Could not create booking type", error: error })); - } - } else { - // Reject any other HTTP method than POST - res.status(405).json({ error: "Only POST Method allowed" }); - } + const booking = await prisma.booking.create({ data: safe.data }); + const data = schemaBookingPublic.parse(booking); + + if (data) res.status(201).json({ data, message: "Booking created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new booking", + error, + }); } -export default withValidBooking(createBooking); +export default withMiddleware(withCost(5), "HTTP_POST")(withValidBooking(createBooking)); diff --git a/pages/api/teams/[id]/index.ts b/pages/api/teams/[id]/index.ts index 0dedf16159..218f296308 100644 --- a/pages/api/teams/[id]/index.ts +++ b/pages/api/teams/[id]/index.ts @@ -12,9 +12,16 @@ import { schemaTeamPublic } from "@lib/validations/team"; /** * @swagger - * /api/teams/:id: + * /api/teams/{id}: * get: * summary: find team by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the team to get * tags: * - teams * responses: diff --git a/pages/api/users/new.ts b/pages/api/users/new.ts index 70e6497b9b..52a25015b8 100644 --- a/pages/api/users/new.ts +++ b/pages/api/users/new.ts @@ -12,12 +12,12 @@ import { schemaUserBodyParams, schemaUserPublic, withValidUser } from "@lib/vali * post: * summary: Creates a new user * requestBody: - description: Optional description in *Markdown* - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/User' + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/User' * tags: * - users * responses: From 2b4a745f121e2660757fb39a80eaa9488dc5cd79 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 1 Apr 2022 22:04:42 +0200 Subject: [PATCH 050/658] feat: improve validations of users/attendee/availabilty to support required fields --- lib/validations/attendee.ts | 11 ++++++++++- lib/validations/availability.ts | 12 +++++++++++- lib/validations/user.ts | 9 ++++++++- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/lib/validations/attendee.ts b/lib/validations/attendee.ts index 5e62be3580..856ab2bcae 100644 --- a/lib/validations/attendee.ts +++ b/lib/validations/attendee.ts @@ -1,11 +1,20 @@ import { withValidation } from "next-validations"; +import { z } from "zod"; import { _AttendeeModel as Attendee } from "@calcom/prisma/zod"; -export const schemaAttendeeBodyParams = Attendee.omit({ id: true }).partial(); +export const schemaAttendeeBaseBodyParams = Attendee.omit({ id: true }).partial(); export const schemaAttendeePublic = Attendee.omit({}); +const schemaAttendeeRequiredParams = z.object({ + email: z.string().email(), + name: z.string(), + timeZone: z.string(), +}); + +export const schemaAttendeeBodyParams = schemaAttendeeBaseBodyParams.merge(schemaAttendeeRequiredParams); + export const withValidAttendee = withValidation({ schema: schemaAttendeeBodyParams, type: "Zod", diff --git a/lib/validations/availability.ts b/lib/validations/availability.ts index cd747bdf73..d55cfb74fa 100644 --- a/lib/validations/availability.ts +++ b/lib/validations/availability.ts @@ -1,11 +1,21 @@ import { withValidation } from "next-validations"; +import { z } from "zod"; import { _AvailabilityModel as Availability } from "@calcom/prisma/zod"; -export const schemaAvailabilityBodyParams = Availability.omit({ id: true }); +export const schemaAvailabilityBaseBodyParams = Availability.omit({ id: true }).partial(); export const schemaAvailabilityPublic = Availability.omit({}); +const schemaAvailabilityRequiredParams = z.object({ + startTime: z.string(), + endTime: z.string(), +}); + +export const schemaAvailabilityBodyParams = schemaAvailabilityBaseBodyParams.merge( + schemaAvailabilityRequiredParams +); + export const withValidAvailability = withValidation({ schema: schemaAvailabilityBodyParams, type: "Zod", diff --git a/lib/validations/user.ts b/lib/validations/user.ts index a626456145..ec3f7a2247 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -1,8 +1,9 @@ import { withValidation } from "next-validations"; +import { z } from "zod"; import { _UserModel as User } from "@calcom/prisma/zod"; -export const schemaUserBodyParams = User.omit({ +export const schemaUserBaseBodyParams = User.omit({ id: true, createdAt: true, password: true, @@ -10,6 +11,12 @@ export const schemaUserBodyParams = User.omit({ twoFactorSecret: true, }).partial(); +const schemaUserRequiredParams = z.object({ + email: z.string().email(), +}); + +export const schemaUserBodyParams = schemaUserBaseBodyParams.merge(schemaUserRequiredParams); + export const schemaUserPublic = User.omit({ identityProvider: true, identityProviderId: true, From 55f93cded6665a5ed48da1f98ad0fbe608fa4cdc Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 1 Apr 2022 22:05:10 +0200 Subject: [PATCH 051/658] feat: update attendees / availabilites / users endpoints and document parameters --- pages/api/attendees/[id]/delete.ts | 54 ++++++++++++------ pages/api/attendees/[id]/edit.ts | 71 ++++++++++++++--------- pages/api/attendees/[id]/index.ts | 55 ++++++++++++------ pages/api/attendees/index.ts | 44 ++++++++++----- pages/api/attendees/new.ts | 57 +++++++++++++------ pages/api/availabilities/[id]/delete.ts | 55 ++++++++++++------ pages/api/availabilities/[id]/edit.ts | 75 ++++++++++++++++--------- pages/api/availabilities/[id]/index.ts | 55 ++++++++++++------ pages/api/availabilities/index.ts | 44 ++++++++++----- pages/api/availabilities/new.ts | 68 ++++++++++++++-------- pages/api/event-types/[id]/delete.ts | 11 +++- pages/api/event-types/[id]/edit.ts | 11 +++- pages/api/event-types/[id]/index.ts | 2 +- pages/api/users/[id]/edit.ts | 11 +++- 14 files changed, 419 insertions(+), 194 deletions(-) diff --git a/pages/api/attendees/[id]/delete.ts b/pages/api/attendees/[id]/delete.ts index 99ca9eef3f..59cf150af5 100644 --- a/pages/api/attendees/[id]/delete.ts +++ b/pages/api/attendees/[id]/delete.ts @@ -2,27 +2,49 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BaseResponse } from "@lib/types"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/attendees/{id}/delete: + * delete: + * summary: Remove an existing attendee + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the attendee to delete + * tags: + * - attendees + * responses: + * 201: + * description: OK, attendee removed successfuly + * model: Attendee + * 400: + * description: Bad request. Attendee id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteAttendee(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query", safe.error); -export async function attendee(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const attendee = await prisma.attendee.delete({ where: { id: safe.data.id } }); - // We only remove the attendee type from the database if there's an existing resource. - if (attendee) res.status(200).json({ message: `attendee with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.attendee.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only DELETE Method allowed" }); + const data = await prisma.attendee.delete({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ message: `Attendee with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `Attendee with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withValidQueryIdTransformParseInt(attendee); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteAttendee)); diff --git a/pages/api/attendees/[id]/edit.ts b/pages/api/attendees/[id]/edit.ts index 78374a4dc0..0f0d5f2e0c 100644 --- a/pages/api/attendees/[id]/edit.ts +++ b/pages/api/attendees/[id]/edit.ts @@ -1,41 +1,58 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Attendee } from "@calcom/prisma/client"; -import { schemaAttendee, withValidAttendee } from "@lib/validations/attendee"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { AttendeeResponse } from "@lib/types"; +import { schemaAttendeeBodyParams, schemaAttendeePublic, withValidAttendee } from "@lib/validations/attendee"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: Attendee; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/attendees/{id}/edit: + * patch: + * summary: Edit an existing attendee + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the attendee to edit + * tags: + * - attendees + * responses: + * 201: + * description: OK, attendee edited successfuly + * model: Attendee + * 400: + * description: Bad request. Attendee body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editAttendee(req: NextApiRequest, res: NextApiResponse) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaAttendeeBodyParams.safeParse(req.body); -export async function editAttendee(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaAttendee.safeParse(body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const attendee = await prisma.attendee.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaAttendeePublic.parse(attendee); - if (method === "PATCH" && safeQuery.success && safeBody.success) { - await prisma.attendee - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((attendee) => { - res.status(200).json({ data: attendee }); - }) - .catch((error) => { - res - .status(404) - .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, + error, }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only PATCH Method allowed for updating attendees" }); } -export default withValidQueryIdTransformParseInt(withValidAttendee(editAttendee)); +export default withMiddleware("HTTP_PATCH")( + withValidQueryIdTransformParseInt(withValidAttendee(editAttendee)) +); diff --git a/pages/api/attendees/[id]/index.ts b/pages/api/attendees/[id]/index.ts index 6fc30b78f2..6fe39d540c 100644 --- a/pages/api/attendees/[id]/index.ts +++ b/pages/api/attendees/[id]/index.ts @@ -1,30 +1,51 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Attendee } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { AttendeeResponse } from "@lib/types"; +import { schemaAttendeePublic } from "@lib/validations/attendee"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: Attendee; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/attendees/{id}: + * get: + * summary: Get a attendee by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the attendee to get + * tags: + * - attendees + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Attendee was not found + */ +export async function attendeeById(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); -export async function attendee(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); + const attendee = await prisma.attendee.findUnique({ where: { id: safe.data.id } }); + const data = schemaAttendeePublic.parse(attendee); - if (method === "GET" && safe.success) { - const attendee = await prisma.attendee.findUnique({ where: { id: safe.data.id } }); - - if (attendee) res.status(200).json({ data: attendee }); - if (!attendee) res.status(404).json({ message: "Event type not found" }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only GET Method allowed" }); + if (attendee) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "Attendee was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(attendee); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(attendeeById)); diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index c5ac16eb09..4c94c6ed7d 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -1,19 +1,37 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Attendee } from "@calcom/prisma/client"; -type ResponseData = { - data?: Attendee[]; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { AttendeesResponse } from "@lib/types"; +import { schemaAttendeePublic } from "@lib/validations/attendee"; -export default async function attendee(req: NextApiRequest, res: NextApiResponse) { - try { - const data = await prisma.attendee.findMany(); - res.status(200).json({ data }); - } catch (error) { - // FIXME: Add zod for validation/error handling - res.status(400).json({ error: error }); - } +/** + * @swagger + * /api/attendees: + * get: + * summary: Get all attendees + * tags: + * - attendees + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No attendees were found + */ +async function allAttendees(_: NextApiRequest, res: NextApiResponse) { + const attendees = await prisma.attendee.findMany(); + const data = attendees.map((attendee) => schemaAttendeePublic.parse(attendee)); + + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "No Attendees were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allAttendees); diff --git a/pages/api/attendees/new.ts b/pages/api/attendees/new.ts index f01d7a3dbe..7825755b0e 100644 --- a/pages/api/attendees/new.ts +++ b/pages/api/attendees/new.ts @@ -1,27 +1,48 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Attendee } from "@calcom/prisma/client"; -import { schemaAttendee, withValidAttendee } from "@lib/validations/attendee"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { AttendeeResponse } from "@lib/types"; +import { schemaAttendeeBodyParams, schemaAttendeePublic, withValidAttendee } from "@lib/validations/attendee"; -type ResponseData = { - data?: Attendee; - message?: string; - error?: string; -}; +/** + * @swagger + * /api/attendees/new: + * post: + * summary: Creates a new attendee + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/Attendee' + * tags: + * - attendees + * responses: + * 201: + * description: OK, attendee created + * model: Attendee + * 400: + * description: Bad request. Attendee body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createAttendee(req: NextApiRequest, res: NextApiResponse) { + const safe = schemaAttendeeBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createAttendee(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - const safe = schemaAttendee.safeParse(body); + const attendee = await prisma.attendee.create({ data: safe.data }); + const data = schemaAttendeePublic.parse(attendee); - if (method === "POST" && safe.success) { - await prisma.attendee - .create({ data: safe.data }) - .then((attendee) => res.status(201).json({ data: attendee })) - .catch((error) => res.status(400).json({ message: "Could not create attendee type", error: error })); - // Reject any other HTTP method than POST - } else res.status(405).json({ error: "Only POST Method allowed" }); + if (data) res.status(201).json({ data, message: "Attendee created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new attendee", + error, + }); } -export default withValidAttendee(createAttendee); +export default withMiddleware("HTTP_POST")(withValidAttendee(createAttendee)); diff --git a/pages/api/availabilities/[id]/delete.ts b/pages/api/availabilities/[id]/delete.ts index b59534eb08..1601b014a1 100644 --- a/pages/api/availabilities/[id]/delete.ts +++ b/pages/api/availabilities/[id]/delete.ts @@ -2,28 +2,49 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BaseResponse } from "@lib/types"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/availabilites/{id}/delete: + * delete: + * summary: Remove an existing availability + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the availability to delete + * tags: + * - availabilites + * responses: + * 201: + * description: OK, availability removed successfuly + * model: Availability + * 400: + * description: Bad request. Availability id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteAvailability(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query", safe.error); -export async function availability(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const availability = await prisma.availability.delete({ where: { id: safe.data.id } }); - // We only remove the availability type from the database if there's an existing resource. - if (availability) - res.status(200).json({ message: `availability with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.availability.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only DELETE Method allowed" }); + const data = await prisma.availability.delete({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ message: `Availability with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `Availability with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withValidQueryIdTransformParseInt(availability); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteAvailability)); diff --git a/pages/api/availabilities/[id]/edit.ts b/pages/api/availabilities/[id]/edit.ts index c12de7ddc2..e530090a43 100644 --- a/pages/api/availabilities/[id]/edit.ts +++ b/pages/api/availabilities/[id]/edit.ts @@ -1,41 +1,62 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Availability } from "@calcom/prisma/client"; -import { schemaAvailability, withValidAvailability } from "@lib/validations/availability"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { AvailabilityResponse } from "@lib/types"; +import { + schemaAvailabilityBodyParams, + schemaAvailabilityPublic, + withValidAvailability, +} from "@lib/validations/availability"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: Availability; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/availabilites/{id}/edit: + * patch: + * summary: Edit an existing availability + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the availability to edit + * tags: + * - availabilites + * responses: + * 201: + * description: OK, availability edited successfuly + * model: Availability + * 400: + * description: Bad request. Availability body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editAvailability(req: NextApiRequest, res: NextApiResponse) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaAvailabilityBodyParams.safeParse(req.body); -export async function editAvailability(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaAvailability.safeParse(body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const availability = await prisma.availability.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaAvailabilityPublic.parse(availability); - if (method === "PATCH" && safeQuery.success && safeBody.success) { - await prisma.availability - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((availability) => { - res.status(200).json({ data: availability }); - }) - .catch((error) => { - res - .status(404) - .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, + error, }); - // Reject any other HTTP method than PATCH - } else res.status(405).json({ message: "Only PATCH Method allowed for updating availabilities" }); } -export default withValidQueryIdTransformParseInt(withValidAvailability(editAvailability)); +export default withMiddleware("HTTP_PATCH")( + withValidQueryIdTransformParseInt(withValidAvailability(editAvailability)) +); diff --git a/pages/api/availabilities/[id]/index.ts b/pages/api/availabilities/[id]/index.ts index 8e2573df69..22e160e436 100644 --- a/pages/api/availabilities/[id]/index.ts +++ b/pages/api/availabilities/[id]/index.ts @@ -1,30 +1,51 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Availability } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { AvailabilityResponse } from "@lib/types"; +import { schemaAvailabilityPublic } from "@lib/validations/availability"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: Availability; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/availabilites/{id}: + * get: + * summary: Get a availability by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the availability to get + * tags: + * - availabilites + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Availability was not found + */ +export async function availabilityById(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); -export async function availability(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); + const availability = await prisma.availability.findUnique({ where: { id: safe.data.id } }); + const data = schemaAvailabilityPublic.parse(availability); - if (method === "GET" && safe.success) { - const availability = await prisma.availability.findUnique({ where: { id: safe.data.id } }); - - if (availability) res.status(200).json({ data: availability }); - if (!availability) res.status(404).json({ message: "Event type not found" }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only GET Method allowed" }); + if (availability) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "Availability was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(availability); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(availabilityById)); diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index 95cde57385..d3a2168565 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -1,19 +1,37 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Availability } from "@calcom/prisma/client"; -type ResponseData = { - data?: Availability[]; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { AvailabilitysResponse } from "@lib/types"; +import { schemaAvailabilityPublic } from "@lib/validations/availability"; -export default async function availability(req: NextApiRequest, res: NextApiResponse) { - try { - const data = await prisma.availability.findMany(); - res.status(200).json({ data }); - } catch (error) { - // FIXME: Add zod for validation/error handling - res.status(400).json({ error: error }); - } +/** + * @swagger + * /api/availabilites: + * get: + * summary: Get all availabilites + * tags: + * - availabilites + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No availabilites were found + */ +async function allAvailabilitys(_: NextApiRequest, res: NextApiResponse) { + const availabilites = await prisma.availability.findMany(); + const data = availabilites.map((availability) => schemaAvailabilityPublic.parse(availability)); + + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "No Availabilitys were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allAvailabilitys); diff --git a/pages/api/availabilities/new.ts b/pages/api/availabilities/new.ts index 5df3ea02e2..2e3587e551 100644 --- a/pages/api/availabilities/new.ts +++ b/pages/api/availabilities/new.ts @@ -1,32 +1,52 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Availability } from "@calcom/prisma/client"; -import { schemaAvailability, withValidAvailability } from "@lib/validations/availability"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { AvailabilityResponse } from "@lib/types"; +import { + schemaAvailabilityBodyParams, + schemaAvailabilityPublic, + withValidAvailability, +} from "@lib/validations/availability"; -type ResponseData = { - data?: Availability; - message?: string; - error?: string; -}; +/** + * @swagger + * /api/availabilites/new: + * post: + * summary: Creates a new availability + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/Availability' + * tags: + * - availabilites + * responses: + * 201: + * description: OK, availability created + * model: Availability + * 400: + * description: Bad request. Availability body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createAvailability(req: NextApiRequest, res: NextApiResponse) { + const safe = schemaAvailabilityBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createAvailability(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - if (method === "POST") { - const safe = schemaAvailability.safeParse(body); - if (safe.success && safe.data) { - await prisma.availability - .create({ data: safe.data }) - .then((availability) => res.status(201).json({ data: availability })) - .catch((error) => - res.status(400).json({ message: "Could not create availability type", error: error }) - ); - } - } else { - // Reject any other HTTP method than POST - res.status(405).json({ error: "Only POST Method allowed" }); - } + const availability = await prisma.availability.create({ data: safe.data }); + const data = schemaAvailabilityPublic.parse(availability); + + if (data) res.status(201).json({ data, message: "Availability created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new availability", + error, + }); } -export default withValidAvailability(createAvailability); +export default withMiddleware("HTTP_POST")(withValidAvailability(createAvailability)); diff --git a/pages/api/event-types/[id]/delete.ts b/pages/api/event-types/[id]/delete.ts index 4ac7f612dc..ce83548f73 100644 --- a/pages/api/event-types/[id]/delete.ts +++ b/pages/api/event-types/[id]/delete.ts @@ -11,9 +11,18 @@ import { /** * @swagger - * /api/eventTypes/:id/delete: + * /api/eventTypes/{id}/delete: * delete: * summary: Remove an existing eventType + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the eventType to delete + * tags: + * - eventTypes * responses: * 201: * description: OK, eventType removed successfuly diff --git a/pages/api/event-types/[id]/edit.ts b/pages/api/event-types/[id]/edit.ts index 08458274e3..bb181742c0 100644 --- a/pages/api/event-types/[id]/edit.ts +++ b/pages/api/event-types/[id]/edit.ts @@ -16,9 +16,18 @@ import { /** * @swagger - * /api/eventTypes/:id/edit: + * /api/eventTypes/{id}/edit: * patch: * summary: Edits an existing eventType + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the eventType to delete + * tags: + * - eventTypes * responses: * 201: * description: OK, eventType edited successfuly diff --git a/pages/api/event-types/[id]/index.ts b/pages/api/event-types/[id]/index.ts index 9a7236577b..4e64863965 100644 --- a/pages/api/event-types/[id]/index.ts +++ b/pages/api/event-types/[id]/index.ts @@ -21,7 +21,7 @@ import { * schema: * type: integer * required: true - * description: Numeric ID of the event type to get + * description: Numeric ID of the eventType to get * responses: * 200: * description: OK diff --git a/pages/api/users/[id]/edit.ts b/pages/api/users/[id]/edit.ts index 3f37b36d77..4d39bb80ce 100644 --- a/pages/api/users/[id]/edit.ts +++ b/pages/api/users/[id]/edit.ts @@ -12,9 +12,16 @@ import { schemaUserBodyParams, schemaUserPublic, withValidUser } from "@lib/vali /** * @swagger - * /api/users/:id/edit: + * /api/users/{id}/edit: * patch: - * summary: Edits an existing user + * summary: Edit an existing user + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the user to edit * tags: * - users * responses: From 1c19032884c768ec37e4d8b4814a0fd7cedb819b Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 1 Apr 2022 23:03:03 +0200 Subject: [PATCH 052/658] chore: bring up to date booking references, bookings, and credentials --- lib/types.ts | 1 + lib/validations/booking-reference.ts | 12 +++- lib/validations/booking.ts | 4 +- lib/validations/credential.ts | 14 +++- lib/validations/shared/jsonSchema.ts | 9 +++ pages/api/booking-references/[id]/delete.ts | 56 ++++++++++----- pages/api/booking-references/[id]/edit.ts | 77 ++++++++++++++------- pages/api/booking-references/[id]/index.ts | 57 ++++++++++----- pages/api/booking-references/index.ts | 40 ++++++++--- pages/api/booking-references/new.ts | 64 +++++++++++------ pages/api/bookings/[id]/delete.ts | 55 ++++++++++----- pages/api/bookings/[id]/edit.ts | 75 +++++++++++--------- pages/api/bookings/[id]/index.ts | 57 ++++++++++----- pages/api/bookings/index.ts | 44 ++++++++---- pages/api/bookings/new.ts | 3 +- pages/api/credentials/[id]/delete.ts | 55 ++++++++++----- pages/api/credentials/[id]/edit.ts | 74 +++++++++++++------- pages/api/credentials/[id]/index.ts | 54 ++++++++++----- pages/api/credentials/index.ts | 38 +++++++--- pages/api/credentials/new.ts | 62 ++++++++++++----- 20 files changed, 593 insertions(+), 258 deletions(-) create mode 100644 lib/validations/shared/jsonSchema.ts diff --git a/lib/types.ts b/lib/types.ts index cec3f65c0b..806f84b18f 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -2,6 +2,7 @@ import { User, ApiKey, Team, + Credential, SelectedCalendar, EventType, Attendee, diff --git a/lib/validations/booking-reference.ts b/lib/validations/booking-reference.ts index c73be296bc..75a7d95f0c 100644 --- a/lib/validations/booking-reference.ts +++ b/lib/validations/booking-reference.ts @@ -1,11 +1,21 @@ import { withValidation } from "next-validations"; +import { z } from "zod"; import { _BookingReferenceModel as BookingReference } from "@calcom/prisma/zod"; -export const schemaBookingReferenceBodyParams = BookingReference.omit({ id: true }); +export const schemaBookingReferenceBaseBodyParams = BookingReference.omit({ id: true }).partial(); export const schemaBookingReferencePublic = BookingReference.omit({}); +const schemaBookingReferenceRequiredParams = z.object({ + type: z.string(), + uid: z.string(), +}); + +export const schemaBookingReferenceBodyParams = schemaBookingReferenceBaseBodyParams.merge( + schemaBookingReferenceRequiredParams +); + export const withValidBookingReference = withValidation({ schema: schemaBookingReferenceBodyParams, type: "Zod", diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index df5293e053..77eca1d156 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -3,10 +3,8 @@ import { z } from "zod"; import { _BookingModel as Booking } from "@calcom/prisma/zod"; -// Here we remove any parameters that are not needed for the API with omit. const schemaBookingBaseBodyParams = Booking.omit({ id: true }).partial(); -// Here we redeclare the required ones after removing the ones we don't need. -// and making the rest optional with .partial() + const schemaBookingRequiredParams = z.object({ uid: z.string(), title: z.string(), diff --git a/lib/validations/credential.ts b/lib/validations/credential.ts index 001e4870f6..9397ef2577 100644 --- a/lib/validations/credential.ts +++ b/lib/validations/credential.ts @@ -1,8 +1,20 @@ import { withValidation } from "next-validations"; +import { z } from "zod"; import { _CredentialModel as Credential } from "@calcom/prisma/zod"; -export const schemaCredentialBodyParams = Credential.omit({ id: true }); +import { jsonSchema } from "./shared/jsonSchema"; + +const schemaCredentialBaseBodyParams = Credential.omit({ id: true, userId: true }).partial(); + +const schemaCredentialRequiredParams = z.object({ + type: z.string(), + key: jsonSchema, +}); + +export const schemaCredentialBodyParams = schemaCredentialBaseBodyParams.merge( + schemaCredentialRequiredParams +); export const schemaCredentialPublic = Credential.omit({}); diff --git a/lib/validations/shared/jsonSchema.ts b/lib/validations/shared/jsonSchema.ts new file mode 100644 index 0000000000..bfc7ae1f2b --- /dev/null +++ b/lib/validations/shared/jsonSchema.ts @@ -0,0 +1,9 @@ +import { z } from "zod"; + +// Helper schema for JSON fields +type Literal = boolean | number | string; +type Json = Literal | { [key: string]: Json } | Json[]; +const literalSchema = z.union([z.string(), z.number(), z.boolean()]); +export const jsonSchema: z.ZodSchema = z.lazy(() => + z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)]) +); diff --git a/pages/api/booking-references/[id]/delete.ts b/pages/api/booking-references/[id]/delete.ts index 6f7685854f..0a49d82d21 100644 --- a/pages/api/booking-references/[id]/delete.ts +++ b/pages/api/booking-references/[id]/delete.ts @@ -2,28 +2,50 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BaseResponse } from "@lib/types"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/booking-references/{id}/delete: + * delete: + * summary: Remove an existing bookingReference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the bookingReference to delete + * tags: + * - bookingReferences + * responses: + * 201: + * description: OK, bookingReference removed successfuly + * model: BookingReference + * 400: + * description: Bad request. BookingReference id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteBookingReference(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query", safe.error); -export async function deleteBookingReference(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const bookingReference = await prisma.bookingReference.delete({ where: { id: safe.data.id } }); - // We only remove the bookingReference type from the database if there's an existing resource. - if (bookingReference) - res.status(200).json({ message: `bookingReference with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.bookingReference.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only DELETE Method allowed" }); + const data = await prisma.bookingReference.delete({ where: { id: safe.data.id } }); + + if (data) + res.status(200).json({ message: `BookingReference with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `BookingReference with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withValidQueryIdTransformParseInt(deleteBookingReference); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteBookingReference)); diff --git a/pages/api/booking-references/[id]/edit.ts b/pages/api/booking-references/[id]/edit.ts index b1ecfcee35..3d05537514 100644 --- a/pages/api/booking-references/[id]/edit.ts +++ b/pages/api/booking-references/[id]/edit.ts @@ -1,38 +1,65 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { BookingReference } from "@calcom/prisma/client"; -import { schemaBookingReference, withValidBookingReference } from "@lib/validations/booking-reference"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BookingReferenceResponse } from "@lib/types"; +import { + schemaBookingReferenceBodyParams, + schemaBookingReferencePublic, + withValidBookingReference, +} from "@lib/validations/booking-reference"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: BookingReference; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/booking-references/{id}/edit: + * patch: + * summary: Edit an existing bookingReference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the bookingReference to edit + * tags: + * - bookingReferences + * responses: + * 201: + * description: OK, bookingReference edited successfuly + * model: BookingReference + * 400: + * description: Bad request. BookingReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editBookingReference( + req: NextApiRequest, + res: NextApiResponse +) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaBookingReferenceBodyParams.safeParse(req.body); -export async function editBookingReference(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaBookingReference.safeParse(body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const bookingReference = await prisma.bookingReference.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaBookingReferencePublic.parse(bookingReference); - if (method === "PATCH" && safeQuery.success && safeBody.success) { - const data = await prisma.bookingReference.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - if (data) res.status(200).json({ data }); - else - res - .status(404) - .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated` }); - - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only PATCH Method allowed for updating bookingReferences" }); + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, + error, + }); } -export default withValidQueryIdTransformParseInt(withValidBookingReference(editBookingReference)); +export default withMiddleware("HTTP_PATCH")( + withValidQueryIdTransformParseInt(withValidBookingReference(editBookingReference)) +); diff --git a/pages/api/booking-references/[id]/index.ts b/pages/api/booking-references/[id]/index.ts index 4e8483b797..ee6f7c8e84 100644 --- a/pages/api/booking-references/[id]/index.ts +++ b/pages/api/booking-references/[id]/index.ts @@ -1,29 +1,54 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { BookingReference } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BookingReferenceResponse } from "@lib/types"; +import { schemaBookingReferencePublic } from "@lib/validations/booking-reference"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: BookingReference; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/booking-references/{id}: + * get: + * summary: Get a bookingReference by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the bookingReference to get + * tags: + * - bookingReferences + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: BookingReference was not found + */ +export async function bookingReferenceById( + req: NextApiRequest, + res: NextApiResponse +) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); -export async function bookingReference(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "GET" && safe.success) { - const data = await prisma.bookingReference.findUnique({ where: { id: safe.data.id } }); + const bookingReference = await prisma.bookingReference.findUnique({ where: { id: safe.data.id } }); + const data = schemaBookingReferencePublic.parse(bookingReference); - if (data) res.status(200).json({ data }); - else res.status(404).json({ message: "Event type not found" }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only GET Method allowed" }); + if (bookingReference) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "BookingReference was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(bookingReference); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(bookingReferenceById)); diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index f0244da6bb..c1c4afc9dc 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -1,15 +1,39 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { BookingReference } from "@calcom/prisma/client"; -type ResponseData = { - data?: BookingReference[]; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { BookingReferencesResponse } from "@lib/types"; +import { schemaBookingReferencePublic } from "@lib/validations/booking-reference"; + +/** + * @swagger + * /api/booking-references: + * get: + * summary: Get all bookingReferences + * tags: + * - bookingReferences + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No bookingReferences were found + */ +async function allBookingReferences(_: NextApiRequest, res: NextApiResponse) { + const bookingReferences = await prisma.bookingReference.findMany(); + const data = bookingReferences.map((bookingReference) => + schemaBookingReferencePublic.parse(bookingReference) + ); -export default async function bookingReference(req: NextApiRequest, res: NextApiResponse) { - const data = await prisma.bookingReference.findMany(); if (data) res.status(200).json({ data }); - else res.status(400).json({ error: "No data found" }); + else + (error: Error) => + res.status(404).json({ + message: "No BookingReferences were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allBookingReferences); diff --git a/pages/api/booking-references/new.ts b/pages/api/booking-references/new.ts index 319e80404e..5430206cde 100644 --- a/pages/api/booking-references/new.ts +++ b/pages/api/booking-references/new.ts @@ -1,28 +1,52 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { BookingReference } from "@calcom/prisma/client"; -import { schemaBookingReference, withValidBookingReference } from "@lib/validations/booking-reference"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BookingReferenceResponse } from "@lib/types"; +import { + schemaBookingReferenceBodyParams, + schemaBookingReferencePublic, + withValidBookingReference, +} from "@lib/validations/booking-reference"; -type ResponseData = { - data?: BookingReference; - message?: string; - error?: string; -}; +/** + * @swagger + * /api/booking-references/new: + * post: + * summary: Creates a new bookingReference + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/BookingReference' + * tags: + * - bookingReferences + * responses: + * 201: + * description: OK, bookingReference created + * model: BookingReference + * 400: + * description: Bad request. BookingReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createBookingReference(req: NextApiRequest, res: NextApiResponse) { + const safe = schemaBookingReferenceBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createBookingReference(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - const safe = schemaBookingReference.safeParse(body); - if (method === "POST" && safe.success) { - await prisma.bookingReference - .create({ data: safe.data }) - .then((data) => res.status(201).json({ data })) - .catch((error) => - res.status(400).json({ message: "Could not create bookingReference type", error: error }) - ); - // Reject any other HTTP method than POST - } else res.status(405).json({ error: "Only POST Method allowed" }); + const bookingReference = await prisma.bookingReference.create({ data: safe.data }); + const data = schemaBookingReferencePublic.parse(bookingReference); + + if (data) res.status(201).json({ data, message: "BookingReference created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new bookingReference", + error, + }); } -export default withValidBookingReference(createBookingReference); +export default withMiddleware("HTTP_POST")(withValidBookingReference(createBookingReference)); diff --git a/pages/api/bookings/[id]/delete.ts b/pages/api/bookings/[id]/delete.ts index a2dad90c7e..5d6e58d656 100644 --- a/pages/api/bookings/[id]/delete.ts +++ b/pages/api/bookings/[id]/delete.ts @@ -2,28 +2,49 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BaseResponse } from "@lib/types"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/bookings/{id}/delete: + * delete: + * summary: Remove an existing booking + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the booking to delete + * tags: + * - bookings + * responses: + * 201: + * description: OK, booking removed successfuly + * model: Booking + * 400: + * description: Bad request. Booking id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteBooking(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query", safe.error); -export async function deleteBooking(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const booking = await prisma.booking.delete({ where: { id: safe.data.id } }); - // We only remove the booking type from the database if there's an existing resource. - if (booking) res.status(200).json({ message: `booking with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.booking.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` }); - // Reject any other HTTP method than POST - } else - res.status(405).json({ message: "Only DELETE Method allowed in /availabilities/[id]/delete endpoint" }); + const data = await prisma.booking.delete({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ message: `Booking with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `Booking with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withValidQueryIdTransformParseInt(deleteBooking); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteBooking)); diff --git a/pages/api/bookings/[id]/edit.ts b/pages/api/bookings/[id]/edit.ts index d74a512cd9..3e12bdaa86 100644 --- a/pages/api/bookings/[id]/edit.ts +++ b/pages/api/bookings/[id]/edit.ts @@ -1,45 +1,56 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Booking } from "@calcom/prisma/client"; -import { schemaBooking, withValidBooking } from "@lib/validations/booking"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BookingResponse } from "@lib/types"; +import { schemaBookingBodyParams, schemaBookingPublic, withValidBooking } from "@lib/validations/booking"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: Booking; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/bookings/{id}/edit: + * patch: + * summary: Edit an existing booking + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the booking to edit + * tags: + * - bookings + * responses: + * 201: + * description: OK, booking edited successfuly + * model: Booking + * 400: + * description: Bad request. Booking body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editBooking(req: NextApiRequest, res: NextApiResponse) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaBookingBodyParams.safeParse(req.body); -export async function editBooking(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaBooking.safeParse(body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const booking = await prisma.booking.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaBookingPublic.parse(booking); - if (method === "PATCH") { - if (safeQuery.success && safeBody.success) { - await prisma.booking - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((booking) => { - res.status(200).json({ data: booking }); - }) - .catch((error) => { - res - .status(404) - .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); - }); - } - } else { - // Reject any other HTTP method than POST - res.status(405).json({ message: "Only PATCH Method allowed for updating bookings" }); - } + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, + error, + }); } -export default withValidQueryIdTransformParseInt(withValidBooking(editBooking)); +export default withMiddleware("HTTP_PATCH")(withValidQueryIdTransformParseInt(withValidBooking(editBooking))); diff --git a/pages/api/bookings/[id]/index.ts b/pages/api/bookings/[id]/index.ts index 8311dea842..fab8940978 100644 --- a/pages/api/bookings/[id]/index.ts +++ b/pages/api/bookings/[id]/index.ts @@ -1,32 +1,51 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Booking } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BookingResponse } from "@lib/types"; +import { schemaBookingPublic } from "@lib/validations/booking"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: Booking; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/bookings/{id}: + * get: + * summary: Get a booking by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the booking to get + * tags: + * - bookings + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Booking was not found + */ +export async function bookingById(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); -export async function booking(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); + const booking = await prisma.booking.findUnique({ where: { id: safe.data.id } }); + const data = schemaBookingPublic.parse(booking); - if (method === "GET" && safe.success) { - const booking = await prisma.booking.findUnique({ where: { id: safe.data.id } }); - - if (booking) res.status(200).json({ data: booking }); - if (!booking) res.status(404).json({ message: "Event type not found" }); - } else { - // Reject any other HTTP method than POST - res.status(405).json({ message: "Only GET Method allowed" }); - } + if (booking) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "Booking was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(booking); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(bookingById)); diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index d99dc318bd..f2d724071c 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -1,19 +1,37 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Booking } from "@calcom/prisma/client"; -type ResponseData = { - data?: Booking[]; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { BookingsResponse } from "@lib/types"; +import { schemaBookingPublic } from "@lib/validations/booking"; -export default async function booking(req: NextApiRequest, res: NextApiResponse) { - try { - const data = await prisma.booking.findMany(); - res.status(200).json({ data }); - } catch (error) { - // FIXME: Add zod for validation/error handling - res.status(400).json({ error: error }); - } +/** + * @swagger + * /api/bookings: + * get: + * summary: Get all bookings + * tags: + * - bookings + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No bookings were found + */ +async function allBookings(_: NextApiRequest, res: NextApiResponse) { + const bookings = await prisma.booking.findMany(); + const data = bookings.map((booking) => schemaBookingPublic.parse(booking)); + + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "No Bookings were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allBookings); diff --git a/pages/api/bookings/new.ts b/pages/api/bookings/new.ts index fcc5f89efc..4e62b0e531 100644 --- a/pages/api/bookings/new.ts +++ b/pages/api/bookings/new.ts @@ -2,7 +2,6 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { withCost } from "@lib/helpers/withCost"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { BookingResponse } from "@lib/types"; import { schemaBookingBodyParams, schemaBookingPublic, withValidBooking } from "@lib/validations/booking"; @@ -46,4 +45,4 @@ async function createBooking(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query", safe.error); -export async function deleteCredential(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const credential = await prisma.credential.delete({ where: { id: safe.data.id } }); - // We only remove the credential type from the database if there's an existing resource. - if (credential) - res.status(200).json({ message: `credential with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.credential.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only DELETE Method allowed" }); + const data = await prisma.credential.delete({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ message: `Credential with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `Credential with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withValidQueryIdTransformParseInt(deleteCredential); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteCredential)); diff --git a/pages/api/credentials/[id]/edit.ts b/pages/api/credentials/[id]/edit.ts index b34be12932..5febf03067 100644 --- a/pages/api/credentials/[id]/edit.ts +++ b/pages/api/credentials/[id]/edit.ts @@ -1,38 +1,62 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Credential } from "@calcom/prisma/client"; -import { schemaCredential, withValidCredential } from "@lib/validations/credential"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { CredentialResponse } from "@lib/types"; +import { + schemaCredentialBodyParams, + schemaCredentialPublic, + withValidCredential, +} from "@lib/validations/credential"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: Credential; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/credentials/{id}/edit: + * patch: + * summary: Edit an existing credential + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the credential to edit + * tags: + * - credentials + * responses: + * 201: + * description: OK, credential edited successfuly + * model: Credential + * 400: + * description: Bad request. Credential body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editCredential(req: NextApiRequest, res: NextApiResponse) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaCredentialBodyParams.safeParse(req.body); -export async function editCredential(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaCredential.safeParse(body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const credential = await prisma.credential.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaCredentialPublic.parse(credential); - if (method === "PATCH" && safeQuery.success && safeBody.success) { - const data = await prisma.credential.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - if (data) res.status(200).json({ data }); - else - res - .status(404) - .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); - - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only PATCH Method allowed for updating credentials" }); + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, + error, + }); } -export default withValidQueryIdTransformParseInt(withValidCredential(editCredential)); +export default withMiddleware("HTTP_PATCH")( + withValidQueryIdTransformParseInt(withValidCredential(editCredential)) +); diff --git a/pages/api/credentials/[id]/index.ts b/pages/api/credentials/[id]/index.ts index 18810aa488..9686700a17 100644 --- a/pages/api/credentials/[id]/index.ts +++ b/pages/api/credentials/[id]/index.ts @@ -1,29 +1,51 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Credential } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { CredentialResponse } from "@lib/types"; +import { schemaCredentialPublic } from "@lib/validations/credential"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: Credential; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/credentials/{id}: + * get: + * summary: Get a credential by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the credential to get + * tags: + * - credentials + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Credential was not found + */ +export async function credentialById(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); -export async function credential(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "GET" && safe.success) { - const data = await prisma.credential.findUnique({ where: { id: safe.data.id } }); + const credential = await prisma.credential.findUnique({ where: { id: safe.data.id } }); + const data = schemaCredentialPublic.parse(credential); - if (data) res.status(200).json({ data }); - else res.status(404).json({ message: "Event type not found" }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only GET Method allowed" }); + if (credential) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "Credential was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(credential); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(credentialById)); diff --git a/pages/api/credentials/index.ts b/pages/api/credentials/index.ts index 5810b80e63..1ef98a95df 100644 --- a/pages/api/credentials/index.ts +++ b/pages/api/credentials/index.ts @@ -1,15 +1,37 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Credential } from "@calcom/prisma/client"; -type ResponseData = { - data?: Credential[]; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { CredentialsResponse } from "@lib/types"; +import { schemaCredentialPublic } from "@lib/validations/credential"; + +/** + * @swagger + * /api/credentials: + * get: + * summary: Get all credentials + * tags: + * - credentials + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No credentials were found + */ +async function allCredentials(_: NextApiRequest, res: NextApiResponse) { + const credentials = await prisma.credential.findMany(); + const data = credentials.map((credential) => schemaCredentialPublic.parse(credential)); -export default async function credential(req: NextApiRequest, res: NextApiResponse) { - const data = await prisma.credential.findMany(); if (data) res.status(200).json({ data }); - else res.status(400).json({ error: "No data found" }); + else + (error: Error) => + res.status(404).json({ + message: "No Credentials were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allCredentials); diff --git a/pages/api/credentials/new.ts b/pages/api/credentials/new.ts index b823a1f1b0..265f17d3cd 100644 --- a/pages/api/credentials/new.ts +++ b/pages/api/credentials/new.ts @@ -1,26 +1,52 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { Credential } from "@calcom/prisma/client"; -import { schemaCredential, withValidCredential } from "@lib/validations/credential"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { CredentialResponse } from "@lib/types"; +import { + schemaCredentialBodyParams, + schemaCredentialPublic, + withValidCredential, +} from "@lib/validations/credential"; -type ResponseData = { - data?: Credential; - message?: string; - error?: string; -}; +/** + * @swagger + * /api/credentials/new: + * post: + * summary: Creates a new credential + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/Credential' + * tags: + * - credentials + * responses: + * 201: + * description: OK, credential created + * model: Credential + * 400: + * description: Bad request. Credential body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createCredential(req: NextApiRequest, res: NextApiResponse) { + const safe = schemaCredentialBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createCredential(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - const safe = schemaCredential.safeParse(body); - if (method === "POST" && safe.success) { - await prisma.credential - .create({ data: safe.data }) - .then((data) => res.status(201).json({ data })) - .catch((error) => res.status(400).json({ message: "Could not create credential type", error: error })); - // Reject any other HTTP method than POST - } else res.status(405).json({ error: "Only POST Method allowed" }); + const credential = await prisma.credential.create({ data: safe.data }); + const data = schemaCredentialPublic.parse(credential); + + if (data) res.status(201).json({ data, message: "Credential created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new credential", + error, + }); } -export default withValidCredential(createCredential); +export default withMiddleware("HTTP_POST")(withValidCredential(createCredential)); From 9f4a62e2ef04945e0b0a102fcc8eac27aeb2e20c Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 2 Apr 2022 01:55:41 +0200 Subject: [PATCH 053/658] feat: yarn build no errors --- lib/helpers/withCost.ts | 2 - lib/types.ts | 9 +++ lib/validations/event-type-custom-input.ts | 29 ++++++++ lib/validations/schedule.ts | 12 ++- lib/validations/selected-calendar.ts | 24 +++++- .../api/daily-event-references/[id]/delete.ts | 55 +++++++++----- pages/api/daily-event-references/[id]/edit.ts | 74 ++++++++++++------- .../api/daily-event-references/[id]/index.ts | 57 ++++++++++---- pages/api/daily-event-references/index.ts | 43 +++++++++-- pages/api/daily-event-references/new.ts | 64 +++++++++++----- .../api/destination-calendars/[id]/delete.ts | 56 +++++++++----- pages/api/destination-calendars/[id]/edit.ts | 74 ++++++++++++------- pages/api/destination-calendars/[id]/index.ts | 57 ++++++++++---- pages/api/destination-calendars/index.ts | 43 +++++++++-- pages/api/destination-calendars/new.ts | 64 +++++++++++----- .../event-type-custom-inputs/[id]/delete.ts | 56 +++++++++----- .../api/event-type-custom-inputs/[id]/edit.ts | 41 ---------- .../[id]/edit.ts.fixme | 65 ++++++++++++++++ .../event-type-custom-inputs/[id]/index.ts | 57 ++++++++++---- pages/api/event-type-custom-inputs/index.ts | 43 +++++++++-- pages/api/event-type-custom-inputs/new.ts | 31 -------- .../api/event-type-custom-inputs/new.ts.fixme | 55 ++++++++++++++ pages/api/selected-calendars/[id]/delete.ts | 37 +++++++--- pages/api/selected-calendars/[id]/edit.ts | 24 +++--- pages/api/selected-calendars/[id]/index.ts | 36 ++++++--- 25 files changed, 786 insertions(+), 322 deletions(-) create mode 100644 lib/validations/event-type-custom-input.ts delete mode 100644 pages/api/event-type-custom-inputs/[id]/edit.ts create mode 100644 pages/api/event-type-custom-inputs/[id]/edit.ts.fixme delete mode 100644 pages/api/event-type-custom-inputs/new.ts create mode 100644 pages/api/event-type-custom-inputs/new.ts.fixme diff --git a/lib/helpers/withCost.ts b/lib/helpers/withCost.ts index 55f8e06ee5..d462536956 100644 --- a/lib/helpers/withCost.ts +++ b/lib/helpers/withCost.ts @@ -3,8 +3,6 @@ // Initially to test out 0,5 cent per booking via API call // withCost(5)(endpoint) // Should add a charge of 0.5 cent per booking to the subscription of the user making the request -// Should be called in the middleware of the e -// import { NextMiddleware } from "next-api-middleware"; export const withCost = (priceInCents: number): NextMiddleware => { diff --git a/lib/types.ts b/lib/types.ts index 806f84b18f..d0c33538c3 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -5,6 +5,7 @@ import { Credential, SelectedCalendar, EventType, + EventTypeCustomInput, Attendee, Availability, BookingReference, @@ -120,6 +121,14 @@ export type MembershipsResponse = BaseResponse & { data?: Partial[]; }; +// EventTypeCustomInput +export type EventTypeCustomInputResponse = BaseResponse & { + data?: Partial; +}; +export type EventTypeCustomInputsResponse = BaseResponse & { + data?: Partial[]; +}; + // EventType export type EventTypeResponse = BaseResponse & { data?: Partial; diff --git a/lib/validations/event-type-custom-input.ts b/lib/validations/event-type-custom-input.ts new file mode 100644 index 0000000000..4898af83bd --- /dev/null +++ b/lib/validations/event-type-custom-input.ts @@ -0,0 +1,29 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +import { EventTypeModel, _EventTypeCustomInputModel as EventTypeCustomInput } from "@calcom/prisma/zod"; + +export const schemaEventTypeCustomInputBaseBodyParams = EventTypeCustomInput.omit({ + id: true, + eventTypeId: true, +}).partial(); + +export const schemaEventTypeCustomInputPublic = EventTypeCustomInput.omit({}); + +const schemaEventTypeCustomInputRequiredParams = z.object({ + label: z.string(), + // uid: z.string(), + eventType: EventTypeModel.optional(), + + // eventType: z.instanceof(EventTypeInputModel), +}); + +export const schemaEventTypeCustomInputBodyParams = schemaEventTypeCustomInputBaseBodyParams.merge( + schemaEventTypeCustomInputRequiredParams +); + +export const withValidEventTypeCustomInput = withValidation({ + schema: schemaEventTypeCustomInputBodyParams, + type: "Zod", + mode: "body", +}); diff --git a/lib/validations/schedule.ts b/lib/validations/schedule.ts index dca4a77345..e71ecbfba8 100644 --- a/lib/validations/schedule.ts +++ b/lib/validations/schedule.ts @@ -1,8 +1,18 @@ import { withValidation } from "next-validations"; +import { z } from "zod"; import { _ScheduleModel as Schedule } from "@calcom/prisma/zod"; -export const schemaScheduleBodyParams = Schedule.omit({ id: true }).partial(); +// import { jsonSchema } from "./shared/jsonSchema"; + +const schemaScheduleBaseBodyParams = Schedule.omit({ id: true }).partial(); + +const schemaScheduleRequiredParams = z.object({ + userId: z.number(), + name: z.string(), +}); + +export const schemaScheduleBodyParams = schemaScheduleBaseBodyParams.merge(schemaScheduleRequiredParams); export const schemaSchedulePublic = Schedule.omit({}); diff --git a/lib/validations/selected-calendar.ts b/lib/validations/selected-calendar.ts index f1bb0483ae..64eee4e401 100644 --- a/lib/validations/selected-calendar.ts +++ b/lib/validations/selected-calendar.ts @@ -1,10 +1,28 @@ import { withValidation } from "next-validations"; +import { z } from "zod"; -import { _SelectedCalendarModel as SelectedCalendar } from "@calcom/prisma/zod"; +import { _UserModel, _SelectedCalendarModel as SelectedCalendar } from "@calcom/prisma/zod"; -export const schemaSelectedCalendarBodyParams = SelectedCalendar.omit({}).partial(); +export const schemaSelectedCalendarBaseBodyParams = SelectedCalendar.omit({ userId: true }).partial(); -export const schemaSelectedCalendarPublic = SelectedCalendar.omit({ userId: true }); +export const schemaSelectedCalendarPublic = SelectedCalendar.omit({}); + +const schemaSelectedCalendarRequiredParams = z.object({ + externalId: z.string(), + integration: z.string(), + user: z.object({ + connect: z.object({ + id: z.number().optional(), + username: z.string().optional(), + email: z.string().optional(), + }), + create: z.any(), + }), +}); + +export const schemaSelectedCalendarBodyParams = schemaSelectedCalendarBaseBodyParams.merge( + schemaSelectedCalendarRequiredParams +); export const withValidSelectedCalendar = withValidation({ schema: schemaSelectedCalendarBodyParams, diff --git a/pages/api/daily-event-references/[id]/delete.ts b/pages/api/daily-event-references/[id]/delete.ts index 77c97782a6..71b61d86c4 100644 --- a/pages/api/daily-event-references/[id]/delete.ts +++ b/pages/api/daily-event-references/[id]/delete.ts @@ -3,30 +3,49 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BaseResponse } from "@lib/types"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - message?: string; - error?: unknown; -}; - -export async function deleteDailyEventReference(req: NextApiRequest, res: NextApiResponse) { +/** + * @swagger + * /api/daily-event-references/{id}/delete: + * delete: + * summary: Remove an existing dailyEventReference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the dailyEventReference to delete + * tags: + * - dailyEventReferences + * responses: + * 201: + * description: OK, dailyEventReference removed successfuly + * model: DailyEventReference + * 400: + * description: Bad request. DailyEventReference id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteDailyEventReference(req: NextApiRequest, res: NextApiResponse) { const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (safe.success) { - const deletedDailyEventReference = await prisma.dailyEventReference.delete({ - where: { id: safe.data.id }, - }); - // We only remove the dailyEventReference type from the database if there's an existing resource. - if (deletedDailyEventReference) - res.status(200).json({ message: `dailyEventReference with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.dailyEventReference.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only DELETE Method allowed" }); + if (!safe.success) throw new Error("Invalid request query", safe.error); + + const data = await prisma.dailyEventReference.delete({ where: { id: safe.data.id } }); + + if (data) + res.status(200).json({ message: `DailyEventReference with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `DailyEventReference with id: ${safe.data.id} was not able to be processed`, + error, + }); } -// export default withValidQueryIdTransformParseInt(deleteDailyEventReference); export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteDailyEventReference)); diff --git a/pages/api/daily-event-references/[id]/edit.ts b/pages/api/daily-event-references/[id]/edit.ts index 372e258163..e3d9f73765 100644 --- a/pages/api/daily-event-references/[id]/edit.ts +++ b/pages/api/daily-event-references/[id]/edit.ts @@ -1,10 +1,12 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { DailyEventReference } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { DailyEventReferenceResponse } from "@lib/types"; import { - schemaDailyEventReference, + schemaDailyEventReferenceBodyParams, + schemaDailyEventReferencePublic, withValidDailyEventReference, } from "@lib/validations/daily-event-reference"; import { @@ -12,30 +14,52 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: DailyEventReference; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/daily-event-references/{id}/edit: + * patch: + * summary: Edit an existing dailyEventReference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the dailyEventReference to edit + * tags: + * - dailyEventReferences + * responses: + * 201: + * description: OK, dailyEventReference edited successfuly + * model: DailyEventReference + * 400: + * description: Bad request. DailyEventReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editDailyEventReference( + req: NextApiRequest, + res: NextApiResponse +) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaDailyEventReferenceBodyParams.safeParse(req.body); -export async function editDailyEventReference(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaDailyEventReference.safeParse(body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const dailyEventReference = await prisma.dailyEventReference.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaDailyEventReferencePublic.parse(dailyEventReference); - if (method === "PATCH" && safeQuery.success && safeBody.success) { - const data = await prisma.dailyEventReference.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - if (data) res.status(200).json({ data }); - else - res - .status(404) - .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); - - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only PATCH Method allowed for updating dailyEventReferences" }); + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, + error, + }); } -export default withValidQueryIdTransformParseInt(withValidDailyEventReference(editDailyEventReference)); +export default withMiddleware("HTTP_PATCH")( + withValidQueryIdTransformParseInt(withValidDailyEventReference(editDailyEventReference)) +); diff --git a/pages/api/daily-event-references/[id]/index.ts b/pages/api/daily-event-references/[id]/index.ts index 459c4f5381..338a64470c 100644 --- a/pages/api/daily-event-references/[id]/index.ts +++ b/pages/api/daily-event-references/[id]/index.ts @@ -1,29 +1,54 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { DailyEventReference } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { DailyEventReferenceResponse } from "@lib/types"; +import { schemaDailyEventReferencePublic } from "@lib/validations/daily-event-reference"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: DailyEventReference; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/daily-event-references/{id}: + * get: + * summary: Get a dailyEventReference by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the dailyEventReference to get + * tags: + * - dailyEventReferences + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: DailyEventReference was not found + */ +export async function dailyEventReferenceById( + req: NextApiRequest, + res: NextApiResponse +) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); -export async function dailyEventReference(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "GET" && safe.success) { - const data = await prisma.dailyEventReference.findUnique({ where: { id: safe.data.id } }); + const dailyEventReference = await prisma.dailyEventReference.findUnique({ where: { id: safe.data.id } }); + const data = schemaDailyEventReferencePublic.parse(dailyEventReference); - if (data) res.status(200).json({ data }); - else res.status(404).json({ message: "Event type not found" }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only GET Method allowed" }); + if (dailyEventReference) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "DailyEventReference was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(dailyEventReference); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(dailyEventReferenceById)); diff --git a/pages/api/daily-event-references/index.ts b/pages/api/daily-event-references/index.ts index a5509f8a90..774d39358c 100644 --- a/pages/api/daily-event-references/index.ts +++ b/pages/api/daily-event-references/index.ts @@ -1,15 +1,42 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { DailyEventReference } from "@calcom/prisma/client"; -type ResponseData = { - data?: DailyEventReference[]; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { DailyEventReferencesResponse } from "@lib/types"; +import { schemaDailyEventReferencePublic } from "@lib/validations/daily-event-reference"; + +/** + * @swagger + * /api/daily-event-references: + * get: + * summary: Get all dailyEventReferences + * tags: + * - dailyEventReferences + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No dailyEventReferences were found + */ +async function allDailyEventReferences( + _: NextApiRequest, + res: NextApiResponse +) { + const dailyEventReferences = await prisma.dailyEventReference.findMany(); + const data = dailyEventReferences.map((dailyEventReference) => + schemaDailyEventReferencePublic.parse(dailyEventReference) + ); -export default async function dailyEventReference(req: NextApiRequest, res: NextApiResponse) { - const data = await prisma.dailyEventReference.findMany(); if (data) res.status(200).json({ data }); - else res.status(400).json({ error: "No data found" }); + else + (error: Error) => + res.status(404).json({ + message: "No DailyEventReferences were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allDailyEventReferences); diff --git a/pages/api/daily-event-references/new.ts b/pages/api/daily-event-references/new.ts index 5bbc67fb2c..baf5e83d10 100644 --- a/pages/api/daily-event-references/new.ts +++ b/pages/api/daily-event-references/new.ts @@ -1,31 +1,55 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { DailyEventReference } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { DailyEventReferenceResponse } from "@lib/types"; import { - schemaDailyEventReference, + schemaDailyEventReferenceBodyParams, + schemaDailyEventReferencePublic, withValidDailyEventReference, } from "@lib/validations/daily-event-reference"; -type ResponseData = { - data?: DailyEventReference; - message?: string; - error?: string; -}; +/** + * @swagger + * /api/daily-event-references/new: + * post: + * summary: Creates a new dailyEventReference + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/DailyEventReference' + * tags: + * - dailyEventReferences + * responses: + * 201: + * description: OK, dailyEventReference created + * model: DailyEventReference + * 400: + * description: Bad request. DailyEventReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createDailyEventReference( + req: NextApiRequest, + res: NextApiResponse +) { + const safe = schemaDailyEventReferenceBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createDailyEventReference(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - const safe = schemaDailyEventReference.safeParse(body); - if (method === "POST" && safe.success) { - await prisma.dailyEventReference - .create({ data: safe.data }) - .then((data) => res.status(201).json({ data })) - .catch((error) => - res.status(400).json({ message: "Could not create dailyEventReference type", error: error }) - ); - // Reject any other HTTP method than POST - } else res.status(405).json({ error: "Only POST Method allowed" }); + const dailyEventReference = await prisma.dailyEventReference.create({ data: safe.data }); + const data = schemaDailyEventReferencePublic.parse(dailyEventReference); + + if (data) res.status(201).json({ data, message: "DailyEventReference created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new dailyEventReference", + error, + }); } -export default withValidDailyEventReference(createDailyEventReference); +export default withMiddleware("HTTP_POST")(withValidDailyEventReference(createDailyEventReference)); diff --git a/pages/api/destination-calendars/[id]/delete.ts b/pages/api/destination-calendars/[id]/delete.ts index b734fbdf9b..2573532efd 100644 --- a/pages/api/destination-calendars/[id]/delete.ts +++ b/pages/api/destination-calendars/[id]/delete.ts @@ -2,28 +2,50 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BaseResponse } from "@lib/types"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/destination-calendars/{id}/delete: + * delete: + * summary: Remove an existing destinationCalendar + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the destinationCalendar to delete + * tags: + * - destinationCalendars + * responses: + * 201: + * description: OK, destinationCalendar removed successfuly + * model: DestinationCalendar + * 400: + * description: Bad request. DestinationCalendar id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteDestinationCalendar(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query", safe.error); -export async function deleteDestinationCalendar(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const destinationCalendar = await prisma.destinationCalendar.delete({ where: { id: safe.data.id } }); - // We only remove the destinationCalendar type from the database if there's an existing resource. - if (destinationCalendar) - res.status(200).json({ message: `destinationCalendar with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.destinationCalendar.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only DELETE Method allowed" }); + const data = await prisma.destinationCalendar.delete({ where: { id: safe.data.id } }); + + if (data) + res.status(200).json({ message: `DestinationCalendar with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `DestinationCalendar with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withValidQueryIdTransformParseInt(deleteDestinationCalendar); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteDestinationCalendar)); diff --git a/pages/api/destination-calendars/[id]/edit.ts b/pages/api/destination-calendars/[id]/edit.ts index 09c042b7e1..9dc4ae38fb 100644 --- a/pages/api/destination-calendars/[id]/edit.ts +++ b/pages/api/destination-calendars/[id]/edit.ts @@ -1,10 +1,12 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { DestinationCalendar } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { DestinationCalendarResponse } from "@lib/types"; import { - schemaDestinationCalendar, + schemaDestinationCalendarBodyParams, + schemaDestinationCalendarPublic, withValidDestinationCalendar, } from "@lib/validations/destination-calendar"; import { @@ -12,30 +14,52 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: DestinationCalendar; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/destination-calendars/{id}/edit: + * patch: + * summary: Edit an existing destinationCalendar + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the destinationCalendar to edit + * tags: + * - destinationCalendars + * responses: + * 201: + * description: OK, destinationCalendar edited successfuly + * model: DestinationCalendar + * 400: + * description: Bad request. DestinationCalendar body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editDestinationCalendar( + req: NextApiRequest, + res: NextApiResponse +) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaDestinationCalendarBodyParams.safeParse(req.body); -export async function editDestinationCalendar(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaDestinationCalendar.safeParse(body); + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const destinationCalendar = await prisma.destinationCalendar.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaDestinationCalendarPublic.parse(destinationCalendar); - if (method === "PATCH" && safeQuery.success && safeBody.success) { - const data = await prisma.destinationCalendar.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - if (data) res.status(200).json({ data }); - else - res - .status(404) - .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); - - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only PATCH Method allowed for updating destinationCalendars" }); + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, + error, + }); } -export default withValidQueryIdTransformParseInt(withValidDestinationCalendar(editDestinationCalendar)); +export default withMiddleware("HTTP_PATCH")( + withValidQueryIdTransformParseInt(withValidDestinationCalendar(editDestinationCalendar)) +); diff --git a/pages/api/destination-calendars/[id]/index.ts b/pages/api/destination-calendars/[id]/index.ts index fde198f77f..2639e70538 100644 --- a/pages/api/destination-calendars/[id]/index.ts +++ b/pages/api/destination-calendars/[id]/index.ts @@ -1,29 +1,54 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { DestinationCalendar } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { DestinationCalendarResponse } from "@lib/types"; +import { schemaDestinationCalendarPublic } from "@lib/validations/destination-calendar"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: DestinationCalendar; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/destination-calendars/{id}: + * get: + * summary: Get a destinationCalendar by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the destinationCalendar to get + * tags: + * - destinationCalendars + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: DestinationCalendar was not found + */ +export async function destinationCalendarById( + req: NextApiRequest, + res: NextApiResponse +) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); -export async function destinationCalendar(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "GET" && safe.success) { - const data = await prisma.destinationCalendar.findUnique({ where: { id: safe.data.id } }); + const destinationCalendar = await prisma.destinationCalendar.findUnique({ where: { id: safe.data.id } }); + const data = schemaDestinationCalendarPublic.parse(destinationCalendar); - if (data) res.status(200).json({ data }); - else res.status(404).json({ message: "Event type not found" }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only GET Method allowed" }); + if (destinationCalendar) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "DestinationCalendar was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(destinationCalendar); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(destinationCalendarById)); diff --git a/pages/api/destination-calendars/index.ts b/pages/api/destination-calendars/index.ts index 933ef20568..6f1a9147dd 100644 --- a/pages/api/destination-calendars/index.ts +++ b/pages/api/destination-calendars/index.ts @@ -1,15 +1,42 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { DestinationCalendar } from "@calcom/prisma/client"; -type ResponseData = { - data?: DestinationCalendar[]; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { DestinationCalendarsResponse } from "@lib/types"; +import { schemaDestinationCalendarPublic } from "@lib/validations/destination-calendar"; + +/** + * @swagger + * /api/destination-calendars: + * get: + * summary: Get all destinationCalendars + * tags: + * - destinationCalendars + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No destinationCalendars were found + */ +async function allDestinationCalendars( + _: NextApiRequest, + res: NextApiResponse +) { + const destinationCalendars = await prisma.destinationCalendar.findMany(); + const data = destinationCalendars.map((destinationCalendar) => + schemaDestinationCalendarPublic.parse(destinationCalendar) + ); -export default async function destinationCalendar(req: NextApiRequest, res: NextApiResponse) { - const data = await prisma.destinationCalendar.findMany(); if (data) res.status(200).json({ data }); - else res.status(400).json({ error: "No data found" }); + else + (error: Error) => + res.status(404).json({ + message: "No DestinationCalendars were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allDestinationCalendars); diff --git a/pages/api/destination-calendars/new.ts b/pages/api/destination-calendars/new.ts index 483ff56de1..896be9f06a 100644 --- a/pages/api/destination-calendars/new.ts +++ b/pages/api/destination-calendars/new.ts @@ -1,31 +1,55 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { DestinationCalendar } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { DestinationCalendarResponse } from "@lib/types"; import { - schemaDestinationCalendar, + schemaDestinationCalendarBodyParams, + schemaDestinationCalendarPublic, withValidDestinationCalendar, } from "@lib/validations/destination-calendar"; -type ResponseData = { - data?: DestinationCalendar; - message?: string; - error?: string; -}; +/** + * @swagger + * /api/destination-calendars/new: + * post: + * summary: Creates a new destinationCalendar + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/DestinationCalendar' + * tags: + * - destinationCalendars + * responses: + * 201: + * description: OK, destinationCalendar created + * model: DestinationCalendar + * 400: + * description: Bad request. DestinationCalendar body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createDestinationCalendar( + req: NextApiRequest, + res: NextApiResponse +) { + const safe = schemaDestinationCalendarBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); -async function createDestinationCalendar(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - const safe = schemaDestinationCalendar.safeParse(body); - if (method === "POST" && safe.success) { - await prisma.destinationCalendar - .create({ data: safe.data }) - .then((data) => res.status(201).json({ data })) - .catch((error) => - res.status(400).json({ message: "Could not create destinationCalendar type", error: error }) - ); - // Reject any other HTTP method than POST - } else res.status(405).json({ error: "Only POST Method allowed" }); + const destinationCalendar = await prisma.destinationCalendar.create({ data: safe.data }); + const data = schemaDestinationCalendarPublic.parse(destinationCalendar); + + if (data) res.status(201).json({ data, message: "DestinationCalendar created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new destinationCalendar", + error, + }); } -export default withValidDestinationCalendar(createDestinationCalendar); +export default withMiddleware("HTTP_POST")(withValidDestinationCalendar(createDestinationCalendar)); diff --git a/pages/api/event-type-custom-inputs/[id]/delete.ts b/pages/api/event-type-custom-inputs/[id]/delete.ts index acccbac7d7..94c6bb2610 100644 --- a/pages/api/event-type-custom-inputs/[id]/delete.ts +++ b/pages/api/event-type-custom-inputs/[id]/delete.ts @@ -2,28 +2,50 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BaseResponse } from "@lib/types"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/event-type-custom-inputs/{id}/delete: + * delete: + * summary: Remove an existing eventTypeCustomInput + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the eventTypeCustomInput to delete + * tags: + * - eventTypeCustomInputs + * responses: + * 201: + * description: OK, eventTypeCustomInput removed successfuly + * model: EventTypeCustomInput + * 400: + * description: Bad request. EventTypeCustomInput id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteEventTypeCustomInput(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query", safe.error); -export async function deleteEventTypeCustomInput(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "DELETE" && safe.success && safe.data) { - const eventTypeCustomInput = await prisma.eventTypeCustomInput.delete({ where: { id: safe.data.id } }); - // We only remove the eventTypeCustomInput type from the database if there's an existing resource. - if (eventTypeCustomInput) - res.status(200).json({ message: `eventTypeCustomInput with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.eventTypeCustomInput.delete() if the resource is not found. - else res.status(400).json({ message: `Resource with id:${safe.data.id} was not found` }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only DELETE Method allowed" }); + const data = await prisma.eventTypeCustomInput.delete({ where: { id: safe.data.id } }); + + if (data) + res.status(200).json({ message: `EventTypeCustomInput with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `EventTypeCustomInput with id: ${safe.data.id} was not able to be processed`, + error, + }); } -export default withValidQueryIdTransformParseInt(deleteEventTypeCustomInput); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteEventTypeCustomInput)); diff --git a/pages/api/event-type-custom-inputs/[id]/edit.ts b/pages/api/event-type-custom-inputs/[id]/edit.ts deleted file mode 100644 index 1c632034c2..0000000000 --- a/pages/api/event-type-custom-inputs/[id]/edit.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; -import { EventTypeCustomInput } from "@calcom/prisma/client"; - -import { - schemaEventTypeCustomInput, - withValidEventTypeCustomInput, -} from "@lib/validations/eventTypeCustomInput"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -type ResponseData = { - data?: EventTypeCustomInput; - message?: string; - error?: unknown; -}; - -export async function editEventTypeCustomInput(req: NextApiRequest, res: NextApiResponse) { - const { query, body, method } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaEventTypeCustomInput.safeParse(body); - - if (method === "PATCH" && safeQuery.success && safeBody.success) { - const data = await prisma.eventTypeCustomInput.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - if (data) res.status(200).json({ data }); - else - res - .status(404) - .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); - - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only PATCH Method allowed for updating eventTypeCustomInputs" }); -} - -export default withValidQueryIdTransformParseInt(withValidEventTypeCustomInput(editEventTypeCustomInput)); diff --git a/pages/api/event-type-custom-inputs/[id]/edit.ts.fixme b/pages/api/event-type-custom-inputs/[id]/edit.ts.fixme new file mode 100644 index 0000000000..c95d4aa876 --- /dev/null +++ b/pages/api/event-type-custom-inputs/[id]/edit.ts.fixme @@ -0,0 +1,65 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { EventTypeCustomInputResponse } from "@lib/types"; +import { + schemaEventTypeCustomInputBodyParams, + schemaEventTypeCustomInputPublic, + withValidEventTypeCustomInput, +} from "@lib/validations/event-type-custom-input"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /api/event-type-custom-inputs/{id}/edit: + * patch: + * summary: Edit an existing eventTypeCustomInput + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the eventTypeCustomInput to edit + * tags: + * - eventTypeCustomInputs + * responses: + * 201: + * description: OK, eventTypeCustomInput edited successfuly + * model: EventTypeCustomInput + * 400: + * description: Bad request. EventTypeCustomInput body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editEventTypeCustomInput( + req: NextApiRequest, + res: NextApiResponse +) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaEventTypeCustomInputBodyParams.safeParse(req.body); + + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const eventTypeCustomInput = await prisma.eventTypeCustomInput.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaEventTypeCustomInputPublic.parse(eventTypeCustomInput); + + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, + error, + }); +} + +export default withMiddleware("HTTP_PATCH")( + withValidQueryIdTransformParseInt(withValidEventTypeCustomInput(editEventTypeCustomInput)) +); diff --git a/pages/api/event-type-custom-inputs/[id]/index.ts b/pages/api/event-type-custom-inputs/[id]/index.ts index 47170af37d..5ceea367b4 100644 --- a/pages/api/event-type-custom-inputs/[id]/index.ts +++ b/pages/api/event-type-custom-inputs/[id]/index.ts @@ -1,29 +1,54 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { EventTypeCustomInput } from "@calcom/prisma/client"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { EventTypeCustomInputResponse } from "@lib/types"; +import { schemaEventTypeCustomInputPublic } from "@lib/validations/event-type-custom-input"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -type ResponseData = { - data?: EventTypeCustomInput; - message?: string; - error?: unknown; -}; +/** + * @swagger + * /api/event-type-custom-inputs/{id}: + * get: + * summary: Get a eventTypeCustomInput by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the eventTypeCustomInput to get + * tags: + * - eventTypeCustomInputs + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: EventTypeCustomInput was not found + */ +export async function eventTypeCustomInputById( + req: NextApiRequest, + res: NextApiResponse +) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); -export async function eventTypeCustomInput(req: NextApiRequest, res: NextApiResponse) { - const { query, method } = req; - const safe = await schemaQueryIdParseInt.safeParse(query); - if (method === "GET" && safe.success) { - const data = await prisma.eventTypeCustomInput.findUnique({ where: { id: safe.data.id } }); + const eventTypeCustomInput = await prisma.eventTypeCustomInput.findUnique({ where: { id: safe.data.id } }); + const data = schemaEventTypeCustomInputPublic.parse(eventTypeCustomInput); - if (data) res.status(200).json({ data }); - else res.status(404).json({ message: "Event type not found" }); - // Reject any other HTTP method than POST - } else res.status(405).json({ message: "Only GET Method allowed" }); + if (eventTypeCustomInput) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "EventTypeCustomInput was not found", + error, + }); } -export default withValidQueryIdTransformParseInt(eventTypeCustomInput); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(eventTypeCustomInputById)); diff --git a/pages/api/event-type-custom-inputs/index.ts b/pages/api/event-type-custom-inputs/index.ts index b39cd14bca..689d23c7ae 100644 --- a/pages/api/event-type-custom-inputs/index.ts +++ b/pages/api/event-type-custom-inputs/index.ts @@ -1,15 +1,42 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; -import { EventTypeCustomInput } from "@calcom/prisma/client"; -type ResponseData = { - data?: EventTypeCustomInput[]; - error?: unknown; -}; +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { EventTypeCustomInputsResponse } from "@lib/types"; +import { schemaEventTypeCustomInputPublic } from "@lib/validations/event-type-custom-input"; + +/** + * @swagger + * /api/event-type-custom-inputs: + * get: + * summary: Get all eventTypeCustomInputs + * tags: + * - eventTypeCustomInputs + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No eventTypeCustomInputs were found + */ +async function allEventTypeCustomInputs( + _: NextApiRequest, + res: NextApiResponse +) { + const eventTypeCustomInputs = await prisma.eventTypeCustomInput.findMany(); + const data = eventTypeCustomInputs.map((eventTypeCustomInput) => + schemaEventTypeCustomInputPublic.parse(eventTypeCustomInput) + ); -export default async function eventTypeCustomInput(req: NextApiRequest, res: NextApiResponse) { - const data = await prisma.eventTypeCustomInput.findMany(); if (data) res.status(200).json({ data }); - else res.status(400).json({ error: "No data found" }); + else + (error: Error) => + res.status(404).json({ + message: "No EventTypeCustomInputs were found", + error, + }); } + +export default withMiddleware("HTTP_GET")(allEventTypeCustomInputs); diff --git a/pages/api/event-type-custom-inputs/new.ts b/pages/api/event-type-custom-inputs/new.ts deleted file mode 100644 index e2a4078a59..0000000000 --- a/pages/api/event-type-custom-inputs/new.ts +++ /dev/null @@ -1,31 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; -import { EventTypeCustomInput } from "@calcom/prisma/client"; - -import { - schemaEventTypeCustomInput, - withValidEventTypeCustomInput, -} from "@lib/validations/eventTypeCustomInput"; - -type ResponseData = { - data?: EventTypeCustomInput; - message?: string; - error?: string; -}; - -async function createEventTypeCustomInput(req: NextApiRequest, res: NextApiResponse) { - const { body, method } = req; - const safe = schemaEventTypeCustomInput.safeParse(body); - if (method === "POST" && safe.success) { - await prisma.eventTypeCustomInput - .create({ data: safe.data }) - .then((data) => res.status(201).json({ data })) - .catch((error) => - res.status(400).json({ message: "Could not create eventTypeCustomInput type", error: error }) - ); - // Reject any other HTTP method than POST - } else res.status(405).json({ error: "Only POST Method allowed" }); -} - -export default withValidEventTypeCustomInput(createEventTypeCustomInput); diff --git a/pages/api/event-type-custom-inputs/new.ts.fixme b/pages/api/event-type-custom-inputs/new.ts.fixme new file mode 100644 index 0000000000..165ed6cd20 --- /dev/null +++ b/pages/api/event-type-custom-inputs/new.ts.fixme @@ -0,0 +1,55 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { EventTypeCustomInputResponse } from "@lib/types"; +import { + schemaEventTypeCustomInputBodyParams, + schemaEventTypeCustomInputPublic, + withValidEventTypeCustomInput, +} from "@lib/validations/event-type-custom-input"; + +/** + * @swagger + * /api/event-type-custom-inputs/new: + * post: + * summary: Creates a new eventTypeCustomInput + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/EventTypeCustomInput' + * tags: + * - eventTypeCustomInputs + * responses: + * 201: + * description: OK, eventTypeCustomInput created + * model: EventTypeCustomInput + * 400: + * description: Bad request. EventTypeCustomInput body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createEventTypeCustomInput( + req: NextApiRequest, + res: NextApiResponse +) { + const safe = schemaEventTypeCustomInputBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); + + const eventTypeCustomInput = await prisma.eventTypeCustomInput.create({ data: safe.data }); + const data = schemaEventTypeCustomInputPublic.parse(eventTypeCustomInput); + + if (data) res.status(201).json({ data, message: "EventTypeCustomInput created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new eventTypeCustomInput", + error, + }); +} + +export default withMiddleware("HTTP_POST")(withValidEventTypeCustomInput(createEventTypeCustomInput)); diff --git a/pages/api/selected-calendars/[id]/delete.ts b/pages/api/selected-calendars/[id]/delete.ts index d4f0fac746..76b949972a 100644 --- a/pages/api/selected-calendars/[id]/delete.ts +++ b/pages/api/selected-calendars/[id]/delete.ts @@ -4,16 +4,27 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { BaseResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; /** * @swagger - * /api/selectedCalendars/:id/delete: + * /api/selected-calendars/{userId}_{teamId}/delete: * delete: * summary: Remove an existing selectedCalendar + * parameters: + * - in: path + * - name: userId + * schema: + * type: integer + * required: true + * description: Numeric ID of the user to get the selectedCalendar of + * * - name: teamId + * schema: + * type: integer + * required: true + * description: Numeric ID of the team to get the selectedCalendar of + * tags: + * - selectedCalendars * responses: * 201: * description: OK, selectedCalendar removed successfuly @@ -24,10 +35,18 @@ import { * description: Authorization information is missing or invalid. */ export async function deleteSelectedCalendar(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); + const safe = await schemaQueryIdAsString.safeParse(req.query); if (!safe.success) throw new Error("Invalid request query", safe.error); - - const data = await prisma.selectedCalendar.delete({ where: { id: safe.data.id } }); + const [userId, integration, externalId] = safe.data.id.split("_"); + const data = await prisma.selectedCalendar.delete({ + where: { + userId_integration_externalId: { + userId: parseInt(userId), + integration: integration, + externalId: externalId, + }, + }, + }); if (data) res.status(200).json({ message: `SelectedCalendar with id: ${safe.data.id} deleted successfully` }); @@ -39,4 +58,4 @@ export async function deleteSelectedCalendar(req: NextApiRequest, res: NextApiRe }); } -export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteSelectedCalendar)); +export default withMiddleware("HTTP_DELETE")(withValidQueryIdString(deleteSelectedCalendar)); diff --git a/pages/api/selected-calendars/[id]/edit.ts b/pages/api/selected-calendars/[id]/edit.ts index 950c4c04eb..717afb9c1f 100644 --- a/pages/api/selected-calendars/[id]/edit.ts +++ b/pages/api/selected-calendars/[id]/edit.ts @@ -9,16 +9,15 @@ import { schemaSelectedCalendarPublic, withValidSelectedCalendar, } from "@lib/validations/selected-calendar"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; /** * @swagger - * /api/selectedCalendars/:id/edit: + * /api/selected-calendars/{id}/edit: * patch: * summary: Edits an existing selectedCalendar + * tags: + * - selectedCalendars * responses: * 201: * description: OK, selectedCalendar edited successfuly @@ -32,12 +31,19 @@ export async function editSelectedCalendar( req: NextApiRequest, res: NextApiResponse ) { - const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeQuery = await schemaQueryIdAsString.safeParse(req.query); const safeBody = await schemaSelectedCalendarBodyParams.safeParse(req.body); - if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const [userId, integration, externalId] = safeQuery.data.id.split("_"); + const selectedCalendar = await prisma.selectedCalendar.update({ - where: { id: safeQuery.data.id }, + where: { + userId_integration_externalId: { + userId: parseInt(userId), + integration: integration, + externalId: externalId, + }, + }, data: safeBody.data, }); const data = schemaSelectedCalendarPublic.parse(selectedCalendar); @@ -52,5 +58,5 @@ export async function editSelectedCalendar( } export default withMiddleware("HTTP_PATCH")( - withValidQueryIdTransformParseInt(withValidSelectedCalendar(editSelectedCalendar)) + withValidQueryIdString(withValidSelectedCalendar(editSelectedCalendar)) ); diff --git a/pages/api/selected-calendars/[id]/index.ts b/pages/api/selected-calendars/[id]/index.ts index 3867c3834a..d88e0116ff 100644 --- a/pages/api/selected-calendars/[id]/index.ts +++ b/pages/api/selected-calendars/[id]/index.ts @@ -5,25 +5,28 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { SelectedCalendarResponse } from "@lib/types"; import { schemaSelectedCalendarPublic } from "@lib/validations/selected-calendar"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; /** * @swagger - * /api/selectedCalendars/{id}: + * /api/selected-calendars/{userId}_{teamId}: * get: - * summary: find selectedCalendar by ID + * summary: find selectedCalendar by userID and teamID * parameters: * - in: path - * name: id + * name: userId * schema: * type: integer * required: true - * description: Numeric ID of the user to delete + * description: Numeric userId of the selectedCalendar to get + * - in: path + * name: teamId + * schema: + * type: integer + * required: true + * description: Numeric teamId of the selectedCalendar to get * tags: - * - selected-calendars + * - selectedCalendars * responses: * 200: * description: OK @@ -36,10 +39,19 @@ export async function selectedCalendarById( req: NextApiRequest, res: NextApiResponse ) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); + const safe = await schemaQueryIdAsString.safeParse(req.query); if (!safe.success) throw new Error("Invalid request query"); + const [userId, integration, externalId] = safe.data.id.split("_"); - const selectedCalendar = await prisma.selectedCalendar.findUnique({ where: { id: safe.data.id } }); + const selectedCalendar = await prisma.selectedCalendar.findUnique({ + where: { + userId_integration_externalId: { + userId: parseInt(userId), + integration: integration, + externalId: externalId, + }, + }, + }); const data = schemaSelectedCalendarPublic.parse(selectedCalendar); if (selectedCalendar) res.status(200).json({ data }); @@ -51,4 +63,4 @@ export async function selectedCalendarById( }); } -export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(selectedCalendarById)); +export default withMiddleware("HTTP_GET")(withValidQueryIdString(selectedCalendarById)); From fc795f963ba63676fc5a73fac64d74ecf85d329f Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 2 Apr 2022 02:09:04 +0200 Subject: [PATCH 054/658] fix: hack around create/connect issues for now --- lib/validations/event-type-custom-input.ts | 18 +++++++++++++----- lib/validations/schedule.ts | 2 -- lib/validations/selected-calendar.ts | 3 ++- .../[id]/{edit.ts.fixme => edit.ts} | 0 .../{new.ts.fixme => new.ts} | 0 5 files changed, 15 insertions(+), 8 deletions(-) rename pages/api/event-type-custom-inputs/[id]/{edit.ts.fixme => edit.ts} (100%) rename pages/api/event-type-custom-inputs/{new.ts.fixme => new.ts} (100%) diff --git a/lib/validations/event-type-custom-input.ts b/lib/validations/event-type-custom-input.ts index 4898af83bd..ea1e80c3bb 100644 --- a/lib/validations/event-type-custom-input.ts +++ b/lib/validations/event-type-custom-input.ts @@ -1,7 +1,7 @@ import { withValidation } from "next-validations"; import { z } from "zod"; -import { EventTypeModel, _EventTypeCustomInputModel as EventTypeCustomInput } from "@calcom/prisma/zod"; +import { _EventTypeCustomInputModel as EventTypeCustomInput } from "@calcom/prisma/zod"; export const schemaEventTypeCustomInputBaseBodyParams = EventTypeCustomInput.omit({ id: true, @@ -12,10 +12,18 @@ export const schemaEventTypeCustomInputPublic = EventTypeCustomInput.omit({}); const schemaEventTypeCustomInputRequiredParams = z.object({ label: z.string(), - // uid: z.string(), - eventType: EventTypeModel.optional(), - - // eventType: z.instanceof(EventTypeInputModel), + required: z.boolean(), + // eventType: EventTypeModel.optional(), + type: z.enum(["TEXT", "TEXTLONG", "NUMBER", "BOOL"]), + eventType: z.object({ + connect: z.object({ + id: z.number().optional(), + // username: z.string().optional(), + // email: z.string().optional(), + }), + // FIXME: Provide valid EventTypeModel schema here, but not sure how yet. + create: z.any(), + }), }); export const schemaEventTypeCustomInputBodyParams = schemaEventTypeCustomInputBaseBodyParams.merge( diff --git a/lib/validations/schedule.ts b/lib/validations/schedule.ts index e71ecbfba8..e5782a08d7 100644 --- a/lib/validations/schedule.ts +++ b/lib/validations/schedule.ts @@ -3,8 +3,6 @@ import { z } from "zod"; import { _ScheduleModel as Schedule } from "@calcom/prisma/zod"; -// import { jsonSchema } from "./shared/jsonSchema"; - const schemaScheduleBaseBodyParams = Schedule.omit({ id: true }).partial(); const schemaScheduleRequiredParams = z.object({ diff --git a/lib/validations/selected-calendar.ts b/lib/validations/selected-calendar.ts index 64eee4e401..4eab89d937 100644 --- a/lib/validations/selected-calendar.ts +++ b/lib/validations/selected-calendar.ts @@ -1,7 +1,7 @@ import { withValidation } from "next-validations"; import { z } from "zod"; -import { _UserModel, _SelectedCalendarModel as SelectedCalendar } from "@calcom/prisma/zod"; +import { _SelectedCalendarModel as SelectedCalendar } from "@calcom/prisma/zod"; export const schemaSelectedCalendarBaseBodyParams = SelectedCalendar.omit({ userId: true }).partial(); @@ -16,6 +16,7 @@ const schemaSelectedCalendarRequiredParams = z.object({ username: z.string().optional(), email: z.string().optional(), }), + // FIXME: Provide valid UserModel schema here, but not sure how yet. create: z.any(), }), }); diff --git a/pages/api/event-type-custom-inputs/[id]/edit.ts.fixme b/pages/api/event-type-custom-inputs/[id]/edit.ts similarity index 100% rename from pages/api/event-type-custom-inputs/[id]/edit.ts.fixme rename to pages/api/event-type-custom-inputs/[id]/edit.ts diff --git a/pages/api/event-type-custom-inputs/new.ts.fixme b/pages/api/event-type-custom-inputs/new.ts similarity index 100% rename from pages/api/event-type-custom-inputs/new.ts.fixme rename to pages/api/event-type-custom-inputs/new.ts From 3271e1731796386827cacb5913f278d69d505ede Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 2 Apr 2022 02:38:46 +0200 Subject: [PATCH 055/658] feat: adds payments CRUD endpoints --- pages/api/payments/[id]/delete.ts | 50 +++++++++++++++++++++++++++ pages/api/payments/[id]/edit.ts | 56 +++++++++++++++++++++++++++++++ pages/api/payments/[id]/index.ts | 51 ++++++++++++++++++++++++++++ pages/api/payments/index.ts | 37 ++++++++++++++++++++ pages/api/payments/new.ts | 48 ++++++++++++++++++++++++++ 5 files changed, 242 insertions(+) create mode 100644 pages/api/payments/[id]/delete.ts create mode 100644 pages/api/payments/[id]/edit.ts create mode 100644 pages/api/payments/[id]/index.ts create mode 100644 pages/api/payments/index.ts create mode 100644 pages/api/payments/new.ts diff --git a/pages/api/payments/[id]/delete.ts b/pages/api/payments/[id]/delete.ts new file mode 100644 index 0000000000..2367f463b0 --- /dev/null +++ b/pages/api/payments/[id]/delete.ts @@ -0,0 +1,50 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BaseResponse } from "@lib/types"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /api/payments/{id}/delete: + * delete: + * summary: Remove an existing payment + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the payment to delete + * tags: + * - payments + * responses: + * 201: + * description: OK, payment removed successfuly + * model: Payment + * 400: + * description: Bad request. Payment id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deletePayment(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query", safe.error); + + const data = await prisma.payment.delete({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ message: `Payment with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `Payment with id: ${safe.data.id} was not able to be processed`, + error, + }); +} + +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deletePayment)); diff --git a/pages/api/payments/[id]/edit.ts b/pages/api/payments/[id]/edit.ts new file mode 100644 index 0000000000..f0f38b5efd --- /dev/null +++ b/pages/api/payments/[id]/edit.ts @@ -0,0 +1,56 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { PaymentResponse } from "@lib/types"; +import { schemaPaymentBodyParams, schemaPaymentPublic, withValidPayment } from "@lib/validations/payment"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /api/payments/{id}/edit: + * patch: + * summary: Edit an existing payment + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the payment to edit + * tags: + * - payments + * responses: + * 201: + * description: OK, payment edited successfuly + * model: Payment + * 400: + * description: Bad request. Payment body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editPayment(req: NextApiRequest, res: NextApiResponse) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaPaymentBodyParams.safeParse(req.body); + + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const payment = await prisma.payment.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaPaymentPublic.parse(payment); + + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, + error, + }); +} + +export default withMiddleware("HTTP_PATCH")(withValidQueryIdTransformParseInt(withValidPayment(editPayment))); diff --git a/pages/api/payments/[id]/index.ts b/pages/api/payments/[id]/index.ts new file mode 100644 index 0000000000..ea5039cf43 --- /dev/null +++ b/pages/api/payments/[id]/index.ts @@ -0,0 +1,51 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { PaymentResponse } from "@lib/types"; +import { schemaPaymentPublic } from "@lib/validations/payment"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /api/payments/{id}: + * get: + * summary: Get a payment by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the payment to get + * tags: + * - payments + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Payment was not found + */ +export async function paymentById(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); + + const payment = await prisma.payment.findUnique({ where: { id: safe.data.id } }); + const data = schemaPaymentPublic.parse(payment); + + if (payment) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "Payment was not found", + error, + }); +} + +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(paymentById)); diff --git a/pages/api/payments/index.ts b/pages/api/payments/index.ts new file mode 100644 index 0000000000..ccffac1161 --- /dev/null +++ b/pages/api/payments/index.ts @@ -0,0 +1,37 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { PaymentsResponse } from "@lib/types"; +import { schemaPaymentPublic } from "@lib/validations/payment"; + +/** + * @swagger + * /api/payments: + * get: + * summary: Get all payments + * tags: + * - payments + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No payments were found + */ +async function allPayments(_: NextApiRequest, res: NextApiResponse) { + const payments = await prisma.payment.findMany(); + const data = payments.map((payment) => schemaPaymentPublic.parse(payment)); + + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "No Payments were found", + error, + }); +} + +export default withMiddleware("HTTP_GET")(allPayments); diff --git a/pages/api/payments/new.ts b/pages/api/payments/new.ts new file mode 100644 index 0000000000..dca0099e48 --- /dev/null +++ b/pages/api/payments/new.ts @@ -0,0 +1,48 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { PaymentResponse } from "@lib/types"; +import { schemaPaymentBodyParams, schemaPaymentPublic, withValidPayment } from "@lib/validations/payment"; + +/** + * @swagger + * /api/payments/new: + * post: + * summary: Creates a new payment + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/Payment' + * tags: + * - payments + * responses: + * 201: + * description: OK, payment created + * model: Payment + * 400: + * description: Bad request. Payment body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createPayment(req: NextApiRequest, res: NextApiResponse) { + const safe = schemaPaymentBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); + + const payment = await prisma.payment.create({ data: safe.data }); + const data = schemaPaymentPublic.parse(payment); + + if (data) res.status(201).json({ data, message: "Payment created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new payment", + error, + }); +} + +export default withMiddleware("HTTP_POST")(withValidPayment(createPayment)); From 1e18e9b9451f8d870c2b18c88fc6dff9048f040a Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 2 Apr 2022 02:45:28 +0200 Subject: [PATCH 056/658] feat: adds reminder-mail endpoints --- lib/types.ts | 9 ++++ lib/validations/reminder-mail.ts | 24 ++++++++++ pages/api/reminder-mails/[id]/delete.ts | 50 ++++++++++++++++++++ pages/api/reminder-mails/[id]/edit.ts | 62 +++++++++++++++++++++++++ pages/api/reminder-mails/[id]/index.ts | 51 ++++++++++++++++++++ pages/api/reminder-mails/index.ts | 37 +++++++++++++++ pages/api/reminder-mails/new.ts | 52 +++++++++++++++++++++ 7 files changed, 285 insertions(+) create mode 100644 lib/validations/reminder-mail.ts create mode 100644 pages/api/reminder-mails/[id]/delete.ts create mode 100644 pages/api/reminder-mails/[id]/edit.ts create mode 100644 pages/api/reminder-mails/[id]/index.ts create mode 100644 pages/api/reminder-mails/index.ts create mode 100644 pages/api/reminder-mails/new.ts diff --git a/lib/types.ts b/lib/types.ts index d0c33538c3..d5a179f7b3 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -16,6 +16,7 @@ import { Membership, Payment, Schedule, + ReminderMail, } from "@calcom/prisma/client"; // Base response, used for all responses @@ -160,3 +161,11 @@ export type WebhookResponse = BaseResponse & { export type WebhooksResponse = BaseResponse & { data?: Partial[]; }; + +// ReminderMail +export type ReminderMailResponse = BaseResponse & { + data?: Partial; +}; +export type ReminderMailsResponse = BaseResponse & { + data?: Partial[]; +}; diff --git a/lib/validations/reminder-mail.ts b/lib/validations/reminder-mail.ts new file mode 100644 index 0000000000..d97c65c2b1 --- /dev/null +++ b/lib/validations/reminder-mail.ts @@ -0,0 +1,24 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +import { _ReminderMailModel as ReminderMail } from "@calcom/prisma/zod"; + +export const schemaReminderMailBaseBodyParams = ReminderMail.omit({ id: true }).partial(); + +export const schemaReminderMailPublic = ReminderMail.omit({}); + +const schemaReminderMailRequiredParams = z.object({ + referenceId: z.number().int(), + reminderType: z.enum(["PENDING_BOOKING_CONFIRMATION"]), + elapsedMinutes: z.number().int(), +}); + +export const schemaReminderMailBodyParams = schemaReminderMailBaseBodyParams.merge( + schemaReminderMailRequiredParams +); + +export const withValidReminderMail = withValidation({ + schema: schemaReminderMailBodyParams, + type: "Zod", + mode: "body", +}); diff --git a/pages/api/reminder-mails/[id]/delete.ts b/pages/api/reminder-mails/[id]/delete.ts new file mode 100644 index 0000000000..3211a4fa9d --- /dev/null +++ b/pages/api/reminder-mails/[id]/delete.ts @@ -0,0 +1,50 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BaseResponse } from "@lib/types"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /api/reminder-mails/{id}/delete: + * delete: + * summary: Remove an existing reminderMail + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the reminderMail to delete + * tags: + * - reminderMails + * responses: + * 201: + * description: OK, reminderMail removed successfuly + * model: ReminderMail + * 400: + * description: Bad request. ReminderMail id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteReminderMail(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query", safe.error); + + const data = await prisma.reminderMail.delete({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ message: `ReminderMail with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `ReminderMail with id: ${safe.data.id} was not able to be processed`, + error, + }); +} + +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteReminderMail)); diff --git a/pages/api/reminder-mails/[id]/edit.ts b/pages/api/reminder-mails/[id]/edit.ts new file mode 100644 index 0000000000..802381bd1c --- /dev/null +++ b/pages/api/reminder-mails/[id]/edit.ts @@ -0,0 +1,62 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { ReminderMailResponse } from "@lib/types"; +import { + schemaReminderMailBodyParams, + schemaReminderMailPublic, + withValidReminderMail, +} from "@lib/validations/reminder-mail"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /api/reminder-mails/{id}/edit: + * patch: + * summary: Edit an existing reminderMail + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the reminderMail to edit + * tags: + * - reminderMails + * responses: + * 201: + * description: OK, reminderMail edited successfuly + * model: ReminderMail + * 400: + * description: Bad request. ReminderMail body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editReminderMail(req: NextApiRequest, res: NextApiResponse) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaReminderMailBodyParams.safeParse(req.body); + + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const reminderMail = await prisma.reminderMail.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaReminderMailPublic.parse(reminderMail); + + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, + error, + }); +} + +export default withMiddleware("HTTP_PATCH")( + withValidQueryIdTransformParseInt(withValidReminderMail(editReminderMail)) +); diff --git a/pages/api/reminder-mails/[id]/index.ts b/pages/api/reminder-mails/[id]/index.ts new file mode 100644 index 0000000000..3554f87b64 --- /dev/null +++ b/pages/api/reminder-mails/[id]/index.ts @@ -0,0 +1,51 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { ReminderMailResponse } from "@lib/types"; +import { schemaReminderMailPublic } from "@lib/validations/reminder-mail"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /api/reminder-mails/{id}: + * get: + * summary: Get a reminderMail by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the reminderMail to get + * tags: + * - reminderMails + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: ReminderMail was not found + */ +export async function reminderMailById(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); + + const reminderMail = await prisma.reminderMail.findUnique({ where: { id: safe.data.id } }); + const data = schemaReminderMailPublic.parse(reminderMail); + + if (reminderMail) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "ReminderMail was not found", + error, + }); +} + +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(reminderMailById)); diff --git a/pages/api/reminder-mails/index.ts b/pages/api/reminder-mails/index.ts new file mode 100644 index 0000000000..546dc58dc7 --- /dev/null +++ b/pages/api/reminder-mails/index.ts @@ -0,0 +1,37 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { ReminderMailsResponse } from "@lib/types"; +import { schemaReminderMailPublic } from "@lib/validations/reminder-mail"; + +/** + * @swagger + * /api/reminder-mails: + * get: + * summary: Get all reminderMails + * tags: + * - reminderMails + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No reminderMails were found + */ +async function allReminderMails(_: NextApiRequest, res: NextApiResponse) { + const reminderMails = await prisma.reminderMail.findMany(); + const data = reminderMails.map((reminderMail) => schemaReminderMailPublic.parse(reminderMail)); + + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "No ReminderMails were found", + error, + }); +} + +export default withMiddleware("HTTP_GET")(allReminderMails); diff --git a/pages/api/reminder-mails/new.ts b/pages/api/reminder-mails/new.ts new file mode 100644 index 0000000000..85afef2a34 --- /dev/null +++ b/pages/api/reminder-mails/new.ts @@ -0,0 +1,52 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { ReminderMailResponse } from "@lib/types"; +import { + schemaReminderMailBodyParams, + schemaReminderMailPublic, + withValidReminderMail, +} from "@lib/validations/reminder-mail"; + +/** + * @swagger + * /api/reminder-mails/new: + * post: + * summary: Creates a new reminderMail + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/ReminderMail' + * tags: + * - reminderMails + * responses: + * 201: + * description: OK, reminderMail created + * model: ReminderMail + * 400: + * description: Bad request. ReminderMail body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createReminderMail(req: NextApiRequest, res: NextApiResponse) { + const safe = schemaReminderMailBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); + + const reminderMail = await prisma.reminderMail.create({ data: safe.data }); + const data = schemaReminderMailPublic.parse(reminderMail); + + if (data) res.status(201).json({ data, message: "ReminderMail created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new reminderMail", + error, + }); +} + +export default withMiddleware("HTTP_POST")(withValidReminderMail(createReminderMail)); From dd506242419b02cc96f6feeceb496d56dffcbfcb Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 2 Apr 2022 02:47:06 +0200 Subject: [PATCH 057/658] fix: remove unnecessary comment --- lib/validations/event-type-custom-input.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/validations/event-type-custom-input.ts b/lib/validations/event-type-custom-input.ts index ea1e80c3bb..73555285e4 100644 --- a/lib/validations/event-type-custom-input.ts +++ b/lib/validations/event-type-custom-input.ts @@ -13,7 +13,6 @@ export const schemaEventTypeCustomInputPublic = EventTypeCustomInput.omit({}); const schemaEventTypeCustomInputRequiredParams = z.object({ label: z.string(), required: z.boolean(), - // eventType: EventTypeModel.optional(), type: z.enum(["TEXT", "TEXTLONG", "NUMBER", "BOOL"]), eventType: z.object({ connect: z.object({ From 837247f81b2f0d8174a68e65043a9d2ac32b225c Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 2 Apr 2022 02:53:14 +0200 Subject: [PATCH 058/658] chore: add type-check gh actions like monorepo --- .github/workflows/type-check.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/workflows/type-check.yml diff --git a/.github/workflows/type-check.yml b/.github/workflows/type-check.yml new file mode 100644 index 0000000000..69a2997013 --- /dev/null +++ b/.github/workflows/type-check.yml @@ -0,0 +1,27 @@ + +name: Check types +on: + pull_request: + branches: + - main +jobs: + types: + name: Check types + strategy: + matrix: + node: ["14.x"] + os: [ubuntu-latest] + runs-on: ${{ matrix.os }} + + steps: + - name: Checkout repo + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Use Node ${{ matrix.node }} + uses: actions/setup-node@v2 + with: + node-version: ${{ matrix.node }} + - run: yarn + - run: yarn type-check \ No newline at end of file From d144c0f9e13f640882094c28308a47b211542deb Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 2 Apr 2022 03:46:24 +0200 Subject: [PATCH 059/658] feat: upgrade all validations, rename to use snake_case --- .github/workflows/type-check.yml | 3 +-- .prettierignore | 3 ++- lib/validations/api-key.ts | 23 +++++++++++++++++++++++ lib/validations/apiKey.ts | 16 ---------------- lib/validations/daily-event-reference.ts | 11 ++++++++++- lib/validations/destination-calendar.ts | 12 +++++++++++- lib/validations/event-type.ts | 22 ++++++++++++++++++++++ lib/validations/eventType.ts | 13 ------------- lib/validations/membership.ts | 10 +++++++++- lib/validations/team.ts | 9 ++++++++- pages/api/api-keys/[id]/edit.ts | 2 +- pages/api/api-keys/new.ts | 2 +- pages/api/event-types/[id]/edit.ts | 2 +- pages/api/event-types/[id]/index.ts | 2 +- pages/api/event-types/index.ts | 2 +- pages/api/event-types/new.ts | 2 +- 16 files changed, 92 insertions(+), 42 deletions(-) create mode 100644 lib/validations/api-key.ts delete mode 100644 lib/validations/apiKey.ts create mode 100644 lib/validations/event-type.ts delete mode 100644 lib/validations/eventType.ts diff --git a/.github/workflows/type-check.yml b/.github/workflows/type-check.yml index 69a2997013..a8c933d87e 100644 --- a/.github/workflows/type-check.yml +++ b/.github/workflows/type-check.yml @@ -1,4 +1,3 @@ - name: Check types on: pull_request: @@ -24,4 +23,4 @@ jobs: with: node-version: ${{ matrix.node }} - run: yarn - - run: yarn type-check \ No newline at end of file + - run: yarn type-check diff --git a/.prettierignore b/.prettierignore index 9e622a406d..28b23b7d57 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,3 +1,4 @@ .next/ coverage/ -node_modules/ \ No newline at end of file +node_modules/ +tests/ \ No newline at end of file diff --git a/lib/validations/api-key.ts b/lib/validations/api-key.ts new file mode 100644 index 0000000000..c0ffd6c9b3 --- /dev/null +++ b/lib/validations/api-key.ts @@ -0,0 +1,23 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +import { _ApiKeyModel as ApiKey } from "@calcom/prisma/zod"; + +export const schemaApiKeyBaseBodyParams = ApiKey.omit({ id: true, userId: true, createdAt: true }).partial(); + +const schemaApiKeyRequiredParams = z.object({ + email: z.string().email(), +}); + +export const schemaApiKeyBodyParams = schemaApiKeyBaseBodyParams.merge(schemaApiKeyRequiredParams); + +export const schemaApiKeyPublic = ApiKey.omit({ + id: true, + userId: true, +}); + +export const withValidApiKey = withValidation({ + schema: schemaApiKeyBodyParams, + type: "Zod", + mode: "body", +}); diff --git a/lib/validations/apiKey.ts b/lib/validations/apiKey.ts deleted file mode 100644 index e12a50cefa..0000000000 --- a/lib/validations/apiKey.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { withValidation } from "next-validations"; - -import { _ApiKeyModel as ApiKey } from "@calcom/prisma/zod"; - -export const schemaApiKeyBodyParams = ApiKey.omit({ id: true, userId: true, createdAt: true }).partial(); - -export const schemaApiKeyPublic = ApiKey.omit({ - id: true, - userId: true, -}); - -export const withValidApiKey = withValidation({ - schema: schemaApiKeyBodyParams, - type: "Zod", - mode: "body", -}); diff --git a/lib/validations/daily-event-reference.ts b/lib/validations/daily-event-reference.ts index da24927310..f477f6bec6 100644 --- a/lib/validations/daily-event-reference.ts +++ b/lib/validations/daily-event-reference.ts @@ -1,8 +1,17 @@ import { withValidation } from "next-validations"; +import { z } from "zod"; import { _DailyEventReferenceModel as DailyEventReference } from "@calcom/prisma/zod"; -export const schemaDailyEventReferenceBodyParams = DailyEventReference.omit({ id: true }); +export const schemaDailyEventReferenceBaseBodyParams = DailyEventReference.omit({ id: true }); + +const schemaDailyEventReferenceRequiredParams = z.object({ + email: z.string().email(), +}); + +export const schemaDailyEventReferenceBodyParams = schemaDailyEventReferenceBaseBodyParams.merge( + schemaDailyEventReferenceRequiredParams +); export const schemaDailyEventReferencePublic = DailyEventReference.omit({}); diff --git a/lib/validations/destination-calendar.ts b/lib/validations/destination-calendar.ts index 002d68d097..87e367ee19 100644 --- a/lib/validations/destination-calendar.ts +++ b/lib/validations/destination-calendar.ts @@ -1,8 +1,18 @@ import { withValidation } from "next-validations"; +import { z } from "zod"; import { _DestinationCalendarModel as DestinationCalendar } from "@calcom/prisma/zod"; -export const schemaDestinationCalendarBodyParams = DestinationCalendar.omit({ id: true }); +export const schemaDestinationCalendarBaseBodyParams = DestinationCalendar.omit({ id: true }).partial(); + +const schemaDestinationCalendarRequiredParams = z.object({ + integration: z.string(), + externalId: z.string(), +}); + +export const schemaDestinationCalendarBodyParams = schemaDestinationCalendarBaseBodyParams.merge( + schemaDestinationCalendarRequiredParams +); export const schemaDestinationCalendarPublic = DestinationCalendar.omit({}); diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts new file mode 100644 index 0000000000..113620157e --- /dev/null +++ b/lib/validations/event-type.ts @@ -0,0 +1,22 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +import { _EventTypeModel as EventType } from "@calcom/prisma/zod"; + +export const schemaEventTypeBaseBodyParams = EventType.omit({ id: true }).partial(); + +const schemaEventTypeRequiredParams = z.object({ + title: z.string(), + slug: z.string(), + length: z.number(), +}); + +export const schemaEventTypeBodyParams = schemaEventTypeBaseBodyParams.merge(schemaEventTypeRequiredParams); + +export const schemaEventTypePublic = EventType.omit({}); + +export const withValidEventType = withValidation({ + schema: schemaEventTypeBodyParams, + type: "Zod", + mode: "body", +}); diff --git a/lib/validations/eventType.ts b/lib/validations/eventType.ts deleted file mode 100644 index f257a4d0a8..0000000000 --- a/lib/validations/eventType.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { withValidation } from "next-validations"; - -import { _EventTypeModel as EventType } from "@calcom/prisma/zod"; - -export const schemaEventTypeBodyParams = EventType.omit({ id: true }); - -export const schemaEventTypePublic = EventType.omit({}); - -export const withValidEventType = withValidation({ - schema: schemaEventTypeBodyParams, - type: "Zod", - mode: "body", -}); diff --git a/lib/validations/membership.ts b/lib/validations/membership.ts index 46444e6f86..bb5d7cb7fc 100644 --- a/lib/validations/membership.ts +++ b/lib/validations/membership.ts @@ -1,8 +1,16 @@ import { withValidation } from "next-validations"; +import { z } from "zod"; import { _MembershipModel as Membership } from "@calcom/prisma/zod"; -export const schemaMembershipBodyParams = Membership.omit({}); +export const schemaMembershipBaseBodyParams = Membership.omit({}); +const schemaMembershipRequiredParams = z.object({ + teamId: z.number(), +}); + +export const schemaMembershipBodyParams = schemaMembershipBaseBodyParams.merge( + schemaMembershipRequiredParams +); export const schemaMembershipPublic = Membership.omit({}); diff --git a/lib/validations/team.ts b/lib/validations/team.ts index 010d73282a..1d484983ae 100644 --- a/lib/validations/team.ts +++ b/lib/validations/team.ts @@ -1,8 +1,15 @@ import { withValidation } from "next-validations"; +import { z } from "zod"; import { _TeamModel as Team } from "@calcom/prisma/zod"; -export const schemaTeamBodyParams = Team.omit({ id: true }).partial(); +export const schemaTeamBaseBodyParams = Team.omit({ id: true }).partial(); + +const schemaTeamRequiredParams = z.object({ + // email: z.string().email(), +}); + +export const schemaTeamBodyParams = schemaTeamBaseBodyParams.merge(schemaTeamRequiredParams); export const schemaTeamPublic = Team.omit({}); diff --git a/pages/api/api-keys/[id]/edit.ts b/pages/api/api-keys/[id]/edit.ts index bbda40f7fc..66da3539bc 100644 --- a/pages/api/api-keys/[id]/edit.ts +++ b/pages/api/api-keys/[id]/edit.ts @@ -4,7 +4,7 @@ import prisma from "@calcom/prisma"; import { ApiKey } from "@calcom/prisma/client"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { schemaApiKeyBodyParams, withValidApiKey } from "@lib/validations/apiKey"; +import { schemaApiKeyBodyParams, withValidApiKey } from "@lib/validations/api-key"; import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; type ResponseData = { diff --git a/pages/api/api-keys/new.ts b/pages/api/api-keys/new.ts index 97bd5a0b24..160324c19c 100644 --- a/pages/api/api-keys/new.ts +++ b/pages/api/api-keys/new.ts @@ -4,7 +4,7 @@ import prisma from "@calcom/prisma"; import { ApiKey } from "@calcom/prisma/client"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { schemaApiKeyBodyParams, withValidApiKey } from "@lib/validations/apiKey"; +import { schemaApiKeyBodyParams, withValidApiKey } from "@lib/validations/api-key"; type ResponseData = { data?: ApiKey; diff --git a/pages/api/event-types/[id]/edit.ts b/pages/api/event-types/[id]/edit.ts index bb181742c0..5fad6585de 100644 --- a/pages/api/event-types/[id]/edit.ts +++ b/pages/api/event-types/[id]/edit.ts @@ -8,7 +8,7 @@ import { schemaEventTypeBodyParams, schemaEventTypePublic, withValidEventType, -} from "@lib/validations/eventType"; +} from "@lib/validations/event-type"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, diff --git a/pages/api/event-types/[id]/index.ts b/pages/api/event-types/[id]/index.ts index 4e64863965..5e3ac565ae 100644 --- a/pages/api/event-types/[id]/index.ts +++ b/pages/api/event-types/[id]/index.ts @@ -4,7 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { EventTypeResponse } from "@lib/types"; -import { schemaEventTypePublic } from "@lib/validations/eventType"; +import { schemaEventTypePublic } from "@lib/validations/event-type"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index a9bd50bce7..5385f3f3c4 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -4,7 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { EventTypesResponse } from "@lib/types"; -import { schemaEventTypePublic } from "@lib/validations/eventType"; +import { schemaEventTypePublic } from "@lib/validations/event-type"; /** * @swagger diff --git a/pages/api/event-types/new.ts b/pages/api/event-types/new.ts index e0a6bf4707..847d25dd32 100644 --- a/pages/api/event-types/new.ts +++ b/pages/api/event-types/new.ts @@ -8,7 +8,7 @@ import { schemaEventTypeBodyParams, schemaEventTypePublic, withValidEventType, -} from "@lib/validations/eventType"; +} from "@lib/validations/event-type"; /** * @swagger From e8b9ec7f8a21493d036f9d858072958395d4d7d0 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 2 Apr 2022 03:47:41 +0200 Subject: [PATCH 060/658] fix: remove comment --- lib/validations/team.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/validations/team.ts b/lib/validations/team.ts index 1d484983ae..ec6cbf35ec 100644 --- a/lib/validations/team.ts +++ b/lib/validations/team.ts @@ -5,9 +5,7 @@ import { _TeamModel as Team } from "@calcom/prisma/zod"; export const schemaTeamBaseBodyParams = Team.omit({ id: true }).partial(); -const schemaTeamRequiredParams = z.object({ - // email: z.string().email(), -}); +const schemaTeamRequiredParams = z.object({}); export const schemaTeamBodyParams = schemaTeamBaseBodyParams.merge(schemaTeamRequiredParams); From d57e5920a791cb18e7f2a8e5b629560fd43aae1f Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 2 Apr 2022 03:51:33 +0200 Subject: [PATCH 061/658] chore: add tempaltes folder w endpoints and example validation for the future --- templates/endpoints/[id]/delete.ts | 50 ++++++++++++++++++++++++++ templates/endpoints/[id]/edit.ts | 56 ++++++++++++++++++++++++++++++ templates/endpoints/[id]/index.ts | 51 +++++++++++++++++++++++++++ templates/endpoints/index.ts | 37 ++++++++++++++++++++ templates/endpoints/new.ts | 48 +++++++++++++++++++++++++ templates/zod-validation.ts | 23 ++++++++++++ 6 files changed, 265 insertions(+) create mode 100644 templates/endpoints/[id]/delete.ts create mode 100644 templates/endpoints/[id]/edit.ts create mode 100644 templates/endpoints/[id]/index.ts create mode 100644 templates/endpoints/index.ts create mode 100644 templates/endpoints/new.ts create mode 100644 templates/zod-validation.ts diff --git a/templates/endpoints/[id]/delete.ts b/templates/endpoints/[id]/delete.ts new file mode 100644 index 0000000000..95049ae799 --- /dev/null +++ b/templates/endpoints/[id]/delete.ts @@ -0,0 +1,50 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BaseResponse } from "@lib/types"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /api/resources/{id}/delete: + * delete: + * summary: Remove an existing resource + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the resource to delete + * tags: + * - resources + * responses: + * 201: + * description: OK, resource removed successfuly + * model: Resource + * 400: + * description: Bad request. Resource id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteResource(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query", safe.error); + + const data = await prisma.resource.delete({ where: { id: safe.data.id } }); + + if (data) res.status(200).json({ message: `Resource with id: ${safe.data.id} deleted successfully` }); + else + (error: Error) => + res.status(400).json({ + message: `Resource with id: ${safe.data.id} was not able to be processed`, + error, + }); +} + +export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteResource)); diff --git a/templates/endpoints/[id]/edit.ts b/templates/endpoints/[id]/edit.ts new file mode 100644 index 0000000000..e4d2f382ec --- /dev/null +++ b/templates/endpoints/[id]/edit.ts @@ -0,0 +1,56 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { ResourceResponse } from "@lib/types"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaResourceBodyParams, schemaResourcePublic, withValidResource } from "@lib/validations/resource"; + +/** + * @swagger + * /api/resources/{id}/edit: + * patch: + * summary: Edit an existing resource + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the resource to edit + * tags: + * - resources + * responses: + * 201: + * description: OK, resource edited successfuly + * model: Resource + * 400: + * description: Bad request. Resource body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function editResource(req: NextApiRequest, res: NextApiResponse) { + const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); + const safeBody = await schemaResourceBodyParams.safeParse(req.body); + + if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); + const resource = await prisma.resource.update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }); + const data = schemaResourcePublic.parse(resource); + + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, + error, + }); +} + +export default withMiddleware("HTTP_PATCH")(withValidQueryIdTransformParseInt(withValidResource(editResource))); diff --git a/templates/endpoints/[id]/index.ts b/templates/endpoints/[id]/index.ts new file mode 100644 index 0000000000..0ba07d382f --- /dev/null +++ b/templates/endpoints/[id]/index.ts @@ -0,0 +1,51 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { ResourceResponse } from "@lib/types"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaResourcePublic } from "@lib/validations/resource"; + +/** + * @swagger + * /api/resources/{id}: + * get: + * summary: Get a resource by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the resource to get + * tags: + * - resources + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Resource was not found + */ +export async function resourceById(req: NextApiRequest, res: NextApiResponse) { + const safe = await schemaQueryIdParseInt.safeParse(req.query); + if (!safe.success) throw new Error("Invalid request query"); + + const resource = await prisma.resource.findUnique({ where: { id: safe.data.id } }); + const data = schemaResourcePublic.parse(resource); + + if (resource) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "Resource was not found", + error, + }); +} + +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(resourceById)); diff --git a/templates/endpoints/index.ts b/templates/endpoints/index.ts new file mode 100644 index 0000000000..4c4c98b497 --- /dev/null +++ b/templates/endpoints/index.ts @@ -0,0 +1,37 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { ResourcesResponse } from "@lib/types"; +import { schemaResourcePublic } from "@lib/validations/resource"; + +/** + * @swagger + * /api/resources: + * get: + * summary: Get all resources + * tags: + * - resources + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No resources were found + */ +async function allResources(_: NextApiRequest, res: NextApiResponse) { + const resources = await prisma.resource.findMany(); + const data = resources.map((resource) => schemaResourcePublic.parse(resource)); + + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "No Resources were found", + error, + }); +} + +export default withMiddleware("HTTP_GET")(allResources); diff --git a/templates/endpoints/new.ts b/templates/endpoints/new.ts new file mode 100644 index 0000000000..bb1b0b26d2 --- /dev/null +++ b/templates/endpoints/new.ts @@ -0,0 +1,48 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { ResourceResponse } from "@lib/types"; +import { schemaResourceBodyParams, schemaResourcePublic, withValidResource } from "@lib/validations/resource"; + +/** + * @swagger + * /api/resources/new: + * post: + * summary: Creates a new resource + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/Resource' + * tags: + * - resources + * responses: + * 201: + * description: OK, resource created + * model: Resource + * 400: + * description: Bad request. Resource body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createResource(req: NextApiRequest, res: NextApiResponse) { + const safe = schemaResourceBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); + + const resource = await prisma.resource.create({ data: safe.data }); + const data = schemaResourcePublic.parse(resource); + + if (data) res.status(201).json({ data, message: "Resource created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new resource", + error, + }); +} + +export default withMiddleware("HTTP_POST")(withValidResource(createResource)); diff --git a/templates/zod-validation.ts b/templates/zod-validation.ts new file mode 100644 index 0000000000..c200611812 --- /dev/null +++ b/templates/zod-validation.ts @@ -0,0 +1,23 @@ +// import { withValidation } from "next-validations"; +// import { z } from "zod"; + +// import { _ModelModel as Model } from "@calcom/prisma/zod"; + +// export const schemaModelBaseBodyParams = Model.omit({ id: true, userId: true, createdAt: true }).partial(); + +// const schemaModelRequiredParams = z.object({ +// email: z.string().email(), +// }); + +// export const schemaModelBodyParams = schemaModelBaseBodyParams.merge(schemaModelRequiredParams); + +// export const schemaModelPublic = Model.omit({ +// id: true, +// userId: true, +// }); + +// export const withValidModel = withValidation({ +// schema: schemaModelBodyParams, +// type: "Zod", +// mode: "body", +// }); From 61819772bc94375f4b12b9d47545a321696b391d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 3 Apr 2022 17:47:18 +0200 Subject: [PATCH 062/658] fix all swagger docs, dont build templates --- json-schema/json-schema.json | 1262 +++++++++++++++++ package.json | 4 +- pages/api/attendees/[id]/delete.ts | 2 +- pages/api/attendees/[id]/edit.ts | 2 +- pages/api/attendees/[id]/index.ts | 4 +- pages/api/attendees/new.ts | 7 - pages/api/availabilities/[id]/delete.ts | 2 +- pages/api/availabilities/[id]/edit.ts | 2 +- pages/api/availabilities/[id]/index.ts | 4 +- pages/api/availabilities/new.ts | 11 +- pages/api/booking-references/[id]/delete.ts | 4 +- pages/api/booking-references/[id]/edit.ts | 4 +- pages/api/booking-references/[id]/index.ts | 6 +- pages/api/booking-references/index.ts | 2 +- pages/api/booking-references/new.ts | 13 +- pages/api/bookings/[id]/delete.ts | 2 +- pages/api/bookings/[id]/edit.ts | 2 +- pages/api/bookings/[id]/index.ts | 4 +- pages/api/bookings/new.ts | 14 +- pages/api/credentials/[id]/delete.ts | 2 +- pages/api/credentials/[id]/edit.ts | 2 +- pages/api/credentials/[id]/index.ts | 4 +- pages/api/credentials/new.ts | 10 +- .../api/daily-event-references/[id]/delete.ts | 4 +- pages/api/daily-event-references/[id]/edit.ts | 4 +- .../api/daily-event-references/[id]/index.ts | 6 +- pages/api/daily-event-references/index.ts | 2 +- pages/api/daily-event-references/new.ts | 12 +- .../api/destination-calendars/[id]/delete.ts | 4 +- pages/api/destination-calendars/[id]/edit.ts | 4 +- pages/api/destination-calendars/[id]/index.ts | 6 +- pages/api/destination-calendars/index.ts | 2 +- pages/api/destination-calendars/new.ts | 12 +- pages/api/docs.ts | 6 +- .../event-type-custom-inputs/[id]/delete.ts | 4 +- .../api/event-type-custom-inputs/[id]/edit.ts | 4 +- .../event-type-custom-inputs/[id]/index.ts | 6 +- pages/api/event-type-custom-inputs/index.ts | 2 +- pages/api/event-type-custom-inputs/new.ts | 12 +- pages/api/event-types/[id]/delete.ts | 6 +- pages/api/event-types/[id]/edit.ts | 6 +- pages/api/event-types/[id]/index.ts | 6 +- pages/api/event-types/index.ts | 2 + pages/api/event-types/new.ts | 4 +- pages/api/memberships/[id]/delete.ts | 9 +- pages/api/memberships/[id]/index.ts | 2 +- pages/api/payments/[id]/delete.ts | 2 +- pages/api/payments/[id]/edit.ts | 2 +- pages/api/payments/[id]/index.ts | 4 +- pages/api/payments/new.ts | 10 +- pages/api/reminder-mails/[id]/delete.ts | 6 +- pages/api/reminder-mails/[id]/edit.ts | 6 +- pages/api/reminder-mails/[id]/index.ts | 6 +- pages/api/reminder-mails/index.ts | 4 +- pages/api/reminder-mails/new.ts | 14 +- pages/api/schedules/[id]/delete.ts | 2 +- pages/api/schedules/[id]/edit.ts | 2 +- pages/api/schedules/[id]/index.ts | 2 +- pages/api/selected-calendars/[id]/delete.ts | 21 +- pages/api/selected-calendars/[id]/edit.ts | 2 +- pages/api/selected-calendars/[id]/index.ts | 4 +- pages/api/selected-calendars/index.ts | 4 +- pages/api/selected-calendars/new.ts | 4 +- pages/api/teams/[id]/delete.ts | 9 +- pages/api/teams/[id]/edit.ts | 16 +- pages/api/teams/[id]/index.ts | 2 +- pages/api/users/[id]/delete.ts | 2 +- pages/api/users/[id]/edit.ts | 11 +- pages/api/users/[id]/index.ts | 16 +- pages/api/users/new.ts | 19 +- templates/zod-validation.ts | 34 +- tsconfig.json | 4 +- 72 files changed, 1501 insertions(+), 201 deletions(-) create mode 100644 json-schema/json-schema.json diff --git a/json-schema/json-schema.json b/json-schema/json-schema.json new file mode 100644 index 0000000000..220dbd101d --- /dev/null +++ b/json-schema/json-schema.json @@ -0,0 +1,1262 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "definitions": { + "EventType": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "title": { + "type": "string", + "description": "@zod.nonempty()" + }, + "slug": { + "type": "string", + "description": "@zod.custom(imports.eventTypeSlug)" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "position": { + "type": "integer", + "default": 0 + }, + "locations": { + "type": [ + "number", + "string", + "boolean", + "object", + "array", + "null" + ], + "description": "@zod.custom(imports.eventTypeLocations)" + }, + "length": { + "type": "integer" + }, + "hidden": { + "type": "boolean", + "default": false + }, + "users": { + "type": "array", + "items": { + "$ref": "#/definitions/User" + } + }, + "userId": { + "type": [ + "integer", + "null" + ] + }, + "team": { + "anyOf": [ + { + "$ref": "#/definitions/Team" + }, + { + "type": "null" + } + ] + }, + "bookings": { + "type": "array", + "items": { + "$ref": "#/definitions/Booking" + } + }, + "availability": { + "type": "array", + "items": { + "$ref": "#/definitions/Availability" + } + }, + "webhooks": { + "type": "array", + "items": { + "$ref": "#/definitions/Webhook" + } + }, + "destinationCalendar": { + "anyOf": [ + { + "$ref": "#/definitions/DestinationCalendar" + }, + { + "type": "null" + } + ] + }, + "eventName": { + "type": [ + "string", + "null" + ] + }, + "customInputs": { + "type": "array", + "items": { + "$ref": "#/definitions/EventTypeCustomInput" + } + }, + "timeZone": { + "type": [ + "string", + "null" + ] + }, + "periodType": { + "type": "string", + "default": "UNLIMITED", + "enum": [ + "UNLIMITED", + "ROLLING", + "RANGE" + ] + }, + "periodStartDate": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "periodEndDate": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "periodDays": { + "type": [ + "integer", + "null" + ] + }, + "periodCountCalendarDays": { + "type": [ + "boolean", + "null" + ] + }, + "requiresConfirmation": { + "type": "boolean", + "default": false + }, + "disableGuests": { + "type": "boolean", + "default": false + }, + "minimumBookingNotice": { + "type": "integer", + "default": 120 + }, + "beforeEventBuffer": { + "type": "integer", + "default": 0 + }, + "afterEventBuffer": { + "type": "integer", + "default": 0 + }, + "schedulingType": { + "type": [ + "string", + "null" + ], + "enum": [ + "ROUND_ROBIN", + "COLLECTIVE" + ] + }, + "schedule": { + "anyOf": [ + { + "$ref": "#/definitions/Schedule" + }, + { + "type": "null" + } + ] + }, + "price": { + "type": "integer", + "default": 0 + }, + "currency": { + "type": "string", + "default": "usd" + }, + "slotInterval": { + "type": [ + "integer", + "null" + ] + }, + "metadata": { + "type": [ + "number", + "string", + "boolean", + "object", + "array", + "null" + ] + } + } + }, + "Credential": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "key": { + "type": [ + "number", + "string", + "boolean", + "object", + "array", + "null" + ] + }, + "user": { + "anyOf": [ + { + "$ref": "#/definitions/User" + }, + { + "type": "null" + } + ] + } + } + }, + "DestinationCalendar": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "integration": { + "type": "string" + }, + "externalId": { + "type": "string" + }, + "user": { + "anyOf": [ + { + "$ref": "#/definitions/User" + }, + { + "type": "null" + } + ] + }, + "booking": { + "anyOf": [ + { + "$ref": "#/definitions/Booking" + }, + { + "type": "null" + } + ] + }, + "eventType": { + "anyOf": [ + { + "$ref": "#/definitions/EventType" + }, + { + "type": "null" + } + ] + } + } + }, + "User": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "username": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "email": { + "type": "string", + "description": "@zod.email()" + }, + "emailVerified": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "password": { + "type": [ + "string", + "null" + ] + }, + "bio": { + "type": [ + "string", + "null" + ] + }, + "avatar": { + "type": [ + "string", + "null" + ] + }, + "timeZone": { + "type": "string", + "default": "Europe/London" + }, + "weekStart": { + "type": "string", + "default": "Sunday" + }, + "startTime": { + "type": "integer", + "default": 0 + }, + "endTime": { + "type": "integer", + "default": 1440 + }, + "bufferTime": { + "type": "integer", + "default": 0 + }, + "hideBranding": { + "type": "boolean", + "default": false + }, + "theme": { + "type": [ + "string", + "null" + ] + }, + "createdDate": { + "type": "string", + "format": "date-time" + }, + "trialEndsAt": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "eventTypes": { + "type": "array", + "items": { + "$ref": "#/definitions/EventType" + } + }, + "credentials": { + "type": "array", + "items": { + "$ref": "#/definitions/Credential" + } + }, + "teams": { + "type": "array", + "items": { + "$ref": "#/definitions/Membership" + } + }, + "bookings": { + "type": "array", + "items": { + "$ref": "#/definitions/Booking" + } + }, + "schedules": { + "type": "array", + "items": { + "$ref": "#/definitions/Schedule" + } + }, + "defaultScheduleId": { + "type": [ + "integer", + "null" + ] + }, + "selectedCalendars": { + "type": "array", + "items": { + "$ref": "#/definitions/SelectedCalendar" + } + }, + "completedOnboarding": { + "type": "boolean", + "default": false + }, + "locale": { + "type": [ + "string", + "null" + ] + }, + "timeFormat": { + "type": [ + "integer", + "null" + ], + "default": 12 + }, + "twoFactorSecret": { + "type": [ + "string", + "null" + ] + }, + "twoFactorEnabled": { + "type": "boolean", + "default": false + }, + "identityProvider": { + "type": "string", + "default": "CAL", + "enum": [ + "CAL", + "GOOGLE", + "SAML" + ] + }, + "identityProviderId": { + "type": [ + "string", + "null" + ] + }, + "availability": { + "type": "array", + "items": { + "$ref": "#/definitions/Availability" + } + }, + "invitedTo": { + "type": [ + "integer", + "null" + ] + }, + "plan": { + "type": "string", + "default": "TRIAL", + "enum": [ + "FREE", + "TRIAL", + "PRO" + ] + }, + "webhooks": { + "type": "array", + "items": { + "$ref": "#/definitions/Webhook" + } + }, + "brandColor": { + "type": "string", + "default": "#292929" + }, + "darkBrandColor": { + "type": "string", + "default": "#fafafa" + }, + "destinationCalendar": { + "anyOf": [ + { + "$ref": "#/definitions/DestinationCalendar" + }, + { + "type": "null" + } + ] + }, + "away": { + "type": "boolean", + "default": false + }, + "metadata": { + "type": [ + "number", + "string", + "boolean", + "object", + "array", + "null" + ] + }, + "verified": { + "type": [ + "boolean", + "null" + ], + "default": false + }, + "apiKeys": { + "type": "array", + "items": { + "$ref": "#/definitions/ApiKey" + } + } + } + }, + "Team": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "slug": { + "type": [ + "string", + "null" + ] + }, + "logo": { + "type": [ + "string", + "null" + ] + }, + "bio": { + "type": [ + "string", + "null" + ] + }, + "hideBranding": { + "type": "boolean", + "default": false + }, + "members": { + "type": "array", + "items": { + "$ref": "#/definitions/Membership" + } + }, + "eventTypes": { + "type": "array", + "items": { + "$ref": "#/definitions/EventType" + } + } + } + }, + "Membership": { + "type": "object", + "properties": { + "accepted": { + "type": "boolean", + "default": false + }, + "role": { + "type": "string", + "enum": [ + "MEMBER", + "ADMIN", + "OWNER" + ] + }, + "team": { + "$ref": "#/definitions/Team" + }, + "user": { + "$ref": "#/definitions/User" + } + } + }, + "VerificationRequest": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "identifier": { + "type": "string" + }, + "token": { + "type": "string" + }, + "expires": { + "type": "string", + "format": "date-time" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + } + } + }, + "BookingReference": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "type": { + "type": "string" + }, + "uid": { + "type": "string" + }, + "meetingId": { + "type": [ + "string", + "null" + ] + }, + "meetingPassword": { + "type": [ + "string", + "null" + ] + }, + "meetingUrl": { + "type": [ + "string", + "null" + ] + }, + "booking": { + "anyOf": [ + { + "$ref": "#/definitions/Booking" + }, + { + "type": "null" + } + ] + } + } + }, + "Attendee": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "email": { + "type": "string" + }, + "name": { + "type": "string" + }, + "timeZone": { + "type": "string" + }, + "locale": { + "type": [ + "string", + "null" + ], + "default": "en" + }, + "booking": { + "anyOf": [ + { + "$ref": "#/definitions/Booking" + }, + { + "type": "null" + } + ] + } + } + }, + "DailyEventReference": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "dailyurl": { + "type": "string", + "default": "dailycallurl" + }, + "dailytoken": { + "type": "string", + "default": "dailytoken" + }, + "booking": { + "anyOf": [ + { + "$ref": "#/definitions/Booking" + }, + { + "type": "null" + } + ] + } + } + }, + "Booking": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "uid": { + "type": "string" + }, + "user": { + "anyOf": [ + { + "$ref": "#/definitions/User" + }, + { + "type": "null" + } + ] + }, + "references": { + "type": "array", + "items": { + "$ref": "#/definitions/BookingReference" + } + }, + "eventType": { + "anyOf": [ + { + "$ref": "#/definitions/EventType" + }, + { + "type": "null" + } + ] + }, + "title": { + "type": "string" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "startTime": { + "type": "string", + "format": "date-time" + }, + "endTime": { + "type": "string", + "format": "date-time" + }, + "attendees": { + "type": "array", + "items": { + "$ref": "#/definitions/Attendee" + } + }, + "location": { + "type": [ + "string", + "null" + ] + }, + "dailyRef": { + "anyOf": [ + { + "$ref": "#/definitions/DailyEventReference" + }, + { + "type": "null" + } + ] + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "confirmed": { + "type": "boolean", + "default": true + }, + "rejected": { + "type": "boolean", + "default": false + }, + "status": { + "type": "string", + "default": "ACCEPTED", + "enum": [ + "CANCELLED", + "ACCEPTED", + "REJECTED", + "PENDING" + ] + }, + "paid": { + "type": "boolean", + "default": false + }, + "payment": { + "type": "array", + "items": { + "$ref": "#/definitions/Payment" + } + }, + "destinationCalendar": { + "anyOf": [ + { + "$ref": "#/definitions/DestinationCalendar" + }, + { + "type": "null" + } + ] + }, + "cancellationReason": { + "type": [ + "string", + "null" + ] + }, + "rejectionReason": { + "type": [ + "string", + "null" + ] + } + } + }, + "Schedule": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "user": { + "$ref": "#/definitions/User" + }, + "eventType": { + "anyOf": [ + { + "$ref": "#/definitions/EventType" + }, + { + "type": "null" + } + ] + }, + "name": { + "type": "string" + }, + "timeZone": { + "type": [ + "string", + "null" + ] + }, + "availability": { + "type": "array", + "items": { + "$ref": "#/definitions/Availability" + } + } + } + }, + "Availability": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "user": { + "anyOf": [ + { + "$ref": "#/definitions/User" + }, + { + "type": "null" + } + ] + }, + "eventType": { + "anyOf": [ + { + "$ref": "#/definitions/EventType" + }, + { + "type": "null" + } + ] + }, + "days": { + "type": "array", + "items": { + "type": "integer" + } + }, + "startTime": { + "type": "string", + "format": "date-time" + }, + "endTime": { + "type": "string", + "format": "date-time" + }, + "date": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "Schedule": { + "anyOf": [ + { + "$ref": "#/definitions/Schedule" + }, + { + "type": "null" + } + ] + } + } + }, + "SelectedCalendar": { + "type": "object", + "properties": { + "user": { + "$ref": "#/definitions/User" + }, + "integration": { + "type": "string" + }, + "externalId": { + "type": "string" + } + } + }, + "EventTypeCustomInput": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "eventType": { + "$ref": "#/definitions/EventType" + }, + "label": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "TEXT", + "TEXTLONG", + "NUMBER", + "BOOL" + ] + }, + "required": { + "type": "boolean" + }, + "placeholder": { + "type": "string", + "default": "" + } + } + }, + "ResetPasswordRequest": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "updatedAt": { + "type": "string", + "format": "date-time" + }, + "email": { + "type": "string" + }, + "expires": { + "type": "string", + "format": "date-time" + } + } + }, + "ReminderMail": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "referenceId": { + "type": "integer" + }, + "reminderType": { + "type": "string", + "enum": [ + "PENDING_BOOKING_CONFIRMATION" + ] + }, + "elapsedMinutes": { + "type": "integer" + }, + "createdAt": { + "type": "string", + "format": "date-time" + } + } + }, + "Payment": { + "type": "object", + "properties": { + "id": { + "type": "integer" + }, + "uid": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "STRIPE" + ] + }, + "booking": { + "anyOf": [ + { + "$ref": "#/definitions/Booking" + }, + { + "type": "null" + } + ] + }, + "amount": { + "type": "integer" + }, + "fee": { + "type": "integer" + }, + "currency": { + "type": "string" + }, + "success": { + "type": "boolean" + }, + "refunded": { + "type": "boolean" + }, + "data": { + "type": [ + "number", + "string", + "boolean", + "object", + "array", + "null" + ] + }, + "externalId": { + "type": "string" + } + } + }, + "Webhook": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "subscriberUrl": { + "type": "string" + }, + "payloadTemplate": { + "type": [ + "string", + "null" + ] + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "active": { + "type": "boolean", + "default": true + }, + "eventTriggers": { + "type": "array", + "enum": [ + "BOOKING_CREATED", + "BOOKING_RESCHEDULED", + "BOOKING_CANCELLED" + ] + }, + "user": { + "anyOf": [ + { + "$ref": "#/definitions/User" + }, + { + "type": "null" + } + ] + }, + "eventType": { + "anyOf": [ + { + "$ref": "#/definitions/EventType" + }, + { + "type": "null" + } + ] + } + } + }, + "ApiKey": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "user": { + "anyOf": [ + { + "$ref": "#/definitions/User" + }, + { + "type": "null" + } + ] + }, + "createdAt": { + "type": "string", + "format": "date-time" + }, + "expiresAt": { + "type": "string", + "format": "date-time" + }, + "note": { + "type": [ + "string", + "null" + ] + } + } + } + }, + "type": "object", + "properties": { + "eventType": { + "$ref": "#/definitions/EventType" + }, + "credential": { + "$ref": "#/definitions/Credential" + }, + "destinationCalendar": { + "$ref": "#/definitions/DestinationCalendar" + }, + "user": { + "$ref": "#/definitions/User" + }, + "team": { + "$ref": "#/definitions/Team" + }, + "membership": { + "$ref": "#/definitions/Membership" + }, + "verificationRequest": { + "$ref": "#/definitions/VerificationRequest" + }, + "bookingReference": { + "$ref": "#/definitions/BookingReference" + }, + "attendee": { + "$ref": "#/definitions/Attendee" + }, + "dailyEventReference": { + "$ref": "#/definitions/DailyEventReference" + }, + "booking": { + "$ref": "#/definitions/Booking" + }, + "schedule": { + "$ref": "#/definitions/Schedule" + }, + "availability": { + "$ref": "#/definitions/Availability" + }, + "selectedCalendar": { + "$ref": "#/definitions/SelectedCalendar" + }, + "eventTypeCustomInput": { + "$ref": "#/definitions/EventTypeCustomInput" + }, + "resetPasswordRequest": { + "$ref": "#/definitions/ResetPasswordRequest" + }, + "reminderMail": { + "$ref": "#/definitions/ReminderMail" + }, + "payment": { + "$ref": "#/definitions/Payment" + }, + "webhook": { + "$ref": "#/definitions/Webhook" + }, + "apiKey": { + "$ref": "#/definitions/ApiKey" + } + } +} \ No newline at end of file diff --git a/package.json b/package.json index 8507464bf3..16dc0f9b9f 100644 --- a/package.json +++ b/package.json @@ -32,8 +32,8 @@ "prettier": "^2.6.1" }, "dependencies": { - "@sentry/nextjs": "^6.19.2", - "next": "^12.1.0", + "@sentry/nextjs": "^6.19.3", + "next": "^12.1.4", "next-api-middleware": "^1.0.1", "next-swagger-doc": "^0.2.1", "next-transpile-modules": "^9.0.0", diff --git a/pages/api/attendees/[id]/delete.ts b/pages/api/attendees/[id]/delete.ts index 59cf150af5..25e0818960 100644 --- a/pages/api/attendees/[id]/delete.ts +++ b/pages/api/attendees/[id]/delete.ts @@ -14,7 +14,7 @@ import { * /api/attendees/{id}/delete: * delete: * summary: Remove an existing attendee - * parameters: + * parameters: * - in: path * name: id * schema: diff --git a/pages/api/attendees/[id]/edit.ts b/pages/api/attendees/[id]/edit.ts index 0f0d5f2e0c..dab8ed979c 100644 --- a/pages/api/attendees/[id]/edit.ts +++ b/pages/api/attendees/[id]/edit.ts @@ -15,7 +15,7 @@ import { * /api/attendees/{id}/edit: * patch: * summary: Edit an existing attendee - * parameters: + * parameters: * - in: path * name: id * schema: diff --git a/pages/api/attendees/[id]/index.ts b/pages/api/attendees/[id]/index.ts index 6fe39d540c..81f9ead1bd 100644 --- a/pages/api/attendees/[id]/index.ts +++ b/pages/api/attendees/[id]/index.ts @@ -14,8 +14,8 @@ import { * @swagger * /api/attendees/{id}: * get: - * summary: Get a attendee by ID - * parameters: + * summary: Get a attendee by ID + * parameters: * - in: path * name: id * schema: diff --git a/pages/api/attendees/new.ts b/pages/api/attendees/new.ts index 7825755b0e..b934e5b62d 100644 --- a/pages/api/attendees/new.ts +++ b/pages/api/attendees/new.ts @@ -11,13 +11,6 @@ import { schemaAttendeeBodyParams, schemaAttendeePublic, withValidAttendee } fro * /api/attendees/new: * post: * summary: Creates a new attendee - * requestBody: - * description: Optional description in *Markdown* - * required: true - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/Attendee' * tags: * - attendees * responses: diff --git a/pages/api/availabilities/[id]/delete.ts b/pages/api/availabilities/[id]/delete.ts index 1601b014a1..a23f5e9792 100644 --- a/pages/api/availabilities/[id]/delete.ts +++ b/pages/api/availabilities/[id]/delete.ts @@ -14,7 +14,7 @@ import { * /api/availabilites/{id}/delete: * delete: * summary: Remove an existing availability - * parameters: + * parameters: * - in: path * name: id * schema: diff --git a/pages/api/availabilities/[id]/edit.ts b/pages/api/availabilities/[id]/edit.ts index e530090a43..2aeb92dee2 100644 --- a/pages/api/availabilities/[id]/edit.ts +++ b/pages/api/availabilities/[id]/edit.ts @@ -19,7 +19,7 @@ import { * /api/availabilites/{id}/edit: * patch: * summary: Edit an existing availability - * parameters: + * parameters: * - in: path * name: id * schema: diff --git a/pages/api/availabilities/[id]/index.ts b/pages/api/availabilities/[id]/index.ts index 22e160e436..054c32ee9f 100644 --- a/pages/api/availabilities/[id]/index.ts +++ b/pages/api/availabilities/[id]/index.ts @@ -14,8 +14,8 @@ import { * @swagger * /api/availabilites/{id}: * get: - * summary: Get a availability by ID - * parameters: + * summary: Get a availability by ID + * parameters: * - in: path * name: id * schema: diff --git a/pages/api/availabilities/new.ts b/pages/api/availabilities/new.ts index 2e3587e551..d049a42ded 100644 --- a/pages/api/availabilities/new.ts +++ b/pages/api/availabilities/new.ts @@ -15,11 +15,11 @@ import { * /api/availabilites/new: * post: * summary: Creates a new availability - * requestBody: - * description: Optional description in *Markdown* - * required: true - * content: - * application/json: + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: * schema: * $ref: '#/components/schemas/Availability' * tags: @@ -27,7 +27,6 @@ import { * responses: * 201: * description: OK, availability created - * model: Availability * 400: * description: Bad request. Availability body is invalid. * 401: diff --git a/pages/api/booking-references/[id]/delete.ts b/pages/api/booking-references/[id]/delete.ts index 0a49d82d21..1fb0f32eb2 100644 --- a/pages/api/booking-references/[id]/delete.ts +++ b/pages/api/booking-references/[id]/delete.ts @@ -14,7 +14,7 @@ import { * /api/booking-references/{id}/delete: * delete: * summary: Remove an existing bookingReference - * parameters: + * parameters: * - in: path * name: id * schema: @@ -22,7 +22,7 @@ import { * required: true * description: Numeric ID of the bookingReference to delete * tags: - * - bookingReferences + * - booking-references * responses: * 201: * description: OK, bookingReference removed successfuly diff --git a/pages/api/booking-references/[id]/edit.ts b/pages/api/booking-references/[id]/edit.ts index 3d05537514..60c5d53316 100644 --- a/pages/api/booking-references/[id]/edit.ts +++ b/pages/api/booking-references/[id]/edit.ts @@ -19,7 +19,7 @@ import { * /api/booking-references/{id}/edit: * patch: * summary: Edit an existing bookingReference - * parameters: + * parameters: * - in: path * name: id * schema: @@ -27,7 +27,7 @@ import { * required: true * description: Numeric ID of the bookingReference to edit * tags: - * - bookingReferences + * - booking-references * responses: * 201: * description: OK, bookingReference edited successfuly diff --git a/pages/api/booking-references/[id]/index.ts b/pages/api/booking-references/[id]/index.ts index ee6f7c8e84..e71f6920d7 100644 --- a/pages/api/booking-references/[id]/index.ts +++ b/pages/api/booking-references/[id]/index.ts @@ -14,8 +14,8 @@ import { * @swagger * /api/booking-references/{id}: * get: - * summary: Get a bookingReference by ID - * parameters: + * summary: Get a bookingReference by ID + * parameters: * - in: path * name: id * schema: @@ -23,7 +23,7 @@ import { * required: true * description: Numeric ID of the bookingReference to get * tags: - * - bookingReferences + * - booking-references * responses: * 200: * description: OK diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index c1c4afc9dc..312ccf4b78 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -12,7 +12,7 @@ import { schemaBookingReferencePublic } from "@lib/validations/booking-reference * get: * summary: Get all bookingReferences * tags: - * - bookingReferences + * - booking-references * responses: * 200: * description: OK diff --git a/pages/api/booking-references/new.ts b/pages/api/booking-references/new.ts index 5430206cde..737156ae3f 100644 --- a/pages/api/booking-references/new.ts +++ b/pages/api/booking-references/new.ts @@ -15,19 +15,18 @@ import { * /api/booking-references/new: * post: * summary: Creates a new bookingReference - * requestBody: - * description: Optional description in *Markdown* - * required: true - * content: - * application/json: + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: * schema: * $ref: '#/components/schemas/BookingReference' * tags: - * - bookingReferences + * - booking-references * responses: * 201: * description: OK, bookingReference created - * model: BookingReference * 400: * description: Bad request. BookingReference body is invalid. * 401: diff --git a/pages/api/bookings/[id]/delete.ts b/pages/api/bookings/[id]/delete.ts index 5d6e58d656..3905a93b03 100644 --- a/pages/api/bookings/[id]/delete.ts +++ b/pages/api/bookings/[id]/delete.ts @@ -14,7 +14,7 @@ import { * /api/bookings/{id}/delete: * delete: * summary: Remove an existing booking - * parameters: + * parameters: * - in: path * name: id * schema: diff --git a/pages/api/bookings/[id]/edit.ts b/pages/api/bookings/[id]/edit.ts index 3e12bdaa86..fffc48c221 100644 --- a/pages/api/bookings/[id]/edit.ts +++ b/pages/api/bookings/[id]/edit.ts @@ -15,7 +15,7 @@ import { * /api/bookings/{id}/edit: * patch: * summary: Edit an existing booking - * parameters: + * parameters: * - in: path * name: id * schema: diff --git a/pages/api/bookings/[id]/index.ts b/pages/api/bookings/[id]/index.ts index fab8940978..c2b47d737f 100644 --- a/pages/api/bookings/[id]/index.ts +++ b/pages/api/bookings/[id]/index.ts @@ -14,8 +14,8 @@ import { * @swagger * /api/bookings/{id}: * get: - * summary: Get a booking by ID - * parameters: + * summary: Get a booking by ID + * parameters: * - in: path * name: id * schema: diff --git a/pages/api/bookings/new.ts b/pages/api/bookings/new.ts index 4e62b0e531..3e10e1c143 100644 --- a/pages/api/bookings/new.ts +++ b/pages/api/bookings/new.ts @@ -11,13 +11,13 @@ import { schemaBookingBodyParams, schemaBookingPublic, withValidBooking } from " * /api/bookings/new: * post: * summary: Creates a new booking - * requestBody: - * description: Optional description in *Markdown* - * required: true - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/Booking' + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: + * schema: + * $ref: '#/components/schemas/Booking' * tags: * - bookings * responses: diff --git a/pages/api/credentials/[id]/delete.ts b/pages/api/credentials/[id]/delete.ts index e97e78d07c..49e4918792 100644 --- a/pages/api/credentials/[id]/delete.ts +++ b/pages/api/credentials/[id]/delete.ts @@ -14,7 +14,7 @@ import { * /api/credentials/{id}/delete: * delete: * summary: Remove an existing credential - * parameters: + * parameters: * - in: path * name: id * schema: diff --git a/pages/api/credentials/[id]/edit.ts b/pages/api/credentials/[id]/edit.ts index 5febf03067..69883de41e 100644 --- a/pages/api/credentials/[id]/edit.ts +++ b/pages/api/credentials/[id]/edit.ts @@ -19,7 +19,7 @@ import { * /api/credentials/{id}/edit: * patch: * summary: Edit an existing credential - * parameters: + * parameters: * - in: path * name: id * schema: diff --git a/pages/api/credentials/[id]/index.ts b/pages/api/credentials/[id]/index.ts index 9686700a17..f20fa4ba5c 100644 --- a/pages/api/credentials/[id]/index.ts +++ b/pages/api/credentials/[id]/index.ts @@ -14,8 +14,8 @@ import { * @swagger * /api/credentials/{id}: * get: - * summary: Get a credential by ID - * parameters: + * summary: Get a credential by ID + * parameters: * - in: path * name: id * schema: diff --git a/pages/api/credentials/new.ts b/pages/api/credentials/new.ts index 265f17d3cd..39302c7a1d 100644 --- a/pages/api/credentials/new.ts +++ b/pages/api/credentials/new.ts @@ -15,11 +15,11 @@ import { * /api/credentials/new: * post: * summary: Creates a new credential - * requestBody: - * description: Optional description in *Markdown* - * required: true - * content: - * application/json: + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: * schema: * $ref: '#/components/schemas/Credential' * tags: diff --git a/pages/api/daily-event-references/[id]/delete.ts b/pages/api/daily-event-references/[id]/delete.ts index 71b61d86c4..1e020c65ff 100644 --- a/pages/api/daily-event-references/[id]/delete.ts +++ b/pages/api/daily-event-references/[id]/delete.ts @@ -14,7 +14,7 @@ import { * /api/daily-event-references/{id}/delete: * delete: * summary: Remove an existing dailyEventReference - * parameters: + * parameters: * - in: path * name: id * schema: @@ -22,7 +22,7 @@ import { * required: true * description: Numeric ID of the dailyEventReference to delete * tags: - * - dailyEventReferences + * - daily-event-references * responses: * 201: * description: OK, dailyEventReference removed successfuly diff --git a/pages/api/daily-event-references/[id]/edit.ts b/pages/api/daily-event-references/[id]/edit.ts index e3d9f73765..b090962717 100644 --- a/pages/api/daily-event-references/[id]/edit.ts +++ b/pages/api/daily-event-references/[id]/edit.ts @@ -19,7 +19,7 @@ import { * /api/daily-event-references/{id}/edit: * patch: * summary: Edit an existing dailyEventReference - * parameters: + * parameters: * - in: path * name: id * schema: @@ -27,7 +27,7 @@ import { * required: true * description: Numeric ID of the dailyEventReference to edit * tags: - * - dailyEventReferences + * - daily-event-references * responses: * 201: * description: OK, dailyEventReference edited successfuly diff --git a/pages/api/daily-event-references/[id]/index.ts b/pages/api/daily-event-references/[id]/index.ts index 338a64470c..2ff523bc41 100644 --- a/pages/api/daily-event-references/[id]/index.ts +++ b/pages/api/daily-event-references/[id]/index.ts @@ -14,8 +14,8 @@ import { * @swagger * /api/daily-event-references/{id}: * get: - * summary: Get a dailyEventReference by ID - * parameters: + * summary: Get a dailyEventReference by ID + * parameters: * - in: path * name: id * schema: @@ -23,7 +23,7 @@ import { * required: true * description: Numeric ID of the dailyEventReference to get * tags: - * - dailyEventReferences + * - daily-event-references * responses: * 200: * description: OK diff --git a/pages/api/daily-event-references/index.ts b/pages/api/daily-event-references/index.ts index 774d39358c..d4495ef0f1 100644 --- a/pages/api/daily-event-references/index.ts +++ b/pages/api/daily-event-references/index.ts @@ -12,7 +12,7 @@ import { schemaDailyEventReferencePublic } from "@lib/validations/daily-event-re * get: * summary: Get all dailyEventReferences * tags: - * - dailyEventReferences + * - daily-event-references * responses: * 200: * description: OK diff --git a/pages/api/daily-event-references/new.ts b/pages/api/daily-event-references/new.ts index baf5e83d10..1e61a7fa59 100644 --- a/pages/api/daily-event-references/new.ts +++ b/pages/api/daily-event-references/new.ts @@ -15,15 +15,15 @@ import { * /api/daily-event-references/new: * post: * summary: Creates a new dailyEventReference - * requestBody: - * description: Optional description in *Markdown* - * required: true - * content: - * application/json: + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: * schema: * $ref: '#/components/schemas/DailyEventReference' * tags: - * - dailyEventReferences + * - daily-event-references * responses: * 201: * description: OK, dailyEventReference created diff --git a/pages/api/destination-calendars/[id]/delete.ts b/pages/api/destination-calendars/[id]/delete.ts index 2573532efd..1bf35128f9 100644 --- a/pages/api/destination-calendars/[id]/delete.ts +++ b/pages/api/destination-calendars/[id]/delete.ts @@ -14,7 +14,7 @@ import { * /api/destination-calendars/{id}/delete: * delete: * summary: Remove an existing destinationCalendar - * parameters: + * parameters: * - in: path * name: id * schema: @@ -22,7 +22,7 @@ import { * required: true * description: Numeric ID of the destinationCalendar to delete * tags: - * - destinationCalendars + * - destination-calendars * responses: * 201: * description: OK, destinationCalendar removed successfuly diff --git a/pages/api/destination-calendars/[id]/edit.ts b/pages/api/destination-calendars/[id]/edit.ts index 9dc4ae38fb..ab09db2f4d 100644 --- a/pages/api/destination-calendars/[id]/edit.ts +++ b/pages/api/destination-calendars/[id]/edit.ts @@ -19,7 +19,7 @@ import { * /api/destination-calendars/{id}/edit: * patch: * summary: Edit an existing destinationCalendar - * parameters: + * parameters: * - in: path * name: id * schema: @@ -27,7 +27,7 @@ import { * required: true * description: Numeric ID of the destinationCalendar to edit * tags: - * - destinationCalendars + * - destination-calendars * responses: * 201: * description: OK, destinationCalendar edited successfuly diff --git a/pages/api/destination-calendars/[id]/index.ts b/pages/api/destination-calendars/[id]/index.ts index 2639e70538..4a7474ff7c 100644 --- a/pages/api/destination-calendars/[id]/index.ts +++ b/pages/api/destination-calendars/[id]/index.ts @@ -14,8 +14,8 @@ import { * @swagger * /api/destination-calendars/{id}: * get: - * summary: Get a destinationCalendar by ID - * parameters: + * summary: Get a destinationCalendar by ID + * parameters: * - in: path * name: id * schema: @@ -23,7 +23,7 @@ import { * required: true * description: Numeric ID of the destinationCalendar to get * tags: - * - destinationCalendars + * - destination-calendars * responses: * 200: * description: OK diff --git a/pages/api/destination-calendars/index.ts b/pages/api/destination-calendars/index.ts index 6f1a9147dd..fc3493bf28 100644 --- a/pages/api/destination-calendars/index.ts +++ b/pages/api/destination-calendars/index.ts @@ -12,7 +12,7 @@ import { schemaDestinationCalendarPublic } from "@lib/validations/destination-ca * get: * summary: Get all destinationCalendars * tags: - * - destinationCalendars + * - destination-calendars * responses: * 200: * description: OK diff --git a/pages/api/destination-calendars/new.ts b/pages/api/destination-calendars/new.ts index 896be9f06a..eac1e2e110 100644 --- a/pages/api/destination-calendars/new.ts +++ b/pages/api/destination-calendars/new.ts @@ -15,15 +15,15 @@ import { * /api/destination-calendars/new: * post: * summary: Creates a new destinationCalendar - * requestBody: - * description: Optional description in *Markdown* - * required: true - * content: - * application/json: + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: * schema: * $ref: '#/components/schemas/DestinationCalendar' * tags: - * - destinationCalendars + * - destination-calendars * responses: * 201: * description: OK, destinationCalendar created diff --git a/pages/api/docs.ts b/pages/api/docs.ts index 8e489785bd..d9aa75d18c 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -1,3 +1,4 @@ +import jsonSchema from "@/json-schema/json-schema.json"; import pjson from "@/package.json"; import { withSwagger } from "next-swagger-doc"; @@ -8,8 +9,11 @@ const swaggerHandler = withSwagger({ title: `${pjson.name}: ${pjson.description}`, version: pjson.version, }, - tags: ["users", "teams"], + components: { schemas: { ...jsonSchema.definitions } }, + definitions: jsonSchema.definitions, }, apiFolder: "pages/api", + tags: ["users", "teams", "memeberships"], + sort: true, }); export default swaggerHandler(); diff --git a/pages/api/event-type-custom-inputs/[id]/delete.ts b/pages/api/event-type-custom-inputs/[id]/delete.ts index 94c6bb2610..e9064dd69d 100644 --- a/pages/api/event-type-custom-inputs/[id]/delete.ts +++ b/pages/api/event-type-custom-inputs/[id]/delete.ts @@ -14,7 +14,7 @@ import { * /api/event-type-custom-inputs/{id}/delete: * delete: * summary: Remove an existing eventTypeCustomInput - * parameters: + * parameters: * - in: path * name: id * schema: @@ -22,7 +22,7 @@ import { * required: true * description: Numeric ID of the eventTypeCustomInput to delete * tags: - * - eventTypeCustomInputs + * - event-type-custom-inputs * responses: * 201: * description: OK, eventTypeCustomInput removed successfuly diff --git a/pages/api/event-type-custom-inputs/[id]/edit.ts b/pages/api/event-type-custom-inputs/[id]/edit.ts index c95d4aa876..0357d22aff 100644 --- a/pages/api/event-type-custom-inputs/[id]/edit.ts +++ b/pages/api/event-type-custom-inputs/[id]/edit.ts @@ -19,7 +19,7 @@ import { * /api/event-type-custom-inputs/{id}/edit: * patch: * summary: Edit an existing eventTypeCustomInput - * parameters: + * parameters: * - in: path * name: id * schema: @@ -27,7 +27,7 @@ import { * required: true * description: Numeric ID of the eventTypeCustomInput to edit * tags: - * - eventTypeCustomInputs + * - event-type-custom-inputs * responses: * 201: * description: OK, eventTypeCustomInput edited successfuly diff --git a/pages/api/event-type-custom-inputs/[id]/index.ts b/pages/api/event-type-custom-inputs/[id]/index.ts index 5ceea367b4..b99b067b9e 100644 --- a/pages/api/event-type-custom-inputs/[id]/index.ts +++ b/pages/api/event-type-custom-inputs/[id]/index.ts @@ -14,8 +14,8 @@ import { * @swagger * /api/event-type-custom-inputs/{id}: * get: - * summary: Get a eventTypeCustomInput by ID - * parameters: + * summary: Get a eventTypeCustomInput by ID + * parameters: * - in: path * name: id * schema: @@ -23,7 +23,7 @@ import { * required: true * description: Numeric ID of the eventTypeCustomInput to get * tags: - * - eventTypeCustomInputs + * - event-type-custom-inputs * responses: * 200: * description: OK diff --git a/pages/api/event-type-custom-inputs/index.ts b/pages/api/event-type-custom-inputs/index.ts index 689d23c7ae..d1c8e3ad90 100644 --- a/pages/api/event-type-custom-inputs/index.ts +++ b/pages/api/event-type-custom-inputs/index.ts @@ -12,7 +12,7 @@ import { schemaEventTypeCustomInputPublic } from "@lib/validations/event-type-cu * get: * summary: Get all eventTypeCustomInputs * tags: - * - eventTypeCustomInputs + * - event-type-custom-inputs * responses: * 200: * description: OK diff --git a/pages/api/event-type-custom-inputs/new.ts b/pages/api/event-type-custom-inputs/new.ts index 165ed6cd20..3d64c296dd 100644 --- a/pages/api/event-type-custom-inputs/new.ts +++ b/pages/api/event-type-custom-inputs/new.ts @@ -15,15 +15,15 @@ import { * /api/event-type-custom-inputs/new: * post: * summary: Creates a new eventTypeCustomInput - * requestBody: - * description: Optional description in *Markdown* - * required: true - * content: - * application/json: + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: * schema: * $ref: '#/components/schemas/EventTypeCustomInput' * tags: - * - eventTypeCustomInputs + * - event-type-custom-inputs * responses: * 201: * description: OK, eventTypeCustomInput created diff --git a/pages/api/event-types/[id]/delete.ts b/pages/api/event-types/[id]/delete.ts index ce83548f73..1009a97e05 100644 --- a/pages/api/event-types/[id]/delete.ts +++ b/pages/api/event-types/[id]/delete.ts @@ -11,10 +11,10 @@ import { /** * @swagger - * /api/eventTypes/{id}/delete: + * /api/event-types/{id}/delete: * delete: * summary: Remove an existing eventType - * parameters: + * parameters: * - in: path * name: id * schema: @@ -22,7 +22,7 @@ import { * required: true * description: Numeric ID of the eventType to delete * tags: - * - eventTypes + * - event-types * responses: * 201: * description: OK, eventType removed successfuly diff --git a/pages/api/event-types/[id]/edit.ts b/pages/api/event-types/[id]/edit.ts index 5fad6585de..785774c0b6 100644 --- a/pages/api/event-types/[id]/edit.ts +++ b/pages/api/event-types/[id]/edit.ts @@ -16,10 +16,10 @@ import { /** * @swagger - * /api/eventTypes/{id}/edit: + * /api/event-types/{id}/edit: * patch: * summary: Edits an existing eventType - * parameters: + * parameters: * - in: path * name: id * schema: @@ -27,7 +27,7 @@ import { * required: true * description: Numeric ID of the eventType to delete * tags: - * - eventTypes + * - event-types * responses: * 201: * description: OK, eventType edited successfuly diff --git a/pages/api/event-types/[id]/index.ts b/pages/api/event-types/[id]/index.ts index 5e3ac565ae..645708813d 100644 --- a/pages/api/event-types/[id]/index.ts +++ b/pages/api/event-types/[id]/index.ts @@ -12,16 +12,18 @@ import { /** * @swagger - * /api/eventTypes/{id}: + * /api/event-types/{id}: * get: * summary: find eventType by ID - * parameters: + * parameters: * - in: path * name: id * schema: * type: integer * required: true * description: Numeric ID of the eventType to get + * tags: + * - event-types * responses: * 200: * description: OK diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 5385f3f3c4..a626490919 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -11,6 +11,8 @@ import { schemaEventTypePublic } from "@lib/validations/event-type"; * /api/eventTypes: * get: * summary: Returns all eventTypes + * tags: + * - event-types * responses: * 200: * description: OK diff --git a/pages/api/event-types/new.ts b/pages/api/event-types/new.ts index 847d25dd32..491057c453 100644 --- a/pages/api/event-types/new.ts +++ b/pages/api/event-types/new.ts @@ -12,9 +12,11 @@ import { /** * @swagger - * /api/eventTypes/new: + * /api/event-types/new: * post: * summary: Creates a new eventType + * tags: + * - event-types * responses: * 201: * description: OK, eventType created diff --git a/pages/api/memberships/[id]/delete.ts b/pages/api/memberships/[id]/delete.ts index b33148e6d6..8eb4e8ae4a 100644 --- a/pages/api/memberships/[id]/delete.ts +++ b/pages/api/memberships/[id]/delete.ts @@ -11,14 +11,15 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * /api/memberships/{userId}_{teamId}/delete: * delete: * summary: Remove an existing membership - * parameters: - * - in: path - * - name: userId + * parameters: + * - in: path + * name: userId * schema: * type: integer * required: true * description: Numeric ID of the user to get the membership of - * * - name: teamId + * - in: path + * name: teamId * schema: * type: integer * required: true diff --git a/pages/api/memberships/[id]/index.ts b/pages/api/memberships/[id]/index.ts index 5bc5f79496..a1505f185e 100644 --- a/pages/api/memberships/[id]/index.ts +++ b/pages/api/memberships/[id]/index.ts @@ -12,7 +12,7 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * /api/memberships/{userId}_{teamId}: * get: * summary: find membership by userID and teamID - * parameters: + * parameters: * - in: path * name: userId * schema: diff --git a/pages/api/payments/[id]/delete.ts b/pages/api/payments/[id]/delete.ts index 2367f463b0..104fbb0da9 100644 --- a/pages/api/payments/[id]/delete.ts +++ b/pages/api/payments/[id]/delete.ts @@ -14,7 +14,7 @@ import { * /api/payments/{id}/delete: * delete: * summary: Remove an existing payment - * parameters: + * parameters: * - in: path * name: id * schema: diff --git a/pages/api/payments/[id]/edit.ts b/pages/api/payments/[id]/edit.ts index f0f38b5efd..6b1549d66a 100644 --- a/pages/api/payments/[id]/edit.ts +++ b/pages/api/payments/[id]/edit.ts @@ -15,7 +15,7 @@ import { * /api/payments/{id}/edit: * patch: * summary: Edit an existing payment - * parameters: + * parameters: * - in: path * name: id * schema: diff --git a/pages/api/payments/[id]/index.ts b/pages/api/payments/[id]/index.ts index ea5039cf43..5d4fa9547a 100644 --- a/pages/api/payments/[id]/index.ts +++ b/pages/api/payments/[id]/index.ts @@ -14,8 +14,8 @@ import { * @swagger * /api/payments/{id}: * get: - * summary: Get a payment by ID - * parameters: + * summary: Get a payment by ID + * parameters: * - in: path * name: id * schema: diff --git a/pages/api/payments/new.ts b/pages/api/payments/new.ts index dca0099e48..1886270fe2 100644 --- a/pages/api/payments/new.ts +++ b/pages/api/payments/new.ts @@ -11,11 +11,11 @@ import { schemaPaymentBodyParams, schemaPaymentPublic, withValidPayment } from " * /api/payments/new: * post: * summary: Creates a new payment - * requestBody: - * description: Optional description in *Markdown* - * required: true - * content: - * application/json: + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: * schema: * $ref: '#/components/schemas/Payment' * tags: diff --git a/pages/api/reminder-mails/[id]/delete.ts b/pages/api/reminder-mails/[id]/delete.ts index 3211a4fa9d..6b3bad4fe9 100644 --- a/pages/api/reminder-mails/[id]/delete.ts +++ b/pages/api/reminder-mails/[id]/delete.ts @@ -13,8 +13,8 @@ import { * @swagger * /api/reminder-mails/{id}/delete: * delete: - * summary: Remove an existing reminderMail - * parameters: + * summary: Remove an existing reminder mail + * parameters: * - in: path * name: id * schema: @@ -22,7 +22,7 @@ import { * required: true * description: Numeric ID of the reminderMail to delete * tags: - * - reminderMails + * - reminder-mails * responses: * 201: * description: OK, reminderMail removed successfuly diff --git a/pages/api/reminder-mails/[id]/edit.ts b/pages/api/reminder-mails/[id]/edit.ts index 802381bd1c..2fedbb8f86 100644 --- a/pages/api/reminder-mails/[id]/edit.ts +++ b/pages/api/reminder-mails/[id]/edit.ts @@ -18,8 +18,8 @@ import { * @swagger * /api/reminder-mails/{id}/edit: * patch: - * summary: Edit an existing reminderMail - * parameters: + * summary: Edit an existing reminder mail + * parameters: * - in: path * name: id * schema: @@ -27,7 +27,7 @@ import { * required: true * description: Numeric ID of the reminderMail to edit * tags: - * - reminderMails + * - reminder-mails * responses: * 201: * description: OK, reminderMail edited successfuly diff --git a/pages/api/reminder-mails/[id]/index.ts b/pages/api/reminder-mails/[id]/index.ts index 3554f87b64..7b38d22cbe 100644 --- a/pages/api/reminder-mails/[id]/index.ts +++ b/pages/api/reminder-mails/[id]/index.ts @@ -14,8 +14,8 @@ import { * @swagger * /api/reminder-mails/{id}: * get: - * summary: Get a reminderMail by ID - * parameters: + * summary: Get a reminder mail by ID + * parameters: * - in: path * name: id * schema: @@ -23,7 +23,7 @@ import { * required: true * description: Numeric ID of the reminderMail to get * tags: - * - reminderMails + * - reminder-mails * responses: * 200: * description: OK diff --git a/pages/api/reminder-mails/index.ts b/pages/api/reminder-mails/index.ts index 546dc58dc7..3a847def6b 100644 --- a/pages/api/reminder-mails/index.ts +++ b/pages/api/reminder-mails/index.ts @@ -10,9 +10,9 @@ import { schemaReminderMailPublic } from "@lib/validations/reminder-mail"; * @swagger * /api/reminder-mails: * get: - * summary: Get all reminderMails + * summary: Get all reminder mails * tags: - * - reminderMails + * - reminder-mails * responses: * 200: * description: OK diff --git a/pages/api/reminder-mails/new.ts b/pages/api/reminder-mails/new.ts index 85afef2a34..dd82b7a78e 100644 --- a/pages/api/reminder-mails/new.ts +++ b/pages/api/reminder-mails/new.ts @@ -14,16 +14,16 @@ import { * @swagger * /api/reminder-mails/new: * post: - * summary: Creates a new reminderMail - * requestBody: - * description: Optional description in *Markdown* - * required: true - * content: - * application/json: + * summary: Creates a new reminder mail + * requestBody: + * description: Optional description in *Markdown* + * required: true + * content: + * application/json: * schema: * $ref: '#/components/schemas/ReminderMail' * tags: - * - reminderMails + * - reminder-mails * responses: * 201: * description: OK, reminderMail created diff --git a/pages/api/schedules/[id]/delete.ts b/pages/api/schedules/[id]/delete.ts index 4b037be9d2..4a85704a21 100644 --- a/pages/api/schedules/[id]/delete.ts +++ b/pages/api/schedules/[id]/delete.ts @@ -11,7 +11,7 @@ import { /** * @swagger - * /api/schedules/:id/delete: + * /api/schedules/{id}/delete: * delete: * summary: Remove an existing schedule * tags: diff --git a/pages/api/schedules/[id]/edit.ts b/pages/api/schedules/[id]/edit.ts index 2f750536f8..97fad524a0 100644 --- a/pages/api/schedules/[id]/edit.ts +++ b/pages/api/schedules/[id]/edit.ts @@ -12,7 +12,7 @@ import { /** * @swagger - * /api/schedules/:id/edit: + * /api/schedules/{id}/edit: * patch: * summary: Edits an existing schedule * tags: diff --git a/pages/api/schedules/[id]/index.ts b/pages/api/schedules/[id]/index.ts index 1a8675d53f..8bdab1fca0 100644 --- a/pages/api/schedules/[id]/index.ts +++ b/pages/api/schedules/[id]/index.ts @@ -15,7 +15,7 @@ import { * /api/schedules/{id}: * get: * summary: Get schedule by ID - * parameters: + * parameters: * - in: path * name: id * schema: diff --git a/pages/api/selected-calendars/[id]/delete.ts b/pages/api/selected-calendars/[id]/delete.ts index 76b949972a..ec1abebed4 100644 --- a/pages/api/selected-calendars/[id]/delete.ts +++ b/pages/api/selected-calendars/[id]/delete.ts @@ -10,27 +10,26 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * @swagger * /api/selected-calendars/{userId}_{teamId}/delete: * delete: - * summary: Remove an existing selectedCalendar - * parameters: - * - in: path - * - name: userId + * summary: Remove an existing record of a selected calendar + * parameters: + * - in: path + * - name: userId * schema: * type: integer * required: true - * description: Numeric ID of the user to get the selectedCalendar of - * * - name: teamId + * description: Numeric ID of the user to get the selected calendar of + * - name: teamId * schema: * type: integer * required: true - * description: Numeric ID of the team to get the selectedCalendar of + * description: Numeric ID of the team to get the selected calendar of * tags: - * - selectedCalendars + * - selected-calendars * responses: * 201: - * description: OK, selectedCalendar removed successfuly - * model: SelectedCalendar + * description: OK, selected calendar removed successfuly * 400: - * description: Bad request. SelectedCalendar id is invalid. + * description: Bad request. selected calendar id is invalid. * 401: * description: Authorization information is missing or invalid. */ diff --git a/pages/api/selected-calendars/[id]/edit.ts b/pages/api/selected-calendars/[id]/edit.ts index 717afb9c1f..c5737eb4e6 100644 --- a/pages/api/selected-calendars/[id]/edit.ts +++ b/pages/api/selected-calendars/[id]/edit.ts @@ -17,7 +17,7 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * patch: * summary: Edits an existing selectedCalendar * tags: - * - selectedCalendars + * - selected-calendars * responses: * 201: * description: OK, selectedCalendar edited successfuly diff --git a/pages/api/selected-calendars/[id]/index.ts b/pages/api/selected-calendars/[id]/index.ts index d88e0116ff..bec8bcc600 100644 --- a/pages/api/selected-calendars/[id]/index.ts +++ b/pages/api/selected-calendars/[id]/index.ts @@ -12,7 +12,7 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * /api/selected-calendars/{userId}_{teamId}: * get: * summary: find selectedCalendar by userID and teamID - * parameters: + * parameters: * - in: path * name: userId * schema: @@ -26,7 +26,7 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * required: true * description: Numeric teamId of the selectedCalendar to get * tags: - * - selectedCalendars + * - selected-calendars * responses: * 200: * description: OK diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index cb13635eec..bfc6e7b834 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -8,9 +8,11 @@ import { schemaSelectedCalendarPublic } from "@lib/validations/selected-calendar /** * @swagger - * /api/selectedCalendars: + * /api/selected-calendars: * get: * summary: Returns all selected calendars + * tags: + * - selected-calendars * responses: * 200: * description: OK diff --git a/pages/api/selected-calendars/new.ts b/pages/api/selected-calendars/new.ts index dbca6d85a0..4534215c0c 100644 --- a/pages/api/selected-calendars/new.ts +++ b/pages/api/selected-calendars/new.ts @@ -12,9 +12,11 @@ import { /** * @swagger - * /api/selectedCalendars/new: + * /api/selected-calendars/new: * post: * summary: Creates a new selected calendar + * tags: + * - selected-calendars * responses: * 201: * description: OK, selected calendar created diff --git a/pages/api/teams/[id]/delete.ts b/pages/api/teams/[id]/delete.ts index 657e9628ce..0b493f3fc5 100644 --- a/pages/api/teams/[id]/delete.ts +++ b/pages/api/teams/[id]/delete.ts @@ -11,9 +11,16 @@ import { /** * @swagger - * /api/teams/:id/delete: + * /api/teams/{id}/delete: * delete: * summary: Remove an existing team + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the team to remove * tags: * - teams * responses: diff --git a/pages/api/teams/[id]/edit.ts b/pages/api/teams/[id]/edit.ts index 2b0411cdf8..9791e37046 100644 --- a/pages/api/teams/[id]/edit.ts +++ b/pages/api/teams/[id]/edit.ts @@ -12,9 +12,23 @@ import { schemaTeamBodyParams, schemaTeamPublic, withValidTeam } from "@lib/vali /** * @swagger - * /api/teams/:id/edit: + * /api/teams/{id}/edit: * patch: * summary: Edits an existing team + * consumes: + * - application/json + * parameters: + * - in: body + * name: team + * description: The team to edit + * schema: Team + * required: true + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the team to edit * tags: * - teams * responses: diff --git a/pages/api/teams/[id]/index.ts b/pages/api/teams/[id]/index.ts index 218f296308..62765e544d 100644 --- a/pages/api/teams/[id]/index.ts +++ b/pages/api/teams/[id]/index.ts @@ -15,7 +15,7 @@ import { schemaTeamPublic } from "@lib/validations/team"; * /api/teams/{id}: * get: * summary: find team by ID - * parameters: + * parameters: * - in: path * name: id * schema: diff --git a/pages/api/users/[id]/delete.ts b/pages/api/users/[id]/delete.ts index b8b5a7a59f..b484d2cae5 100644 --- a/pages/api/users/[id]/delete.ts +++ b/pages/api/users/[id]/delete.ts @@ -14,7 +14,7 @@ import { * /api/users/{id}/delete: * delete: * summary: Remove an existing user - * parameters: + * parameters: * - in: path * name: id * schema: diff --git a/pages/api/users/[id]/edit.ts b/pages/api/users/[id]/edit.ts index 4d39bb80ce..7ebf00517e 100644 --- a/pages/api/users/[id]/edit.ts +++ b/pages/api/users/[id]/edit.ts @@ -15,7 +15,16 @@ import { schemaUserBodyParams, schemaUserPublic, withValidUser } from "@lib/vali * /api/users/{id}/edit: * patch: * summary: Edit an existing user - * parameters: + * consumes: + * - application/json + * parameters: + * - in: body + * name: user + * description: The user to edit + * schema: + * type: object + * $ref: '#/components/schemas/User' + * required: true * - in: path * name: id * schema: diff --git a/pages/api/users/[id]/index.ts b/pages/api/users/[id]/index.ts index 59987519b7..c9ef417223 100644 --- a/pages/api/users/[id]/index.ts +++ b/pages/api/users/[id]/index.ts @@ -14,14 +14,14 @@ import { schemaUserPublic } from "@lib/validations/user"; * @swagger * /api/users/{id}: * get: - * summary: Get a user by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the user to get + * summary: Get a user by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the user to get * tags: * - users * responses: diff --git a/pages/api/users/new.ts b/pages/api/users/new.ts index 52a25015b8..df3310c09c 100644 --- a/pages/api/users/new.ts +++ b/pages/api/users/new.ts @@ -10,14 +10,17 @@ import { schemaUserBodyParams, schemaUserPublic, withValidUser } from "@lib/vali * @swagger * /api/users/new: * post: - * summary: Creates a new user - * requestBody: - * description: Optional description in *Markdown* - * required: true - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/User' + * summary: Add a new user + * consumes: + * - application/json + * parameters: + * - in: body + * name: user + * description: The user to edit + * schema: + * type: object + * $ref: '#/components/schemas/User' + * required: true * tags: * - users * responses: diff --git a/templates/zod-validation.ts b/templates/zod-validation.ts index c200611812..02b0597529 100644 --- a/templates/zod-validation.ts +++ b/templates/zod-validation.ts @@ -1,23 +1,23 @@ -// import { withValidation } from "next-validations"; -// import { z } from "zod"; +import { withValidation } from "next-validations"; +import { z } from "zod"; -// import { _ModelModel as Model } from "@calcom/prisma/zod"; +import { _ModelModel as Model } from "@calcom/prisma/zod"; -// export const schemaModelBaseBodyParams = Model.omit({ id: true, userId: true, createdAt: true }).partial(); +export const schemaModelBaseBodyParams = Model.omit({ id: true, userId: true, createdAt: true }).partial(); -// const schemaModelRequiredParams = z.object({ -// email: z.string().email(), -// }); +const schemaModelRequiredParams = z.object({ + email: z.string().email(), +}); -// export const schemaModelBodyParams = schemaModelBaseBodyParams.merge(schemaModelRequiredParams); +export const schemaModelBodyParams = schemaModelBaseBodyParams.merge(schemaModelRequiredParams); -// export const schemaModelPublic = Model.omit({ -// id: true, -// userId: true, -// }); +export const schemaModelPublic = Model.omit({ + id: true, + userId: true, +}); -// export const withValidModel = withValidation({ -// schema: schemaModelBodyParams, -// type: "Zod", -// mode: "body", -// }); +export const withValidModel = withValidation({ + schema: schemaModelBodyParams, + type: "Zod", + mode: "body", +}); diff --git a/tsconfig.json b/tsconfig.json index 7859f5e38e..5acb222ba6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "extends": "@calcom/tsconfig/base.json", - "exclude": ["node_modules"], + "exclude": ["node_modules", "templates"], "compilerOptions": { "strictNullChecks": true, "baseUrl": ".", @@ -19,5 +19,5 @@ "@/*": ["*"] } }, - "include": ["./**/*.ts"] + "include": ["./**/*.ts*"] } From ba5382cb32a3255d240add759c3c7ec003ee2ac3 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 3 Apr 2022 19:10:35 +0200 Subject: [PATCH 063/658] add script to vercel deploy with private repos --- scripts/vercel-deploy.sh | 89 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 scripts/vercel-deploy.sh diff --git a/scripts/vercel-deploy.sh b/scripts/vercel-deploy.sh new file mode 100644 index 0000000000..528b1328cc --- /dev/null +++ b/scripts/vercel-deploy.sh @@ -0,0 +1,89 @@ +# github submodule repo addresses without https:// prefix +BRANCH_TO_CLONE="feat/api-keys" + +# This didn't work ¯\_(ツ)_/¯ +# declare -A remotes=( +# ["apps/website"]="github.com/calcom/website" +# ["apps/api"]="github.com/calcom/api" +# ) + +if [ "$VERCEL_GIT_COMMIT_SHA" == "" ]; then + echo "Error: VERCEL_GIT_COMMIT_SHA is empty" + exit 0 +fi + +# github access token is necessary +# add it to Environment Variables on Vercel +if [ "$GITHUB_ACCESS_TOKEN" == "" ]; then + echo "Error: GITHUB_ACCESS_TOKEN is empty" + exit 0 +fi + +# We add an exception to test on staging +if [ "$VERCEL_GIT_COMMIT_REF" == "staging" ]; then + BRANCH_TO_CLONE="-b $VERCEL_GIT_COMMIT_REF" +fi + +# stop execution on error - don't let it build if something goes wrong +set -e + +git config --global init.defaultBranch main +git config --global advice.detachedHead false + +# set up an empty temporary work directory +rm -rf ..?* .[!.]* * || true + +# checkout the current commit +git clone $BRANCH_TO_CLONE https://$GITHUB_ACCESS_TOKEN@github.com/calcom/cal.com.git . + +echo "Cloned" + +# get submodule commit +output=$(git submodule status --recursive) # get submodule info + +# Extract each submodule commit hash and path +submodules=$(echo "$output" | sed "s/ /,/g") + +for submodule in $submodules; do + IFS=',' read -ra submodule_parts <<<"$submodule" + COMMIT=$(echo ${submodule_parts[0]} | sed "s/-/ /g") + SUBMODULE_PATH=${submodule_parts[1]} + echo "COMMIT: $COMMIT SUBMODULE_PATH: $SUBMODULE_PATH" + + # This should be a hash table but couldn't make it work ¯\_(ツ)_/¯ + # SUBMODULE_GITHUB=$remotes[$SUBMODULE_PATH] + if [ "$SUBMODULE_PATH" == "apps/website" ]; then + SUBMODULE_GITHUB=github.com/calcom/website + COMMIT=$VERCEL_GIT_COMMIT_SHA + fi + + if [ "$SUBMODULE_PATH" == "apps/api" ]; then + SUBMODULE_GITHUB=github.com/calcom/api + fi + + echo "Submodule init" + + # set up an empty temporary work directory + rm -rf tmp || true # remove the tmp folder if exists + mkdir tmp # create the tmp folder + cd tmp # go into the tmp folder + + # checkout the current submodule commit + git init # initialise empty repo + git remote add $SUBMODULE_PATH https://$GITHUB_ACCESS_TOKEN@$SUBMODULE_GITHUB # add origin of the submodule + git fetch --depth=1 $SUBMODULE_PATH $COMMIT # fetch only the required version + git checkout $COMMIT # checkout on the right commit + + # move the submodule from tmp to the submodule path + cd .. # go folder up + rm -rf tmp/.git # remove .git + mv tmp/* $SUBMODULE_PATH/ # move the submodule to the submodule path + + # clean up + rm -rf tmp # remove the tmp folder +done + +git diff --quiet HEAD^ HEAD ':!/apps/docs/*' ':!/apps/api/*' ':!/apps/web/*' + +echo "✅ - Build can proceed" +exit 1 \ No newline at end of file From dacc27bae437312207e33430748446e0de057ce0 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 3 Apr 2022 19:16:03 +0200 Subject: [PATCH 064/658] needed for deployment --- apps/api/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 apps/api/.gitkeep diff --git a/apps/api/.gitkeep b/apps/api/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 From 1bbce547fd6a1914b4c75828679d30148ff0e5a0 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 3 Apr 2022 19:24:27 +0200 Subject: [PATCH 065/658] add commit to if submodule api --- scripts/vercel-deploy.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/vercel-deploy.sh b/scripts/vercel-deploy.sh index 528b1328cc..4a39147366 100644 --- a/scripts/vercel-deploy.sh +++ b/scripts/vercel-deploy.sh @@ -59,6 +59,7 @@ for submodule in $submodules; do if [ "$SUBMODULE_PATH" == "apps/api" ]; then SUBMODULE_GITHUB=github.com/calcom/api + COMMIT=$VERCEL_GIT_COMMIT_SHA fi echo "Submodule init" From ebe8e52f1bd098570438b6b188c0836db47126b4 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 3 Apr 2022 19:34:49 +0200 Subject: [PATCH 066/658] small removal of no-react in readme --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 2ede2ddbc9..81e06fa2ae 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,6 @@ This is the public REST api for cal.com It's a barebones **NextJS** + **TypeScript** project leveraging the nextJS API with a pages/api folder. -## No react - -It doesn't have react or react-dom as a dependency, and will only be used by a redirect as a folder or subdomain on cal.com with maybe a v1 tag like: - - `api.cal.com/v1` - `api.cal.com/api/v1` From 5956e705c98b3ba4d3347b1e374355f22c9edd55 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 3 Apr 2022 19:41:23 +0200 Subject: [PATCH 067/658] fix chmod permissions on vercel deploy script --- scripts/vercel-deploy.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 scripts/vercel-deploy.sh diff --git a/scripts/vercel-deploy.sh b/scripts/vercel-deploy.sh old mode 100644 new mode 100755 From 5aacf7f836a4abe1a9cce304eefa044a34b70957 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 3 Apr 2022 19:46:15 +0200 Subject: [PATCH 068/658] no branch to clone, git diff dont ignore api, ignore website --- scripts/vercel-deploy.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/vercel-deploy.sh b/scripts/vercel-deploy.sh index 4a39147366..268021c61b 100755 --- a/scripts/vercel-deploy.sh +++ b/scripts/vercel-deploy.sh @@ -1,5 +1,5 @@ # github submodule repo addresses without https:// prefix -BRANCH_TO_CLONE="feat/api-keys" +BRANCH_TO_CLONE="" # This didn't work ¯\_(ツ)_/¯ # declare -A remotes=( @@ -84,7 +84,7 @@ for submodule in $submodules; do rm -rf tmp # remove the tmp folder done -git diff --quiet HEAD^ HEAD ':!/apps/docs/*' ':!/apps/api/*' ':!/apps/web/*' +git diff --quiet HEAD^ HEAD ':!/apps/docs/*' ':!/apps/website/*' ':!/apps/web/*' echo "✅ - Build can proceed" exit 1 \ No newline at end of file From 2172fd96c00c254fe14a159750fbb4022be00ae0 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 3 Apr 2022 19:48:19 +0200 Subject: [PATCH 069/658] add back branch to clone passing -b before --- scripts/vercel-deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/vercel-deploy.sh b/scripts/vercel-deploy.sh index 268021c61b..a18972826e 100755 --- a/scripts/vercel-deploy.sh +++ b/scripts/vercel-deploy.sh @@ -1,5 +1,5 @@ # github submodule repo addresses without https:// prefix -BRANCH_TO_CLONE="" +BRANCH_TO_CLONE="-b feat/api-keys" # This didn't work ¯\_(ツ)_/¯ # declare -A remotes=( From a2b8b85de46059ae7b084df7968b24f143852401 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 3 Apr 2022 19:50:53 +0200 Subject: [PATCH 070/658] no commit in website --- scripts/vercel-deploy.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/vercel-deploy.sh b/scripts/vercel-deploy.sh index a18972826e..2c801645a1 100755 --- a/scripts/vercel-deploy.sh +++ b/scripts/vercel-deploy.sh @@ -54,7 +54,6 @@ for submodule in $submodules; do # SUBMODULE_GITHUB=$remotes[$SUBMODULE_PATH] if [ "$SUBMODULE_PATH" == "apps/website" ]; then SUBMODULE_GITHUB=github.com/calcom/website - COMMIT=$VERCEL_GIT_COMMIT_SHA fi if [ "$SUBMODULE_PATH" == "apps/api" ]; then From 5233dad5f9f9ba3813f17a10092d99c3aef7ed92 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 4 Apr 2022 00:49:05 +0200 Subject: [PATCH 071/658] re-unify into one route all id ops for teams and users --- json-schema/json-schema.json | 314 ++++++--------------------------- lib/helpers/httpMethods.ts | 12 ++ lib/helpers/withMiddleware.ts | 3 +- pages/api/teams/[id].ts | 130 ++++++++++++++ pages/api/teams/[id]/delete.ts | 50 ------ pages/api/teams/[id]/edit.ts | 63 ------- pages/api/teams/[id]/index.ts | 51 ------ pages/api/users/[id].ts | 130 ++++++++++++++ pages/api/users/[id]/delete.ts | 50 ------ pages/api/users/[id]/edit.ts | 65 ------- pages/api/users/[id]/index.ts | 51 ------ 11 files changed, 332 insertions(+), 587 deletions(-) create mode 100644 pages/api/teams/[id].ts delete mode 100644 pages/api/teams/[id]/delete.ts delete mode 100644 pages/api/teams/[id]/edit.ts delete mode 100644 pages/api/teams/[id]/index.ts create mode 100644 pages/api/users/[id].ts delete mode 100644 pages/api/users/[id]/delete.ts delete mode 100644 pages/api/users/[id]/edit.ts delete mode 100644 pages/api/users/[id]/index.ts diff --git a/json-schema/json-schema.json b/json-schema/json-schema.json index 220dbd101d..1ae113fddf 100644 --- a/json-schema/json-schema.json +++ b/json-schema/json-schema.json @@ -16,24 +16,14 @@ "description": "@zod.custom(imports.eventTypeSlug)" }, "description": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "position": { "type": "integer", "default": 0 }, "locations": { - "type": [ - "number", - "string", - "boolean", - "object", - "array", - "null" - ], + "type": ["number", "string", "boolean", "object", "array", "null"], "description": "@zod.custom(imports.eventTypeLocations)" }, "length": { @@ -50,10 +40,7 @@ } }, "userId": { - "type": [ - "integer", - "null" - ] + "type": ["integer", "null"] }, "team": { "anyOf": [ @@ -94,10 +81,7 @@ ] }, "eventName": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "customInputs": { "type": "array", @@ -106,45 +90,26 @@ } }, "timeZone": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "periodType": { "type": "string", "default": "UNLIMITED", - "enum": [ - "UNLIMITED", - "ROLLING", - "RANGE" - ] + "enum": ["UNLIMITED", "ROLLING", "RANGE"] }, "periodStartDate": { - "type": [ - "string", - "null" - ], + "type": ["string", "null"], "format": "date-time" }, "periodEndDate": { - "type": [ - "string", - "null" - ], + "type": ["string", "null"], "format": "date-time" }, "periodDays": { - "type": [ - "integer", - "null" - ] + "type": ["integer", "null"] }, "periodCountCalendarDays": { - "type": [ - "boolean", - "null" - ] + "type": ["boolean", "null"] }, "requiresConfirmation": { "type": "boolean", @@ -167,14 +132,8 @@ "default": 0 }, "schedulingType": { - "type": [ - "string", - "null" - ], - "enum": [ - "ROUND_ROBIN", - "COLLECTIVE" - ] + "type": ["string", "null"], + "enum": ["ROUND_ROBIN", "COLLECTIVE"] }, "schedule": { "anyOf": [ @@ -195,20 +154,10 @@ "default": "usd" }, "slotInterval": { - "type": [ - "integer", - "null" - ] + "type": ["integer", "null"] }, "metadata": { - "type": [ - "number", - "string", - "boolean", - "object", - "array", - "null" - ] + "type": ["number", "string", "boolean", "object", "array", "null"] } } }, @@ -222,14 +171,7 @@ "type": "string" }, "key": { - "type": [ - "number", - "string", - "boolean", - "object", - "array", - "null" - ] + "type": ["number", "string", "boolean", "object", "array", "null"] }, "user": { "anyOf": [ @@ -294,45 +236,27 @@ "type": "integer" }, "username": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "name": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "email": { "type": "string", "description": "@zod.email()" }, "emailVerified": { - "type": [ - "string", - "null" - ], + "type": ["string", "null"], "format": "date-time" }, "password": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "bio": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "avatar": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "timeZone": { "type": "string", @@ -359,20 +283,14 @@ "default": false }, "theme": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "createdDate": { "type": "string", "format": "date-time" }, "trialEndsAt": { - "type": [ - "string", - "null" - ], + "type": ["string", "null"], "format": "date-time" }, "eventTypes": { @@ -406,10 +324,7 @@ } }, "defaultScheduleId": { - "type": [ - "integer", - "null" - ] + "type": ["integer", "null"] }, "selectedCalendars": { "type": "array", @@ -422,23 +337,14 @@ "default": false }, "locale": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "timeFormat": { - "type": [ - "integer", - "null" - ], + "type": ["integer", "null"], "default": 12 }, "twoFactorSecret": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "twoFactorEnabled": { "type": "boolean", @@ -447,17 +353,10 @@ "identityProvider": { "type": "string", "default": "CAL", - "enum": [ - "CAL", - "GOOGLE", - "SAML" - ] + "enum": ["CAL", "GOOGLE", "SAML"] }, "identityProviderId": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "availability": { "type": "array", @@ -466,19 +365,12 @@ } }, "invitedTo": { - "type": [ - "integer", - "null" - ] + "type": ["integer", "null"] }, "plan": { "type": "string", "default": "TRIAL", - "enum": [ - "FREE", - "TRIAL", - "PRO" - ] + "enum": ["FREE", "TRIAL", "PRO"] }, "webhooks": { "type": "array", @@ -509,20 +401,10 @@ "default": false }, "metadata": { - "type": [ - "number", - "string", - "boolean", - "object", - "array", - "null" - ] + "type": ["number", "string", "boolean", "object", "array", "null"] }, "verified": { - "type": [ - "boolean", - "null" - ], + "type": ["boolean", "null"], "default": false }, "apiKeys": { @@ -540,28 +422,16 @@ "type": "integer" }, "name": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "slug": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "logo": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "bio": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "hideBranding": { "type": "boolean", @@ -590,11 +460,7 @@ }, "role": { "type": "string", - "enum": [ - "MEMBER", - "ADMIN", - "OWNER" - ] + "enum": ["MEMBER", "ADMIN", "OWNER"] }, "team": { "$ref": "#/definitions/Team" @@ -643,22 +509,13 @@ "type": "string" }, "meetingId": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "meetingPassword": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "meetingUrl": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "booking": { "anyOf": [ @@ -688,10 +545,7 @@ "type": "string" }, "locale": { - "type": [ - "string", - "null" - ], + "type": ["string", "null"], "default": "en" }, "booking": { @@ -771,10 +625,7 @@ "type": "string" }, "description": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "startTime": { "type": "string", @@ -791,10 +642,7 @@ } }, "location": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "dailyRef": { "anyOf": [ @@ -811,10 +659,7 @@ "format": "date-time" }, "updatedAt": { - "type": [ - "string", - "null" - ], + "type": ["string", "null"], "format": "date-time" }, "confirmed": { @@ -828,12 +673,7 @@ "status": { "type": "string", "default": "ACCEPTED", - "enum": [ - "CANCELLED", - "ACCEPTED", - "REJECTED", - "PENDING" - ] + "enum": ["CANCELLED", "ACCEPTED", "REJECTED", "PENDING"] }, "paid": { "type": "boolean", @@ -856,16 +696,10 @@ ] }, "cancellationReason": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "rejectionReason": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } } }, @@ -892,10 +726,7 @@ "type": "string" }, "timeZone": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "availability": { "type": "array", @@ -946,10 +777,7 @@ "format": "date-time" }, "date": { - "type": [ - "string", - "null" - ], + "type": ["string", "null"], "format": "date-time" }, "Schedule": { @@ -992,12 +820,7 @@ }, "type": { "type": "string", - "enum": [ - "TEXT", - "TEXTLONG", - "NUMBER", - "BOOL" - ] + "enum": ["TEXT", "TEXTLONG", "NUMBER", "BOOL"] }, "required": { "type": "boolean" @@ -1042,9 +865,7 @@ }, "reminderType": { "type": "string", - "enum": [ - "PENDING_BOOKING_CONFIRMATION" - ] + "enum": ["PENDING_BOOKING_CONFIRMATION"] }, "elapsedMinutes": { "type": "integer" @@ -1066,9 +887,7 @@ }, "type": { "type": "string", - "enum": [ - "STRIPE" - ] + "enum": ["STRIPE"] }, "booking": { "anyOf": [ @@ -1096,14 +915,7 @@ "type": "boolean" }, "data": { - "type": [ - "number", - "string", - "boolean", - "object", - "array", - "null" - ] + "type": ["number", "string", "boolean", "object", "array", "null"] }, "externalId": { "type": "string" @@ -1120,10 +932,7 @@ "type": "string" }, "payloadTemplate": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] }, "createdAt": { "type": "string", @@ -1135,11 +944,7 @@ }, "eventTriggers": { "type": "array", - "enum": [ - "BOOKING_CREATED", - "BOOKING_RESCHEDULED", - "BOOKING_CANCELLED" - ] + "enum": ["BOOKING_CREATED", "BOOKING_RESCHEDULED", "BOOKING_CANCELLED"] }, "user": { "anyOf": [ @@ -1188,10 +993,7 @@ "format": "date-time" }, "note": { - "type": [ - "string", - "null" - ] + "type": ["string", "null"] } } } @@ -1259,4 +1061,4 @@ "$ref": "#/definitions/ApiKey" } } -} \ No newline at end of file +} diff --git a/lib/helpers/httpMethods.ts b/lib/helpers/httpMethods.ts index d19102d4dc..1454355f3a 100644 --- a/lib/helpers/httpMethods.ts +++ b/lib/helpers/httpMethods.ts @@ -11,7 +11,19 @@ export const httpMethod = (allowedHttpMethod: "GET" | "POST" | "PATCH" | "DELETE }; }; +export const httpMethods = (allowedHttpMethod: string[]): NextMiddleware => { + return async function (req, res, next) { + if (allowedHttpMethod.map((method) => method === req.method)) { + await next(); + } else { + res.status(405).json({ message: `Only ${allowedHttpMethod} Method allowed` }); + res.end(); + } + }; +}; + export const HTTP_POST = httpMethod("POST"); export const HTTP_GET = httpMethod("GET"); export const HTTP_PATCH = httpMethod("PATCH"); export const HTTP_DELETE = httpMethod("DELETE"); +export const HTTP_GET_DELETE_PATCH = httpMethods(["GET", "DELETE", "PATCH"]); diff --git a/lib/helpers/withMiddleware.ts b/lib/helpers/withMiddleware.ts index e15c388d51..4171fa774f 100644 --- a/lib/helpers/withMiddleware.ts +++ b/lib/helpers/withMiddleware.ts @@ -2,11 +2,12 @@ import { label } from "next-api-middleware"; import { addRequestId } from "./addRequestid"; import { captureErrors } from "./captureErrors"; -import { HTTP_POST, HTTP_DELETE, HTTP_PATCH, HTTP_GET } from "./httpMethods"; +import { HTTP_POST, HTTP_DELETE, HTTP_PATCH, HTTP_GET, HTTP_GET_DELETE_PATCH } from "./httpMethods"; import { verifyApiKey } from "./verifyApiKey"; const withMiddleware = label( { + HTTP_GET_DELETE_PATCH, HTTP_GET, HTTP_PATCH, HTTP_POST, diff --git a/pages/api/teams/[id].ts b/pages/api/teams/[id].ts new file mode 100644 index 0000000000..49895d6937 --- /dev/null +++ b/pages/api/teams/[id].ts @@ -0,0 +1,130 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { TeamResponse } from "@lib/types"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; + +/** + * @swagger + * /api/teams/{id}: + * get: + * summary: Get a team by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the team to get + * tags: + * - teams + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Team was not found + * patch: + * summary: Edit an existing team + * consumes: + * - application/json + * parameters: + * - in: body + * name: team + * description: The team to edit + * schema: + * type: object + * $ref: '#/components/schemas/Team' + * required: true + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the team to edit + * tags: + * - teams + * responses: + * 201: + * description: OK, team edited successfuly + * model: Team + * 400: + * description: Bad request. Team body is invalid. + * 401: + * description: Authorization information is missing or invalid. + * delete: + * summary: Remove an existing team + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the team to delete + * tags: + * - teams + * responses: + * 201: + * description: OK, team removed successfuly + * model: Team + * 400: + * description: Bad request. Team id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function teamById(req: NextApiRequest, res: NextApiResponse) { + const { method, query, body } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaTeamBodyParams.safeParse(body); + if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + + switch (method) { + case "GET": + await prisma.team + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data) => schemaTeamPublic.parse(data)) + .then((data: TeamResponse) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `Team with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "PATCH": + if (!safeBody.success) throw new Error("Invalid request body"); + await prisma.team + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((team) => schemaTeamPublic.parse(team)) + .then((data: TeamResponse) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `Team with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "DELETE": + await prisma.team + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ message: `Team with id: ${safeQuery.data.id} deleted successfully` }) + ) + .catch((error: Error) => + res.status(404).json({ message: `Team with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } +} + +export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(teamById)); diff --git a/pages/api/teams/[id]/delete.ts b/pages/api/teams/[id]/delete.ts deleted file mode 100644 index 0b493f3fc5..0000000000 --- a/pages/api/teams/[id]/delete.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BaseResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/teams/{id}/delete: - * delete: - * summary: Remove an existing team - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the team to remove - * tags: - * - teams - * responses: - * 201: - * description: OK, team removed successfuly - * model: Team - * 400: - * description: Bad request. Team id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function deleteTeam(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query", safe.error); - - const data = await prisma.team.delete({ where: { id: safe.data.id } }); - - if (data) res.status(200).json({ message: `Team with id: ${safe.data.id} deleted successfully` }); - else - (error: Error) => - res.status(400).json({ - message: `Team with id: ${safe.data.id} was not able to be processed`, - error, - }); -} - -export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteTeam)); diff --git a/pages/api/teams/[id]/edit.ts b/pages/api/teams/[id]/edit.ts deleted file mode 100644 index 9791e37046..0000000000 --- a/pages/api/teams/[id]/edit.ts +++ /dev/null @@ -1,63 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { TeamResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; -import { schemaTeamBodyParams, schemaTeamPublic, withValidTeam } from "@lib/validations/team"; - -/** - * @swagger - * /api/teams/{id}/edit: - * patch: - * summary: Edits an existing team - * consumes: - * - application/json - * parameters: - * - in: body - * name: team - * description: The team to edit - * schema: Team - * required: true - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the team to edit - * tags: - * - teams - * responses: - * 201: - * description: OK, team edited successfuly - * model: Team - * 400: - * description: Bad request. Team body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function editTeam(req: NextApiRequest, res: NextApiResponse) { - const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); - const safeBody = await schemaTeamBodyParams.safeParse(req.body); - - if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); - const team = await prisma.team.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - const data = schemaTeamPublic.parse(team); - - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, - error, - }); -} - -export default withMiddleware("HTTP_PATCH")(withValidQueryIdTransformParseInt(withValidTeam(editTeam))); diff --git a/pages/api/teams/[id]/index.ts b/pages/api/teams/[id]/index.ts deleted file mode 100644 index 62765e544d..0000000000 --- a/pages/api/teams/[id]/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { TeamResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; -import { schemaTeamPublic } from "@lib/validations/team"; - -/** - * @swagger - * /api/teams/{id}: - * get: - * summary: find team by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the team to get - * tags: - * - teams - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Team was not found - */ -export async function teamById(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query"); - - const team = await prisma.team.findUnique({ where: { id: safe.data.id } }); - const data = schemaTeamPublic.parse(team); - - if (team) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "Team was not found", - error, - }); -} - -export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(teamById)); diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts new file mode 100644 index 0000000000..35adf9fa08 --- /dev/null +++ b/pages/api/users/[id].ts @@ -0,0 +1,130 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { UserResponse } from "@lib/types"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaUserBodyParams, schemaUserPublic } from "@lib/validations/user"; + +/** + * @swagger + * /api/users/{id}: + * get: + * summary: Get a user by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the user to get + * tags: + * - users + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: User was not found + * patch: + * summary: Edit an existing user + * consumes: + * - application/json + * parameters: + * - in: body + * name: user + * description: The user to edit + * schema: + * type: object + * $ref: '#/components/schemas/User' + * required: true + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the user to edit + * tags: + * - users + * responses: + * 201: + * description: OK, user edited successfuly + * model: User + * 400: + * description: Bad request. User body is invalid. + * 401: + * description: Authorization information is missing or invalid. + * delete: + * summary: Remove an existing user + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the user to delete + * tags: + * - users + * responses: + * 201: + * description: OK, user removed successfuly + * model: User + * 400: + * description: Bad request. User id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function userById(req: NextApiRequest, res: NextApiResponse) { + const { method, query, body } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaUserBodyParams.safeParse(body); + if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + + switch (method) { + case "GET": + await prisma.user + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data: UserResponse) => schemaUserPublic.parse(data)) + .then((data: UserResponse) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "PATCH": + if (!safeBody.success) throw new Error("Invalid request body"); + await prisma.user + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((user) => schemaUserPublic.parse(user)) + .then((data: UserResponse) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "DELETE": + await prisma.user + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ message: `User with id: ${safeQuery.data.id} deleted successfully` }) + ) + .catch((error: Error) => + res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } +} + +export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(userById)); diff --git a/pages/api/users/[id]/delete.ts b/pages/api/users/[id]/delete.ts deleted file mode 100644 index b484d2cae5..0000000000 --- a/pages/api/users/[id]/delete.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BaseResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/users/{id}/delete: - * delete: - * summary: Remove an existing user - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the user to delete - * tags: - * - users - * responses: - * 201: - * description: OK, user removed successfuly - * model: User - * 400: - * description: Bad request. User id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function deleteUser(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query", safe.error); - - const data = await prisma.user.delete({ where: { id: safe.data.id } }); - - if (data) res.status(200).json({ message: `User with id: ${safe.data.id} deleted successfully` }); - else - (error: Error) => - res.status(400).json({ - message: `User with id: ${safe.data.id} was not able to be processed`, - error, - }); -} - -export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteUser)); diff --git a/pages/api/users/[id]/edit.ts b/pages/api/users/[id]/edit.ts deleted file mode 100644 index 7ebf00517e..0000000000 --- a/pages/api/users/[id]/edit.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { UserResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; -import { schemaUserBodyParams, schemaUserPublic, withValidUser } from "@lib/validations/user"; - -/** - * @swagger - * /api/users/{id}/edit: - * patch: - * summary: Edit an existing user - * consumes: - * - application/json - * parameters: - * - in: body - * name: user - * description: The user to edit - * schema: - * type: object - * $ref: '#/components/schemas/User' - * required: true - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the user to edit - * tags: - * - users - * responses: - * 201: - * description: OK, user edited successfuly - * model: User - * 400: - * description: Bad request. User body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function editUser(req: NextApiRequest, res: NextApiResponse) { - const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); - const safeBody = await schemaUserBodyParams.safeParse(req.body); - - if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); - const user = await prisma.user.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - const data = schemaUserPublic.parse(user); - - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, - error, - }); -} - -export default withMiddleware("HTTP_PATCH")(withValidQueryIdTransformParseInt(withValidUser(editUser))); diff --git a/pages/api/users/[id]/index.ts b/pages/api/users/[id]/index.ts deleted file mode 100644 index c9ef417223..0000000000 --- a/pages/api/users/[id]/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { UserResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; -import { schemaUserPublic } from "@lib/validations/user"; - -/** - * @swagger - * /api/users/{id}: - * get: - * summary: Get a user by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the user to get - * tags: - * - users - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: User was not found - */ -export async function userById(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query"); - - const user = await prisma.user.findUnique({ where: { id: safe.data.id } }); - const data = schemaUserPublic.parse(user); - - if (user) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "User was not found", - error, - }); -} - -export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(userById)); From de8d7f64c38abb58b129443381b79c200da3190c Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 4 Apr 2022 02:02:11 +0200 Subject: [PATCH 072/658] mvoe to less files --- .prettierignore | 3 +- .prettierrc.js | 1 + pages/api/api-keys/[id]/delete.ts | 24 --- pages/api/api-keys/[id]/edit.ts | 38 ----- pages/api/api-keys/[id]/index.ts | 24 --- pages/api/api-keys/index.ts | 20 --- pages/api/api-keys/new.ts | 24 --- pages/api/attendees/[id].ts | 130 ++++++++++++++++ pages/api/attendees/[id]/delete.ts | 50 ------ pages/api/attendees/[id]/edit.ts | 58 ------- pages/api/attendees/[id]/index.ts | 51 ------- pages/api/availabilities/[id].ts | 130 ++++++++++++++++ pages/api/availabilities/[id]/delete.ts | 50 ------ pages/api/availabilities/[id]/edit.ts | 62 -------- pages/api/availabilities/[id]/index.ts | 51 ------- pages/api/booking-references/[id].ts | 138 +++++++++++++++++ pages/api/booking-references/[id]/delete.ts | 51 ------- pages/api/booking-references/[id]/edit.ts | 65 -------- pages/api/booking-references/[id]/index.ts | 54 ------- pages/api/bookings/[id].ts | 130 ++++++++++++++++ pages/api/bookings/[id]/delete.ts | 50 ------ pages/api/bookings/[id]/edit.ts | 56 ------- pages/api/bookings/[id]/index.ts | 51 ------- pages/api/credentials/[id].ts | 130 ++++++++++++++++ pages/api/credentials/[id]/delete.ts | 50 ------ pages/api/credentials/[id]/edit.ts | 62 -------- pages/api/credentials/[id]/index.ts | 51 ------- pages/api/daily-event-references/[id].ts | 144 ++++++++++++++++++ .../api/daily-event-references/[id]/delete.ts | 51 ------- pages/api/daily-event-references/[id]/edit.ts | 65 -------- .../api/daily-event-references/[id]/index.ts | 54 ------- pages/api/destination-calendars/[id].ts | 144 ++++++++++++++++++ .../api/destination-calendars/[id]/delete.ts | 51 ------- pages/api/destination-calendars/[id]/edit.ts | 65 -------- pages/api/destination-calendars/[id]/index.ts | 54 ------- pages/api/destination-calendars/index.ts | 2 +- pages/api/destination-calendars/new.ts | 2 +- pages/api/event-type-custom-inputs/[id].ts | 133 ++++++++++++++++ .../event-type-custom-inputs/[id]/delete.ts | 51 ------- .../api/event-type-custom-inputs/[id]/edit.ts | 65 -------- .../event-type-custom-inputs/[id]/index.ts | 54 ------- pages/api/event-types/[id].ts | 128 ++++++++++++++++ pages/api/event-types/[id]/delete.ts | 50 ------ pages/api/event-types/[id]/edit.ts | 62 -------- pages/api/event-types/[id]/index.ts | 51 ------- pages/api/payments/[id].ts | 130 ++++++++++++++++ pages/api/payments/[id]/delete.ts | 50 ------ pages/api/payments/[id]/edit.ts | 56 ------- pages/api/payments/[id]/index.ts | 51 ------- pages/api/reminder-mails/[id].ts | 130 ++++++++++++++++ pages/api/reminder-mails/[id]/delete.ts | 50 ------ pages/api/reminder-mails/[id]/edit.ts | 62 -------- pages/api/reminder-mails/[id]/index.ts | 51 ------- pages/api/schedules/[id].ts | 130 ++++++++++++++++ pages/api/schedules/[id]/delete.ts | 43 ------ pages/api/schedules/[id]/edit.ts | 51 ------- pages/api/schedules/[id]/index.ts | 51 ------- pages/api/teams/[id].ts | 4 +- pages/api/users/[id].ts | 6 +- prettier.rc.js | 7 - 60 files changed, 1607 insertions(+), 2095 deletions(-) create mode 100644 .prettierrc.js delete mode 100644 pages/api/api-keys/[id]/delete.ts delete mode 100644 pages/api/api-keys/[id]/edit.ts delete mode 100644 pages/api/api-keys/[id]/index.ts delete mode 100644 pages/api/api-keys/index.ts delete mode 100644 pages/api/api-keys/new.ts create mode 100644 pages/api/attendees/[id].ts delete mode 100644 pages/api/attendees/[id]/delete.ts delete mode 100644 pages/api/attendees/[id]/edit.ts delete mode 100644 pages/api/attendees/[id]/index.ts create mode 100644 pages/api/availabilities/[id].ts delete mode 100644 pages/api/availabilities/[id]/delete.ts delete mode 100644 pages/api/availabilities/[id]/edit.ts delete mode 100644 pages/api/availabilities/[id]/index.ts create mode 100644 pages/api/booking-references/[id].ts delete mode 100644 pages/api/booking-references/[id]/delete.ts delete mode 100644 pages/api/booking-references/[id]/edit.ts delete mode 100644 pages/api/booking-references/[id]/index.ts create mode 100644 pages/api/bookings/[id].ts delete mode 100644 pages/api/bookings/[id]/delete.ts delete mode 100644 pages/api/bookings/[id]/edit.ts delete mode 100644 pages/api/bookings/[id]/index.ts create mode 100644 pages/api/credentials/[id].ts delete mode 100644 pages/api/credentials/[id]/delete.ts delete mode 100644 pages/api/credentials/[id]/edit.ts delete mode 100644 pages/api/credentials/[id]/index.ts create mode 100644 pages/api/daily-event-references/[id].ts delete mode 100644 pages/api/daily-event-references/[id]/delete.ts delete mode 100644 pages/api/daily-event-references/[id]/edit.ts delete mode 100644 pages/api/daily-event-references/[id]/index.ts create mode 100644 pages/api/destination-calendars/[id].ts delete mode 100644 pages/api/destination-calendars/[id]/delete.ts delete mode 100644 pages/api/destination-calendars/[id]/edit.ts delete mode 100644 pages/api/destination-calendars/[id]/index.ts create mode 100644 pages/api/event-type-custom-inputs/[id].ts delete mode 100644 pages/api/event-type-custom-inputs/[id]/delete.ts delete mode 100644 pages/api/event-type-custom-inputs/[id]/edit.ts delete mode 100644 pages/api/event-type-custom-inputs/[id]/index.ts create mode 100644 pages/api/event-types/[id].ts delete mode 100644 pages/api/event-types/[id]/delete.ts delete mode 100644 pages/api/event-types/[id]/edit.ts delete mode 100644 pages/api/event-types/[id]/index.ts create mode 100644 pages/api/payments/[id].ts delete mode 100644 pages/api/payments/[id]/delete.ts delete mode 100644 pages/api/payments/[id]/edit.ts delete mode 100644 pages/api/payments/[id]/index.ts create mode 100644 pages/api/reminder-mails/[id].ts delete mode 100644 pages/api/reminder-mails/[id]/delete.ts delete mode 100644 pages/api/reminder-mails/[id]/edit.ts delete mode 100644 pages/api/reminder-mails/[id]/index.ts create mode 100644 pages/api/schedules/[id].ts delete mode 100644 pages/api/schedules/[id]/delete.ts delete mode 100644 pages/api/schedules/[id]/edit.ts delete mode 100644 pages/api/schedules/[id]/index.ts delete mode 100644 prettier.rc.js diff --git a/.prettierignore b/.prettierignore index 28b23b7d57..745ffcee46 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,4 +1,5 @@ .next/ coverage/ node_modules/ -tests/ \ No newline at end of file +tests/ +templates/ \ No newline at end of file diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000000..246057aa0c --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1 @@ +module.exports = require("../../packages/config/prettier-preset"); diff --git a/pages/api/api-keys/[id]/delete.ts b/pages/api/api-keys/[id]/delete.ts deleted file mode 100644 index dbe8250fe2..0000000000 --- a/pages/api/api-keys/[id]/delete.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; - -type ResponseData = { - message?: string; - error?: unknown; -}; - -export async function deleteApiKey(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdAsString.safeParse(req.query); - if (safe.success) { - const data = await prisma.apiKey.delete({ where: { id: safe.data.id } }); - // We only remove the apiKey type from the database if there's an existing resource. - if (data) res.status(200).json({ message: `ApiKey with id: ${safe.data.id} deleted successfully` }); - // This catches the error thrown by prisma.apiKey.delete() if the resource is not found. - else res.status(400).json({ message: `ApiKey with id: ${safe.data.id} was not able to be processed` }); - } -} - -export default withMiddleware("HTTP_DELETE", "addRequestId")(withValidQueryIdString(deleteApiKey)); diff --git a/pages/api/api-keys/[id]/edit.ts b/pages/api/api-keys/[id]/edit.ts deleted file mode 100644 index 66da3539bc..0000000000 --- a/pages/api/api-keys/[id]/edit.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; -import { ApiKey } from "@calcom/prisma/client"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { schemaApiKeyBodyParams, withValidApiKey } from "@lib/validations/api-key"; -import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; - -type ResponseData = { - data?: ApiKey; - message?: string; - error?: unknown; -}; - -export async function editApiKey(req: NextApiRequest, res: NextApiResponse) { - const { query, body } = req; - const safeQuery = await schemaQueryIdAsString.safeParse(query); - const safeBody = await schemaApiKeyBodyParams.safeParse(body); - - if (safeQuery.success && safeBody.success) { - const data = await prisma.apiKey.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - if (data) res.status(200).json({ data }); - else - (error: unknown) => - res - .status(404) - .json({ message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, error }); - } -} - -export default withMiddleware( - "HTTP_PATCH", - "addRequestId" -)(withValidQueryIdString(withValidApiKey(editApiKey))); diff --git a/pages/api/api-keys/[id]/index.ts b/pages/api/api-keys/[id]/index.ts deleted file mode 100644 index 36b9203667..0000000000 --- a/pages/api/api-keys/[id]/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; -import { ApiKey } from "@calcom/prisma/client"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; - -type ResponseData = { - data?: ApiKey; - error?: unknown; -}; - -export async function apiKeyById(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdAsString.safeParse(req.query); - if (safe.success) { - const data = await prisma.apiKey.findUnique({ where: { id: safe.data.id } }); - - if (data) res.status(200).json({ data }); - else res.status(404).json({ error: { message: "ApiKey was not found" } }); - } -} - -export default withMiddleware("addRequestId", "HTTP_GET")(withValidQueryIdString(apiKeyById)); diff --git a/pages/api/api-keys/index.ts b/pages/api/api-keys/index.ts deleted file mode 100644 index 94074a940a..0000000000 --- a/pages/api/api-keys/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; -import { ApiKey } from "@calcom/prisma/client"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; - -type ResponseData = { - data?: ApiKey[]; - error?: unknown; -}; - -async function allApiKeys(req: NextApiRequest, res: NextApiResponse) { - const data = await prisma.apiKey.findMany(); - - if (data) res.status(200).json({ data }); - else res.status(400).json({ error: "No data found" }); -} - -export default withMiddleware("addRequestId", "HTTP_GET")(allApiKeys); diff --git a/pages/api/api-keys/new.ts b/pages/api/api-keys/new.ts deleted file mode 100644 index 160324c19c..0000000000 --- a/pages/api/api-keys/new.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; -import { ApiKey } from "@calcom/prisma/client"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { schemaApiKeyBodyParams, withValidApiKey } from "@lib/validations/api-key"; - -type ResponseData = { - data?: ApiKey; - error?: unknown; -}; - -async function createApiKey(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaApiKeyBodyParams.safeParse(req.body); - if (safe.success) { - const data = await prisma.apiKey.create({ data: safe.data }); - if (data) res.status(201).json({ data }); - else - (error: unknown) => res.status(400).json({ error: { message: "Could not create apiKey type", error } }); - } -} - -export default withMiddleware("addRequestId", "HTTP_POST")(withValidApiKey(createApiKey)); diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts new file mode 100644 index 0000000000..502fb5d1c5 --- /dev/null +++ b/pages/api/attendees/[id].ts @@ -0,0 +1,130 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { AttendeeResponse } from "@lib/types"; +import { schemaAttendeeBodyParams, schemaAttendeePublic } from "@lib/validations/attendee"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /api/attendees/{id}: + * get: + * summary: Get an attendee by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the attendee to get + * tags: + * - attendees + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Attendee was not found + * patch: + * summary: Edit an existing attendee + * consumes: + * - application/json + * parameters: + * - in: body + * name: attendee + * description: The attendee to edit + * schema: + * type: object + * $ref: '#/components/schemas/Attendee' + * required: true + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the attendee to edit + * tags: + * - attendees + * responses: + * 201: + * description: OK, attendee edited successfuly + * model: Attendee + * 400: + * description: Bad request. Attendee body is invalid. + * 401: + * description: Authorization information is missing or invalid. + * delete: + * summary: Remove an existing attendee + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the attendee to delete + * tags: + * - attendees + * responses: + * 201: + * description: OK, attendee removed successfuly + * model: Attendee + * 400: + * description: Bad request. Attendee id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function attendeeById(req: NextApiRequest, res: NextApiResponse) { + const { method, query, body } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaAttendeeBodyParams.safeParse(body); + if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + + switch (method) { + case "GET": + await prisma.attendee + .findUnique({ where: { id: safeQuery.data.id } }) + .then((attendee) => schemaAttendeePublic.parse(attendee)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `Attendee with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "PATCH": + if (!safeBody.success) throw new Error("Invalid request body"); + await prisma.attendee + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((attendee) => schemaAttendeePublic.parse(attendee)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `Attendee with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "DELETE": + await prisma.attendee + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ message: `Attendee with id: ${safeQuery.data.id} deleted successfully` }) + ) + .catch((error: Error) => + res.status(404).json({ message: `Attendee with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } +} + +export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(attendeeById)); diff --git a/pages/api/attendees/[id]/delete.ts b/pages/api/attendees/[id]/delete.ts deleted file mode 100644 index 25e0818960..0000000000 --- a/pages/api/attendees/[id]/delete.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BaseResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/attendees/{id}/delete: - * delete: - * summary: Remove an existing attendee - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the attendee to delete - * tags: - * - attendees - * responses: - * 201: - * description: OK, attendee removed successfuly - * model: Attendee - * 400: - * description: Bad request. Attendee id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function deleteAttendee(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query", safe.error); - - const data = await prisma.attendee.delete({ where: { id: safe.data.id } }); - - if (data) res.status(200).json({ message: `Attendee with id: ${safe.data.id} deleted successfully` }); - else - (error: Error) => - res.status(400).json({ - message: `Attendee with id: ${safe.data.id} was not able to be processed`, - error, - }); -} - -export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteAttendee)); diff --git a/pages/api/attendees/[id]/edit.ts b/pages/api/attendees/[id]/edit.ts deleted file mode 100644 index dab8ed979c..0000000000 --- a/pages/api/attendees/[id]/edit.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { AttendeeResponse } from "@lib/types"; -import { schemaAttendeeBodyParams, schemaAttendeePublic, withValidAttendee } from "@lib/validations/attendee"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/attendees/{id}/edit: - * patch: - * summary: Edit an existing attendee - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the attendee to edit - * tags: - * - attendees - * responses: - * 201: - * description: OK, attendee edited successfuly - * model: Attendee - * 400: - * description: Bad request. Attendee body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function editAttendee(req: NextApiRequest, res: NextApiResponse) { - const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); - const safeBody = await schemaAttendeeBodyParams.safeParse(req.body); - - if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); - const attendee = await prisma.attendee.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - const data = schemaAttendeePublic.parse(attendee); - - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, - error, - }); -} - -export default withMiddleware("HTTP_PATCH")( - withValidQueryIdTransformParseInt(withValidAttendee(editAttendee)) -); diff --git a/pages/api/attendees/[id]/index.ts b/pages/api/attendees/[id]/index.ts deleted file mode 100644 index 81f9ead1bd..0000000000 --- a/pages/api/attendees/[id]/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { AttendeeResponse } from "@lib/types"; -import { schemaAttendeePublic } from "@lib/validations/attendee"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/attendees/{id}: - * get: - * summary: Get a attendee by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the attendee to get - * tags: - * - attendees - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Attendee was not found - */ -export async function attendeeById(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query"); - - const attendee = await prisma.attendee.findUnique({ where: { id: safe.data.id } }); - const data = schemaAttendeePublic.parse(attendee); - - if (attendee) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "Attendee was not found", - error, - }); -} - -export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(attendeeById)); diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts new file mode 100644 index 0000000000..be9d9eb987 --- /dev/null +++ b/pages/api/availabilities/[id].ts @@ -0,0 +1,130 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { AvailabilityResponse } from "@lib/types"; +import { schemaAvailabilityBodyParams, schemaAvailabilityPublic } from "@lib/validations/availability"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /api/availabilities/{id}: + * get: + * summary: Get an availability by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the availability to get + * tags: + * - availabilities + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Availability was not found + * patch: + * summary: Edit an existing availability + * consumes: + * - application/json + * parameters: + * - in: body + * name: availability + * description: The availability to edit + * schema: + * type: object + * $ref: '#/components/schemas/Availability' + * required: true + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the availability to edit + * tags: + * - availabilities + * responses: + * 201: + * description: OK, availability edited successfuly + * model: Availability + * 400: + * description: Bad request. Availability body is invalid. + * 401: + * description: Authorization information is missing or invalid. + * delete: + * summary: Remove an existing availability + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the availability to delete + * tags: + * - availabilities + * responses: + * 201: + * description: OK, availability removed successfuly + * model: Availability + * 400: + * description: Bad request. Availability id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function availabilityById(req: NextApiRequest, res: NextApiResponse) { + const { method, query, body } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaAvailabilityBodyParams.safeParse(body); + if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + + switch (method) { + case "GET": + await prisma.availability + .findUnique({ where: { id: safeQuery.data.id } }) + .then((availability) => schemaAvailabilityPublic.parse(availability)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `Availability with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "PATCH": + if (!safeBody.success) throw new Error("Invalid request body"); + await prisma.availability + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((availability) => schemaAvailabilityPublic.parse(availability)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `Availability with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "DELETE": + await prisma.availability + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ message: `Availability with id: ${safeQuery.data.id} deleted successfully` }) + ) + .catch((error: Error) => + res.status(404).json({ message: `Availability with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } +} + +export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(availabilityById)); diff --git a/pages/api/availabilities/[id]/delete.ts b/pages/api/availabilities/[id]/delete.ts deleted file mode 100644 index a23f5e9792..0000000000 --- a/pages/api/availabilities/[id]/delete.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BaseResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/availabilites/{id}/delete: - * delete: - * summary: Remove an existing availability - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the availability to delete - * tags: - * - availabilites - * responses: - * 201: - * description: OK, availability removed successfuly - * model: Availability - * 400: - * description: Bad request. Availability id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function deleteAvailability(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query", safe.error); - - const data = await prisma.availability.delete({ where: { id: safe.data.id } }); - - if (data) res.status(200).json({ message: `Availability with id: ${safe.data.id} deleted successfully` }); - else - (error: Error) => - res.status(400).json({ - message: `Availability with id: ${safe.data.id} was not able to be processed`, - error, - }); -} - -export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteAvailability)); diff --git a/pages/api/availabilities/[id]/edit.ts b/pages/api/availabilities/[id]/edit.ts deleted file mode 100644 index 2aeb92dee2..0000000000 --- a/pages/api/availabilities/[id]/edit.ts +++ /dev/null @@ -1,62 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { AvailabilityResponse } from "@lib/types"; -import { - schemaAvailabilityBodyParams, - schemaAvailabilityPublic, - withValidAvailability, -} from "@lib/validations/availability"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/availabilites/{id}/edit: - * patch: - * summary: Edit an existing availability - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the availability to edit - * tags: - * - availabilites - * responses: - * 201: - * description: OK, availability edited successfuly - * model: Availability - * 400: - * description: Bad request. Availability body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function editAvailability(req: NextApiRequest, res: NextApiResponse) { - const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); - const safeBody = await schemaAvailabilityBodyParams.safeParse(req.body); - - if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); - const availability = await prisma.availability.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - const data = schemaAvailabilityPublic.parse(availability); - - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, - error, - }); -} - -export default withMiddleware("HTTP_PATCH")( - withValidQueryIdTransformParseInt(withValidAvailability(editAvailability)) -); diff --git a/pages/api/availabilities/[id]/index.ts b/pages/api/availabilities/[id]/index.ts deleted file mode 100644 index 054c32ee9f..0000000000 --- a/pages/api/availabilities/[id]/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { AvailabilityResponse } from "@lib/types"; -import { schemaAvailabilityPublic } from "@lib/validations/availability"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/availabilites/{id}: - * get: - * summary: Get a availability by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the availability to get - * tags: - * - availabilites - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Availability was not found - */ -export async function availabilityById(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query"); - - const availability = await prisma.availability.findUnique({ where: { id: safe.data.id } }); - const data = schemaAvailabilityPublic.parse(availability); - - if (availability) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "Availability was not found", - error, - }); -} - -export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(availabilityById)); diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts new file mode 100644 index 0000000000..8c804321e0 --- /dev/null +++ b/pages/api/booking-references/[id].ts @@ -0,0 +1,138 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BookingReferenceResponse } from "@lib/types"; +import { + schemaBookingReferenceBodyParams, + schemaBookingReferencePublic, +} from "@lib/validations/booking-reference"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /api/booking-references/{id}: + * get: + * summary: Get a daily event reference by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the daily event reference to get + * tags: + * - booking-references + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: BookingReference was not found + * patch: + * summary: Edit an existing daily event reference + * consumes: + * - application/json + * parameters: + * - in: body + * name: bookingReference + * description: The bookingReference to edit + * schema: + * type: object + * $ref: '#/components/schemas/BookingReference' + * required: true + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the daily event reference to edit + * tags: + * - booking-references + * responses: + * 201: + * description: OK, bookingReference edited successfuly + * model: BookingReference + * 400: + * description: Bad request. BookingReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + * delete: + * summary: Remove an existing daily event reference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the daily event reference to delete + * tags: + * - booking-references + * responses: + * 201: + * description: OK, bookingReference removed successfuly + * model: BookingReference + * 400: + * description: Bad request. BookingReference id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function bookingReferenceById( + req: NextApiRequest, + res: NextApiResponse +) { + const { method, query, body } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaBookingReferenceBodyParams.safeParse(body); + if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + + switch (method) { + case "GET": + await prisma.bookingReference + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data) => schemaBookingReferencePublic.parse(data)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `BookingReference with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "PATCH": + if (!safeBody.success) throw new Error("Invalid request body"); + await prisma.bookingReference + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((bookingReference) => schemaBookingReferencePublic.parse(bookingReference)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `BookingReference with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "DELETE": + await prisma.bookingReference + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ message: `BookingReference with id: ${safeQuery.data.id} deleted` }) + ) + .catch((error: Error) => + res.status(404).json({ message: `BookingReference with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } +} + +export default withMiddleware("HTTP_GET_DELETE_PATCH")( + withValidQueryIdTransformParseInt(bookingReferenceById) +); diff --git a/pages/api/booking-references/[id]/delete.ts b/pages/api/booking-references/[id]/delete.ts deleted file mode 100644 index 1fb0f32eb2..0000000000 --- a/pages/api/booking-references/[id]/delete.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BaseResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/booking-references/{id}/delete: - * delete: - * summary: Remove an existing bookingReference - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the bookingReference to delete - * tags: - * - booking-references - * responses: - * 201: - * description: OK, bookingReference removed successfuly - * model: BookingReference - * 400: - * description: Bad request. BookingReference id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function deleteBookingReference(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query", safe.error); - - const data = await prisma.bookingReference.delete({ where: { id: safe.data.id } }); - - if (data) - res.status(200).json({ message: `BookingReference with id: ${safe.data.id} deleted successfully` }); - else - (error: Error) => - res.status(400).json({ - message: `BookingReference with id: ${safe.data.id} was not able to be processed`, - error, - }); -} - -export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteBookingReference)); diff --git a/pages/api/booking-references/[id]/edit.ts b/pages/api/booking-references/[id]/edit.ts deleted file mode 100644 index 60c5d53316..0000000000 --- a/pages/api/booking-references/[id]/edit.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BookingReferenceResponse } from "@lib/types"; -import { - schemaBookingReferenceBodyParams, - schemaBookingReferencePublic, - withValidBookingReference, -} from "@lib/validations/booking-reference"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/booking-references/{id}/edit: - * patch: - * summary: Edit an existing bookingReference - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the bookingReference to edit - * tags: - * - booking-references - * responses: - * 201: - * description: OK, bookingReference edited successfuly - * model: BookingReference - * 400: - * description: Bad request. BookingReference body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function editBookingReference( - req: NextApiRequest, - res: NextApiResponse -) { - const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); - const safeBody = await schemaBookingReferenceBodyParams.safeParse(req.body); - - if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); - const bookingReference = await prisma.bookingReference.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - const data = schemaBookingReferencePublic.parse(bookingReference); - - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, - error, - }); -} - -export default withMiddleware("HTTP_PATCH")( - withValidQueryIdTransformParseInt(withValidBookingReference(editBookingReference)) -); diff --git a/pages/api/booking-references/[id]/index.ts b/pages/api/booking-references/[id]/index.ts deleted file mode 100644 index e71f6920d7..0000000000 --- a/pages/api/booking-references/[id]/index.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BookingReferenceResponse } from "@lib/types"; -import { schemaBookingReferencePublic } from "@lib/validations/booking-reference"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/booking-references/{id}: - * get: - * summary: Get a bookingReference by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the bookingReference to get - * tags: - * - booking-references - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: BookingReference was not found - */ -export async function bookingReferenceById( - req: NextApiRequest, - res: NextApiResponse -) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query"); - - const bookingReference = await prisma.bookingReference.findUnique({ where: { id: safe.data.id } }); - const data = schemaBookingReferencePublic.parse(bookingReference); - - if (bookingReference) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "BookingReference was not found", - error, - }); -} - -export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(bookingReferenceById)); diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts new file mode 100644 index 0000000000..57b817464d --- /dev/null +++ b/pages/api/bookings/[id].ts @@ -0,0 +1,130 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { BookingResponse } from "@lib/types"; +import { schemaBookingBodyParams, schemaBookingPublic } from "@lib/validations/booking"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /api/bookings/{id}: + * get: + * summary: Get a booking by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the booking to get + * tags: + * - bookings + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Booking was not found + * patch: + * summary: Edit an existing booking + * consumes: + * - application/json + * parameters: + * - in: body + * name: booking + * description: The booking to edit + * schema: + * type: object + * $ref: '#/components/schemas/Booking' + * required: true + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the booking to edit + * tags: + * - bookings + * responses: + * 201: + * description: OK, booking edited successfuly + * model: Booking + * 400: + * description: Bad request. Booking body is invalid. + * 401: + * description: Authorization information is missing or invalid. + * delete: + * summary: Remove an existing booking + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the booking to delete + * tags: + * - bookings + * responses: + * 201: + * description: OK, booking removed successfuly + * model: Booking + * 400: + * description: Bad request. Booking id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function bookingById(req: NextApiRequest, res: NextApiResponse) { + const { method, query, body } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaBookingBodyParams.safeParse(body); + if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + + switch (method) { + case "GET": + await prisma.booking + .findUnique({ where: { id: safeQuery.data.id } }) + .then((booking) => schemaBookingPublic.parse(booking)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `Booking with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "PATCH": + if (!safeBody.success) throw new Error("Invalid request body"); + await prisma.booking + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((booking) => schemaBookingPublic.parse(booking)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `Booking with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "DELETE": + await prisma.booking + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ message: `Booking with id: ${safeQuery.data.id} deleted successfully` }) + ) + .catch((error: Error) => + res.status(404).json({ message: `Booking with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } +} + +export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(bookingById)); diff --git a/pages/api/bookings/[id]/delete.ts b/pages/api/bookings/[id]/delete.ts deleted file mode 100644 index 3905a93b03..0000000000 --- a/pages/api/bookings/[id]/delete.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BaseResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/bookings/{id}/delete: - * delete: - * summary: Remove an existing booking - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the booking to delete - * tags: - * - bookings - * responses: - * 201: - * description: OK, booking removed successfuly - * model: Booking - * 400: - * description: Bad request. Booking id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function deleteBooking(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query", safe.error); - - const data = await prisma.booking.delete({ where: { id: safe.data.id } }); - - if (data) res.status(200).json({ message: `Booking with id: ${safe.data.id} deleted successfully` }); - else - (error: Error) => - res.status(400).json({ - message: `Booking with id: ${safe.data.id} was not able to be processed`, - error, - }); -} - -export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteBooking)); diff --git a/pages/api/bookings/[id]/edit.ts b/pages/api/bookings/[id]/edit.ts deleted file mode 100644 index fffc48c221..0000000000 --- a/pages/api/bookings/[id]/edit.ts +++ /dev/null @@ -1,56 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BookingResponse } from "@lib/types"; -import { schemaBookingBodyParams, schemaBookingPublic, withValidBooking } from "@lib/validations/booking"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/bookings/{id}/edit: - * patch: - * summary: Edit an existing booking - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the booking to edit - * tags: - * - bookings - * responses: - * 201: - * description: OK, booking edited successfuly - * model: Booking - * 400: - * description: Bad request. Booking body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function editBooking(req: NextApiRequest, res: NextApiResponse) { - const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); - const safeBody = await schemaBookingBodyParams.safeParse(req.body); - - if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); - const booking = await prisma.booking.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - const data = schemaBookingPublic.parse(booking); - - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, - error, - }); -} - -export default withMiddleware("HTTP_PATCH")(withValidQueryIdTransformParseInt(withValidBooking(editBooking))); diff --git a/pages/api/bookings/[id]/index.ts b/pages/api/bookings/[id]/index.ts deleted file mode 100644 index c2b47d737f..0000000000 --- a/pages/api/bookings/[id]/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BookingResponse } from "@lib/types"; -import { schemaBookingPublic } from "@lib/validations/booking"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/bookings/{id}: - * get: - * summary: Get a booking by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the booking to get - * tags: - * - bookings - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Booking was not found - */ -export async function bookingById(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query"); - - const booking = await prisma.booking.findUnique({ where: { id: safe.data.id } }); - const data = schemaBookingPublic.parse(booking); - - if (booking) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "Booking was not found", - error, - }); -} - -export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(bookingById)); diff --git a/pages/api/credentials/[id].ts b/pages/api/credentials/[id].ts new file mode 100644 index 0000000000..cc48ffab6a --- /dev/null +++ b/pages/api/credentials/[id].ts @@ -0,0 +1,130 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { CredentialResponse } from "@lib/types"; +import { schemaCredentialBodyParams, schemaCredentialPublic } from "@lib/validations/credential"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /api/credentials/{id}: + * get: + * summary: Get a credential by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the credential to get + * tags: + * - credentials + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Credential was not found + * patch: + * summary: Edit an existing credential + * consumes: + * - application/json + * parameters: + * - in: body + * name: credential + * description: The credential to edit + * schema: + * type: object + * $ref: '#/components/schemas/Credential' + * required: true + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the credential to edit + * tags: + * - credentials + * responses: + * 201: + * description: OK, credential edited successfuly + * model: Credential + * 400: + * description: Bad request. Credential body is invalid. + * 401: + * description: Authorization information is missing or invalid. + * delete: + * summary: Remove an existing credential + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the credential to delete + * tags: + * - credentials + * responses: + * 201: + * description: OK, credential removed successfuly + * model: Credential + * 400: + * description: Bad request. Credential id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function credentialById(req: NextApiRequest, res: NextApiResponse) { + const { method, query, body } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaCredentialBodyParams.safeParse(body); + if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + + switch (method) { + case "GET": + await prisma.credential + .findUnique({ where: { id: safeQuery.data.id } }) + .then((credential) => schemaCredentialPublic.parse(credential)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `Credential with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "PATCH": + if (!safeBody.success) throw new Error("Invalid request body"); + await prisma.credential + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((credential) => schemaCredentialPublic.parse(credential)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `Credential with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "DELETE": + await prisma.credential + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ message: `Credential with id: ${safeQuery.data.id} deleted successfully` }) + ) + .catch((error: Error) => + res.status(404).json({ message: `Credential with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } +} + +export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(credentialById)); diff --git a/pages/api/credentials/[id]/delete.ts b/pages/api/credentials/[id]/delete.ts deleted file mode 100644 index 49e4918792..0000000000 --- a/pages/api/credentials/[id]/delete.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BaseResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/credentials/{id}/delete: - * delete: - * summary: Remove an existing credential - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the credential to delete - * tags: - * - credentials - * responses: - * 201: - * description: OK, credential removed successfuly - * model: Credential - * 400: - * description: Bad request. Credential id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function deleteCredential(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query", safe.error); - - const data = await prisma.credential.delete({ where: { id: safe.data.id } }); - - if (data) res.status(200).json({ message: `Credential with id: ${safe.data.id} deleted successfully` }); - else - (error: Error) => - res.status(400).json({ - message: `Credential with id: ${safe.data.id} was not able to be processed`, - error, - }); -} - -export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteCredential)); diff --git a/pages/api/credentials/[id]/edit.ts b/pages/api/credentials/[id]/edit.ts deleted file mode 100644 index 69883de41e..0000000000 --- a/pages/api/credentials/[id]/edit.ts +++ /dev/null @@ -1,62 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { CredentialResponse } from "@lib/types"; -import { - schemaCredentialBodyParams, - schemaCredentialPublic, - withValidCredential, -} from "@lib/validations/credential"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/credentials/{id}/edit: - * patch: - * summary: Edit an existing credential - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the credential to edit - * tags: - * - credentials - * responses: - * 201: - * description: OK, credential edited successfuly - * model: Credential - * 400: - * description: Bad request. Credential body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function editCredential(req: NextApiRequest, res: NextApiResponse) { - const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); - const safeBody = await schemaCredentialBodyParams.safeParse(req.body); - - if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); - const credential = await prisma.credential.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - const data = schemaCredentialPublic.parse(credential); - - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, - error, - }); -} - -export default withMiddleware("HTTP_PATCH")( - withValidQueryIdTransformParseInt(withValidCredential(editCredential)) -); diff --git a/pages/api/credentials/[id]/index.ts b/pages/api/credentials/[id]/index.ts deleted file mode 100644 index f20fa4ba5c..0000000000 --- a/pages/api/credentials/[id]/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { CredentialResponse } from "@lib/types"; -import { schemaCredentialPublic } from "@lib/validations/credential"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/credentials/{id}: - * get: - * summary: Get a credential by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the credential to get - * tags: - * - credentials - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Credential was not found - */ -export async function credentialById(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query"); - - const credential = await prisma.credential.findUnique({ where: { id: safe.data.id } }); - const data = schemaCredentialPublic.parse(credential); - - if (credential) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "Credential was not found", - error, - }); -} - -export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(credentialById)); diff --git a/pages/api/daily-event-references/[id].ts b/pages/api/daily-event-references/[id].ts new file mode 100644 index 0000000000..21072a7a4e --- /dev/null +++ b/pages/api/daily-event-references/[id].ts @@ -0,0 +1,144 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { DailyEventReferenceResponse } from "@lib/types"; +import { + schemaDailyEventReferenceBodyParams, + schemaDailyEventReferencePublic, +} from "@lib/validations/daily-event-reference"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /api/daily-event-references/{id}: + * get: + * summary: Get a daily event reference by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the daily event reference to get + * tags: + * - daily-event-references + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: DailyEventReference was not found + * patch: + * summary: Edit an existing daily event reference + * consumes: + * - application/json + * parameters: + * - in: body + * name: dailyEventReference + * description: The dailyEventReference to edit + * schema: + * type: object + * $ref: '#/components/schemas/DailyEventReference' + * required: true + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the daily event reference to edit + * tags: + * - daily-event-references + * responses: + * 201: + * description: OK, dailyEventReference edited successfuly + * model: DailyEventReference + * 400: + * description: Bad request. DailyEventReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + * delete: + * summary: Remove an existing daily event reference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the daily event reference to delete + * tags: + * - daily-event-references + * responses: + * 201: + * description: OK, dailyEventReference removed successfuly + * model: DailyEventReference + * 400: + * description: Bad request. DailyEventReference id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function dailyEventReferenceById( + req: NextApiRequest, + res: NextApiResponse +) { + const { method, query, body } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaDailyEventReferenceBodyParams.safeParse(body); + if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + + switch (method) { + case "GET": + await prisma.dailyEventReference + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data) => schemaDailyEventReferencePublic.parse(data)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res + .status(404) + .json({ message: `DailyEventReference with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "PATCH": + if (!safeBody.success) throw new Error("Invalid request body"); + await prisma.dailyEventReference + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((dailyEventReference) => schemaDailyEventReferencePublic.parse(dailyEventReference)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res + .status(404) + .json({ message: `DailyEventReference with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "DELETE": + await prisma.dailyEventReference + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ message: `DailyEventReference with id: ${safeQuery.data.id} deleted` }) + ) + .catch((error: Error) => + res + .status(404) + .json({ message: `DailyEventReference with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } +} + +export default withMiddleware("HTTP_GET_DELETE_PATCH")( + withValidQueryIdTransformParseInt(dailyEventReferenceById) +); diff --git a/pages/api/daily-event-references/[id]/delete.ts b/pages/api/daily-event-references/[id]/delete.ts deleted file mode 100644 index 1e020c65ff..0000000000 --- a/pages/api/daily-event-references/[id]/delete.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BaseResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/daily-event-references/{id}/delete: - * delete: - * summary: Remove an existing dailyEventReference - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the dailyEventReference to delete - * tags: - * - daily-event-references - * responses: - * 201: - * description: OK, dailyEventReference removed successfuly - * model: DailyEventReference - * 400: - * description: Bad request. DailyEventReference id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function deleteDailyEventReference(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query", safe.error); - - const data = await prisma.dailyEventReference.delete({ where: { id: safe.data.id } }); - - if (data) - res.status(200).json({ message: `DailyEventReference with id: ${safe.data.id} deleted successfully` }); - else - (error: Error) => - res.status(400).json({ - message: `DailyEventReference with id: ${safe.data.id} was not able to be processed`, - error, - }); -} - -export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteDailyEventReference)); diff --git a/pages/api/daily-event-references/[id]/edit.ts b/pages/api/daily-event-references/[id]/edit.ts deleted file mode 100644 index b090962717..0000000000 --- a/pages/api/daily-event-references/[id]/edit.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { DailyEventReferenceResponse } from "@lib/types"; -import { - schemaDailyEventReferenceBodyParams, - schemaDailyEventReferencePublic, - withValidDailyEventReference, -} from "@lib/validations/daily-event-reference"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/daily-event-references/{id}/edit: - * patch: - * summary: Edit an existing dailyEventReference - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the dailyEventReference to edit - * tags: - * - daily-event-references - * responses: - * 201: - * description: OK, dailyEventReference edited successfuly - * model: DailyEventReference - * 400: - * description: Bad request. DailyEventReference body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function editDailyEventReference( - req: NextApiRequest, - res: NextApiResponse -) { - const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); - const safeBody = await schemaDailyEventReferenceBodyParams.safeParse(req.body); - - if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); - const dailyEventReference = await prisma.dailyEventReference.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - const data = schemaDailyEventReferencePublic.parse(dailyEventReference); - - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, - error, - }); -} - -export default withMiddleware("HTTP_PATCH")( - withValidQueryIdTransformParseInt(withValidDailyEventReference(editDailyEventReference)) -); diff --git a/pages/api/daily-event-references/[id]/index.ts b/pages/api/daily-event-references/[id]/index.ts deleted file mode 100644 index 2ff523bc41..0000000000 --- a/pages/api/daily-event-references/[id]/index.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { DailyEventReferenceResponse } from "@lib/types"; -import { schemaDailyEventReferencePublic } from "@lib/validations/daily-event-reference"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/daily-event-references/{id}: - * get: - * summary: Get a dailyEventReference by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the dailyEventReference to get - * tags: - * - daily-event-references - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: DailyEventReference was not found - */ -export async function dailyEventReferenceById( - req: NextApiRequest, - res: NextApiResponse -) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query"); - - const dailyEventReference = await prisma.dailyEventReference.findUnique({ where: { id: safe.data.id } }); - const data = schemaDailyEventReferencePublic.parse(dailyEventReference); - - if (dailyEventReference) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "DailyEventReference was not found", - error, - }); -} - -export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(dailyEventReferenceById)); diff --git a/pages/api/destination-calendars/[id].ts b/pages/api/destination-calendars/[id].ts new file mode 100644 index 0000000000..a08406f9fa --- /dev/null +++ b/pages/api/destination-calendars/[id].ts @@ -0,0 +1,144 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { DestinationCalendarResponse } from "@lib/types"; +import { + schemaDestinationCalendarBodyParams, + schemaDestinationCalendarPublic, +} from "@lib/validations/destination-calendar"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /api/destination-calendars/{id}: + * get: + * summary: Get a destination calendar by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the destination calendar to get + * tags: + * - destination-calendars + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: DestinationCalendar was not found + * patch: + * summary: Edit an existing destination calendar + * consumes: + * - application/json + * parameters: + * - in: body + * name: destinationCalendar + * description: The destinationCalendar to edit + * schema: + * type: object + * $ref: '#/components/schemas/DestinationCalendar' + * required: true + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the destination calendar to edit + * tags: + * - destination-calendars + * responses: + * 201: + * description: OK, destinationCalendar edited successfuly + * model: DestinationCalendar + * 400: + * description: Bad request. DestinationCalendar body is invalid. + * 401: + * description: Authorization information is missing or invalid. + * delete: + * summary: Remove an existing destination calendar + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the destination calendar to delete + * tags: + * - destination-calendars + * responses: + * 201: + * description: OK, destinationCalendar removed successfuly + * model: DestinationCalendar + * 400: + * description: Bad request. DestinationCalendar id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function destionationCalendarById( + req: NextApiRequest, + res: NextApiResponse +) { + const { method, query, body } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaDestinationCalendarBodyParams.safeParse(body); + if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + + switch (method) { + case "GET": + await prisma.destinationCalendar + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data) => schemaDestinationCalendarPublic.parse(data)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res + .status(404) + .json({ message: `DestinationCalendar with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "PATCH": + if (!safeBody.success) throw new Error("Invalid request body"); + await prisma.destinationCalendar + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((destinationCalendar) => schemaDestinationCalendarPublic.parse(destinationCalendar)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res + .status(404) + .json({ message: `DestinationCalendar with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "DELETE": + await prisma.destinationCalendar + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ message: `DestinationCalendar with id: ${safeQuery.data.id} deleted` }) + ) + .catch((error: Error) => + res + .status(404) + .json({ message: `DestinationCalendar with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } +} + +export default withMiddleware("HTTP_GET_DELETE_PATCH")( + withValidQueryIdTransformParseInt(destionationCalendarById) +); diff --git a/pages/api/destination-calendars/[id]/delete.ts b/pages/api/destination-calendars/[id]/delete.ts deleted file mode 100644 index 1bf35128f9..0000000000 --- a/pages/api/destination-calendars/[id]/delete.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BaseResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/destination-calendars/{id}/delete: - * delete: - * summary: Remove an existing destinationCalendar - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the destinationCalendar to delete - * tags: - * - destination-calendars - * responses: - * 201: - * description: OK, destinationCalendar removed successfuly - * model: DestinationCalendar - * 400: - * description: Bad request. DestinationCalendar id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function deleteDestinationCalendar(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query", safe.error); - - const data = await prisma.destinationCalendar.delete({ where: { id: safe.data.id } }); - - if (data) - res.status(200).json({ message: `DestinationCalendar with id: ${safe.data.id} deleted successfully` }); - else - (error: Error) => - res.status(400).json({ - message: `DestinationCalendar with id: ${safe.data.id} was not able to be processed`, - error, - }); -} - -export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteDestinationCalendar)); diff --git a/pages/api/destination-calendars/[id]/edit.ts b/pages/api/destination-calendars/[id]/edit.ts deleted file mode 100644 index ab09db2f4d..0000000000 --- a/pages/api/destination-calendars/[id]/edit.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { DestinationCalendarResponse } from "@lib/types"; -import { - schemaDestinationCalendarBodyParams, - schemaDestinationCalendarPublic, - withValidDestinationCalendar, -} from "@lib/validations/destination-calendar"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/destination-calendars/{id}/edit: - * patch: - * summary: Edit an existing destinationCalendar - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the destinationCalendar to edit - * tags: - * - destination-calendars - * responses: - * 201: - * description: OK, destinationCalendar edited successfuly - * model: DestinationCalendar - * 400: - * description: Bad request. DestinationCalendar body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function editDestinationCalendar( - req: NextApiRequest, - res: NextApiResponse -) { - const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); - const safeBody = await schemaDestinationCalendarBodyParams.safeParse(req.body); - - if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); - const destinationCalendar = await prisma.destinationCalendar.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - const data = schemaDestinationCalendarPublic.parse(destinationCalendar); - - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, - error, - }); -} - -export default withMiddleware("HTTP_PATCH")( - withValidQueryIdTransformParseInt(withValidDestinationCalendar(editDestinationCalendar)) -); diff --git a/pages/api/destination-calendars/[id]/index.ts b/pages/api/destination-calendars/[id]/index.ts deleted file mode 100644 index 4a7474ff7c..0000000000 --- a/pages/api/destination-calendars/[id]/index.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { DestinationCalendarResponse } from "@lib/types"; -import { schemaDestinationCalendarPublic } from "@lib/validations/destination-calendar"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/destination-calendars/{id}: - * get: - * summary: Get a destinationCalendar by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the destinationCalendar to get - * tags: - * - destination-calendars - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: DestinationCalendar was not found - */ -export async function destinationCalendarById( - req: NextApiRequest, - res: NextApiResponse -) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query"); - - const destinationCalendar = await prisma.destinationCalendar.findUnique({ where: { id: safe.data.id } }); - const data = schemaDestinationCalendarPublic.parse(destinationCalendar); - - if (destinationCalendar) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "DestinationCalendar was not found", - error, - }); -} - -export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(destinationCalendarById)); diff --git a/pages/api/destination-calendars/index.ts b/pages/api/destination-calendars/index.ts index fc3493bf28..b031b8a27e 100644 --- a/pages/api/destination-calendars/index.ts +++ b/pages/api/destination-calendars/index.ts @@ -10,7 +10,7 @@ import { schemaDestinationCalendarPublic } from "@lib/validations/destination-ca * @swagger * /api/destination-calendars: * get: - * summary: Get all destinationCalendars + * summary: Get all destination calendars * tags: * - destination-calendars * responses: diff --git a/pages/api/destination-calendars/new.ts b/pages/api/destination-calendars/new.ts index eac1e2e110..e98472b216 100644 --- a/pages/api/destination-calendars/new.ts +++ b/pages/api/destination-calendars/new.ts @@ -14,7 +14,7 @@ import { * @swagger * /api/destination-calendars/new: * post: - * summary: Creates a new destinationCalendar + * summary: Creates a new destination calendar * requestBody: * description: Optional description in *Markdown* * required: true diff --git a/pages/api/event-type-custom-inputs/[id].ts b/pages/api/event-type-custom-inputs/[id].ts new file mode 100644 index 0000000000..8b5d29ed8f --- /dev/null +++ b/pages/api/event-type-custom-inputs/[id].ts @@ -0,0 +1,133 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { EventTypeCustomInputResponse } from "@lib/types"; +import { + schemaEventTypeCustomInputBodyParams, + schemaEventTypeCustomInputPublic, +} from "@lib/validations/event-type-custom-input"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /api/event-type-custom-inputs/{id}: + * get: + * summary: Get a eventTypeCustomInput by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the eventTypeCustomInput to get + * tags: + * - event-type-custom-inputs + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * deCustomInputscription: EventType was not found + * patch: + * summary: Edit an existing eventTypeCustomInput + * consumes: + * - application/json + * parameters: + * - in: body + * name: eventTypeCustomInput + * description: The eventTypeCustomInput to edit + * schema: + * type: object + * $ref: '#/comCustomInputponents/schemas/EventType' + * required: true + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the eventTypeCustomInput to edit + * tags: + * - event-type-custom-inputs + * responses: + * 201: + * description: OK, eventTypeCustomInput edited successfuly + * model: EventTypeCustomInput + * 400: + * desCustomInputcription: Bad request. EventType body is invalid. + * 401: + * description: Authorization information is missing or invalid. + * delete: + * summary: Remove an existing eventTypeCustomInput + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the eventTypeCustomInput to delete + * tags: + * - event-type-custom-inputs + * responses: + * 201: + * description: OK, eventTypeCustomInput removed successfuly + * model: EventTypeCustomInput + * 400: + * desCustomInputcription: Bad request. EventType id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function eventTypeById(req: NextApiRequest, res: NextApiResponse) { + const { method, query, body } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaEventTypeCustomInputBodyParams.safeParse(body); + if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + + switch (method) { + case "GET": + await prisma.eventTypeCustomInput + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data) => schemaEventTypeCustomInputPublic.parse(data)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `EventType with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "PATCH": + if (!safeBody.success) throw new Error("Invalid request body"); + await prisma.eventTypeCustomInput + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((eventTypeCustomInput) => schemaEventTypeCustomInputPublic.parse(eventTypeCustomInput)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `EventType with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "DELETE": + await prisma.eventTypeCustomInput + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ message: `CustomInputEventType with id: ${safeQuery.data.id} deleted` }) + ) + .catch((error: Error) => + res.status(404).json({ message: `EventType with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } +} + +export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(eventTypeById)); diff --git a/pages/api/event-type-custom-inputs/[id]/delete.ts b/pages/api/event-type-custom-inputs/[id]/delete.ts deleted file mode 100644 index e9064dd69d..0000000000 --- a/pages/api/event-type-custom-inputs/[id]/delete.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BaseResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/event-type-custom-inputs/{id}/delete: - * delete: - * summary: Remove an existing eventTypeCustomInput - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the eventTypeCustomInput to delete - * tags: - * - event-type-custom-inputs - * responses: - * 201: - * description: OK, eventTypeCustomInput removed successfuly - * model: EventTypeCustomInput - * 400: - * description: Bad request. EventTypeCustomInput id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function deleteEventTypeCustomInput(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query", safe.error); - - const data = await prisma.eventTypeCustomInput.delete({ where: { id: safe.data.id } }); - - if (data) - res.status(200).json({ message: `EventTypeCustomInput with id: ${safe.data.id} deleted successfully` }); - else - (error: Error) => - res.status(400).json({ - message: `EventTypeCustomInput with id: ${safe.data.id} was not able to be processed`, - error, - }); -} - -export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteEventTypeCustomInput)); diff --git a/pages/api/event-type-custom-inputs/[id]/edit.ts b/pages/api/event-type-custom-inputs/[id]/edit.ts deleted file mode 100644 index 0357d22aff..0000000000 --- a/pages/api/event-type-custom-inputs/[id]/edit.ts +++ /dev/null @@ -1,65 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { EventTypeCustomInputResponse } from "@lib/types"; -import { - schemaEventTypeCustomInputBodyParams, - schemaEventTypeCustomInputPublic, - withValidEventTypeCustomInput, -} from "@lib/validations/event-type-custom-input"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/event-type-custom-inputs/{id}/edit: - * patch: - * summary: Edit an existing eventTypeCustomInput - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the eventTypeCustomInput to edit - * tags: - * - event-type-custom-inputs - * responses: - * 201: - * description: OK, eventTypeCustomInput edited successfuly - * model: EventTypeCustomInput - * 400: - * description: Bad request. EventTypeCustomInput body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function editEventTypeCustomInput( - req: NextApiRequest, - res: NextApiResponse -) { - const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); - const safeBody = await schemaEventTypeCustomInputBodyParams.safeParse(req.body); - - if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); - const eventTypeCustomInput = await prisma.eventTypeCustomInput.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - const data = schemaEventTypeCustomInputPublic.parse(eventTypeCustomInput); - - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, - error, - }); -} - -export default withMiddleware("HTTP_PATCH")( - withValidQueryIdTransformParseInt(withValidEventTypeCustomInput(editEventTypeCustomInput)) -); diff --git a/pages/api/event-type-custom-inputs/[id]/index.ts b/pages/api/event-type-custom-inputs/[id]/index.ts deleted file mode 100644 index b99b067b9e..0000000000 --- a/pages/api/event-type-custom-inputs/[id]/index.ts +++ /dev/null @@ -1,54 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { EventTypeCustomInputResponse } from "@lib/types"; -import { schemaEventTypeCustomInputPublic } from "@lib/validations/event-type-custom-input"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/event-type-custom-inputs/{id}: - * get: - * summary: Get a eventTypeCustomInput by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the eventTypeCustomInput to get - * tags: - * - event-type-custom-inputs - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: EventTypeCustomInput was not found - */ -export async function eventTypeCustomInputById( - req: NextApiRequest, - res: NextApiResponse -) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query"); - - const eventTypeCustomInput = await prisma.eventTypeCustomInput.findUnique({ where: { id: safe.data.id } }); - const data = schemaEventTypeCustomInputPublic.parse(eventTypeCustomInput); - - if (eventTypeCustomInput) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "EventTypeCustomInput was not found", - error, - }); -} - -export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(eventTypeCustomInputById)); diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts new file mode 100644 index 0000000000..bf94bcdfa0 --- /dev/null +++ b/pages/api/event-types/[id].ts @@ -0,0 +1,128 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { EventTypeResponse } from "@lib/types"; +import { schemaEventTypeBodyParams, schemaEventTypePublic } from "@lib/validations/event-type"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /api/event-types/{id}: + * get: + * summary: Get a eventType by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the eventType to get + * tags: + * - event-types + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: EventType was not found + * patch: + * summary: Edit an existing eventType + * consumes: + * - application/json + * parameters: + * - in: body + * name: eventType + * description: The eventType to edit + * schema: + * type: object + * $ref: '#/components/schemas/EventType' + * required: true + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the eventType to edit + * tags: + * - event-types + * responses: + * 201: + * description: OK, eventType edited successfuly + * model: EventType + * 400: + * description: Bad request. EventType body is invalid. + * 401: + * description: Authorization information is missing or invalid. + * delete: + * summary: Remove an existing eventType + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the eventType to delete + * tags: + * - event-types + * responses: + * 201: + * description: OK, eventType removed successfuly + * model: EventType + * 400: + * description: Bad request. EventType id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function eventTypeById(req: NextApiRequest, res: NextApiResponse) { + const { method, query, body } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaEventTypeBodyParams.safeParse(body); + if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + + switch (method) { + case "GET": + await prisma.eventType + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data) => schemaEventTypePublic.parse(data)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `EventType with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "PATCH": + if (!safeBody.success) throw new Error("Invalid request body"); + await prisma.eventType + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((eventType) => schemaEventTypePublic.parse(eventType)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `EventType with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "DELETE": + await prisma.eventType + .delete({ where: { id: safeQuery.data.id } }) + .then(() => res.status(200).json({ message: `EventType with id: ${safeQuery.data.id} deleted` })) + .catch((error: Error) => + res.status(404).json({ message: `EventType with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } +} + +export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(eventTypeById)); diff --git a/pages/api/event-types/[id]/delete.ts b/pages/api/event-types/[id]/delete.ts deleted file mode 100644 index 1009a97e05..0000000000 --- a/pages/api/event-types/[id]/delete.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BaseResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/event-types/{id}/delete: - * delete: - * summary: Remove an existing eventType - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the eventType to delete - * tags: - * - event-types - * responses: - * 201: - * description: OK, eventType removed successfuly - * model: EventType - * 400: - * description: Bad request. EventType id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function deleteEventType(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query", safe.error); - - const data = await prisma.eventType.delete({ where: { id: safe.data.id } }); - - if (data) res.status(200).json({ message: `EventType with id: ${safe.data.id} deleted successfully` }); - else - (error: Error) => - res.status(400).json({ - message: `EventType with id: ${safe.data.id} was not able to be processed`, - error, - }); -} - -export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteEventType)); diff --git a/pages/api/event-types/[id]/edit.ts b/pages/api/event-types/[id]/edit.ts deleted file mode 100644 index 785774c0b6..0000000000 --- a/pages/api/event-types/[id]/edit.ts +++ /dev/null @@ -1,62 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { EventTypeResponse } from "@lib/types"; -import { - schemaEventTypeBodyParams, - schemaEventTypePublic, - withValidEventType, -} from "@lib/validations/event-type"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/event-types/{id}/edit: - * patch: - * summary: Edits an existing eventType - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the eventType to delete - * tags: - * - event-types - * responses: - * 201: - * description: OK, eventType edited successfuly - * model: EventType - * 400: - * description: Bad request. EventType body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function editEventType(req: NextApiRequest, res: NextApiResponse) { - const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); - const safeBody = await schemaEventTypeBodyParams.safeParse(req.body); - - if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); - const eventType = await prisma.eventType.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - const data = schemaEventTypePublic.parse(eventType); - - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, - error, - }); -} - -export default withMiddleware("HTTP_PATCH")( - withValidQueryIdTransformParseInt(withValidEventType(editEventType)) -); diff --git a/pages/api/event-types/[id]/index.ts b/pages/api/event-types/[id]/index.ts deleted file mode 100644 index 645708813d..0000000000 --- a/pages/api/event-types/[id]/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { EventTypeResponse } from "@lib/types"; -import { schemaEventTypePublic } from "@lib/validations/event-type"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/event-types/{id}: - * get: - * summary: find eventType by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the eventType to get - * tags: - * - event-types - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: EventType was not found - */ -export async function eventTypeById(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query"); - - const eventType = await prisma.eventType.findUnique({ where: { id: safe.data.id } }); - const data = schemaEventTypePublic.parse(eventType); - - if (eventType) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "EventType was not found", - error, - }); -} - -export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(eventTypeById)); diff --git a/pages/api/payments/[id].ts b/pages/api/payments/[id].ts new file mode 100644 index 0000000000..a9ee3c78fe --- /dev/null +++ b/pages/api/payments/[id].ts @@ -0,0 +1,130 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { PaymentResponse } from "@lib/types"; +import { schemaPaymentBodyParams, schemaPaymentPublic } from "@lib/validations/payment"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /api/payments/{id}: + * get: + * summary: Get a payment by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the payment to get + * tags: + * - payments + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Payment was not found + * patch: + * summary: Edit an existing payment + * consumes: + * - application/json + * parameters: + * - in: body + * name: payment + * description: The payment to edit + * schema: + * type: object + * $ref: '#/components/schemas/Payment' + * required: true + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the payment to edit + * tags: + * - payments + * responses: + * 201: + * description: OK, payment edited successfuly + * model: Payment + * 400: + * description: Bad request. Payment body is invalid. + * 401: + * description: Authorization information is missing or invalid. + * delete: + * summary: Remove an existing payment + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the payment to delete + * tags: + * - payments + * responses: + * 201: + * description: OK, payment removed successfuly + * model: Payment + * 400: + * description: Bad request. Payment id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function paymentById(req: NextApiRequest, res: NextApiResponse) { + const { method, query, body } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaPaymentBodyParams.safeParse(body); + if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + + switch (method) { + case "GET": + await prisma.payment + .findUnique({ where: { id: safeQuery.data.id } }) + .then((payment) => schemaPaymentPublic.parse(payment)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `Payment with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "PATCH": + if (!safeBody.success) throw new Error("Invalid request body"); + await prisma.payment + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((payment) => schemaPaymentPublic.parse(payment)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `Payment with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "DELETE": + await prisma.payment + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ message: `Payment with id: ${safeQuery.data.id} deleted successfully` }) + ) + .catch((error: Error) => + res.status(404).json({ message: `Payment with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } +} + +export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(paymentById)); diff --git a/pages/api/payments/[id]/delete.ts b/pages/api/payments/[id]/delete.ts deleted file mode 100644 index 104fbb0da9..0000000000 --- a/pages/api/payments/[id]/delete.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BaseResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/payments/{id}/delete: - * delete: - * summary: Remove an existing payment - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the payment to delete - * tags: - * - payments - * responses: - * 201: - * description: OK, payment removed successfuly - * model: Payment - * 400: - * description: Bad request. Payment id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function deletePayment(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query", safe.error); - - const data = await prisma.payment.delete({ where: { id: safe.data.id } }); - - if (data) res.status(200).json({ message: `Payment with id: ${safe.data.id} deleted successfully` }); - else - (error: Error) => - res.status(400).json({ - message: `Payment with id: ${safe.data.id} was not able to be processed`, - error, - }); -} - -export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deletePayment)); diff --git a/pages/api/payments/[id]/edit.ts b/pages/api/payments/[id]/edit.ts deleted file mode 100644 index 6b1549d66a..0000000000 --- a/pages/api/payments/[id]/edit.ts +++ /dev/null @@ -1,56 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { PaymentResponse } from "@lib/types"; -import { schemaPaymentBodyParams, schemaPaymentPublic, withValidPayment } from "@lib/validations/payment"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/payments/{id}/edit: - * patch: - * summary: Edit an existing payment - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the payment to edit - * tags: - * - payments - * responses: - * 201: - * description: OK, payment edited successfuly - * model: Payment - * 400: - * description: Bad request. Payment body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function editPayment(req: NextApiRequest, res: NextApiResponse) { - const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); - const safeBody = await schemaPaymentBodyParams.safeParse(req.body); - - if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); - const payment = await prisma.payment.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - const data = schemaPaymentPublic.parse(payment); - - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, - error, - }); -} - -export default withMiddleware("HTTP_PATCH")(withValidQueryIdTransformParseInt(withValidPayment(editPayment))); diff --git a/pages/api/payments/[id]/index.ts b/pages/api/payments/[id]/index.ts deleted file mode 100644 index 5d4fa9547a..0000000000 --- a/pages/api/payments/[id]/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { PaymentResponse } from "@lib/types"; -import { schemaPaymentPublic } from "@lib/validations/payment"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/payments/{id}: - * get: - * summary: Get a payment by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the payment to get - * tags: - * - payments - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Payment was not found - */ -export async function paymentById(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query"); - - const payment = await prisma.payment.findUnique({ where: { id: safe.data.id } }); - const data = schemaPaymentPublic.parse(payment); - - if (payment) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "Payment was not found", - error, - }); -} - -export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(paymentById)); diff --git a/pages/api/reminder-mails/[id].ts b/pages/api/reminder-mails/[id].ts new file mode 100644 index 0000000000..5d101b4c6d --- /dev/null +++ b/pages/api/reminder-mails/[id].ts @@ -0,0 +1,130 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { ReminderMailResponse } from "@lib/types"; +import { schemaReminderMailBodyParams, schemaReminderMailPublic } from "@lib/validations/reminder-mail"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /api/reminder-mails/{id}: + * get: + * summary: Get a reminderMail by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the reminderMail to get + * tags: + * - reminder-mails + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: ReminderMail was not found + * patch: + * summary: Edit an existing reminderMail + * consumes: + * - application/json + * parameters: + * - in: body + * name: reminderMail + * description: The reminderMail to edit + * schema: + * type: object + * $ref: '#/components/schemas/ReminderMail' + * required: true + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the reminderMail to edit + * tags: + * - reminder-mails + * responses: + * 201: + * description: OK, reminderMail edited successfuly + * model: ReminderMail + * 400: + * description: Bad request. ReminderMail body is invalid. + * 401: + * description: Authorization information is missing or invalid. + * delete: + * summary: Remove an existing reminderMail + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the reminderMail to delete + * tags: + * - reminder-mails + * responses: + * 201: + * description: OK, reminderMail removed successfuly + * model: ReminderMail + * 400: + * description: Bad request. ReminderMail id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function reminderMailById(req: NextApiRequest, res: NextApiResponse) { + const { method, query, body } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaReminderMailBodyParams.safeParse(body); + if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + + switch (method) { + case "GET": + await prisma.reminderMail + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data) => schemaReminderMailPublic.parse(data)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `ReminderMail with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "PATCH": + if (!safeBody.success) throw new Error("Invalid request body"); + await prisma.reminderMail + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((reminderMail) => schemaReminderMailPublic.parse(reminderMail)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `ReminderMail with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "DELETE": + await prisma.reminderMail + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ message: `ReminderMail with id: ${safeQuery.data.id} deleted successfully` }) + ) + .catch((error: Error) => + res.status(404).json({ message: `ReminderMail with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } +} + +export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(reminderMailById)); diff --git a/pages/api/reminder-mails/[id]/delete.ts b/pages/api/reminder-mails/[id]/delete.ts deleted file mode 100644 index 6b3bad4fe9..0000000000 --- a/pages/api/reminder-mails/[id]/delete.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BaseResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/reminder-mails/{id}/delete: - * delete: - * summary: Remove an existing reminder mail - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the reminderMail to delete - * tags: - * - reminder-mails - * responses: - * 201: - * description: OK, reminderMail removed successfuly - * model: ReminderMail - * 400: - * description: Bad request. ReminderMail id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function deleteReminderMail(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query", safe.error); - - const data = await prisma.reminderMail.delete({ where: { id: safe.data.id } }); - - if (data) res.status(200).json({ message: `ReminderMail with id: ${safe.data.id} deleted successfully` }); - else - (error: Error) => - res.status(400).json({ - message: `ReminderMail with id: ${safe.data.id} was not able to be processed`, - error, - }); -} - -export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteReminderMail)); diff --git a/pages/api/reminder-mails/[id]/edit.ts b/pages/api/reminder-mails/[id]/edit.ts deleted file mode 100644 index 2fedbb8f86..0000000000 --- a/pages/api/reminder-mails/[id]/edit.ts +++ /dev/null @@ -1,62 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { ReminderMailResponse } from "@lib/types"; -import { - schemaReminderMailBodyParams, - schemaReminderMailPublic, - withValidReminderMail, -} from "@lib/validations/reminder-mail"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/reminder-mails/{id}/edit: - * patch: - * summary: Edit an existing reminder mail - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the reminderMail to edit - * tags: - * - reminder-mails - * responses: - * 201: - * description: OK, reminderMail edited successfuly - * model: ReminderMail - * 400: - * description: Bad request. ReminderMail body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function editReminderMail(req: NextApiRequest, res: NextApiResponse) { - const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); - const safeBody = await schemaReminderMailBodyParams.safeParse(req.body); - - if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); - const reminderMail = await prisma.reminderMail.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - const data = schemaReminderMailPublic.parse(reminderMail); - - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, - error, - }); -} - -export default withMiddleware("HTTP_PATCH")( - withValidQueryIdTransformParseInt(withValidReminderMail(editReminderMail)) -); diff --git a/pages/api/reminder-mails/[id]/index.ts b/pages/api/reminder-mails/[id]/index.ts deleted file mode 100644 index 7b38d22cbe..0000000000 --- a/pages/api/reminder-mails/[id]/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { ReminderMailResponse } from "@lib/types"; -import { schemaReminderMailPublic } from "@lib/validations/reminder-mail"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/reminder-mails/{id}: - * get: - * summary: Get a reminder mail by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the reminderMail to get - * tags: - * - reminder-mails - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: ReminderMail was not found - */ -export async function reminderMailById(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query"); - - const reminderMail = await prisma.reminderMail.findUnique({ where: { id: safe.data.id } }); - const data = schemaReminderMailPublic.parse(reminderMail); - - if (reminderMail) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "ReminderMail was not found", - error, - }); -} - -export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(reminderMailById)); diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts new file mode 100644 index 0000000000..682dc334d2 --- /dev/null +++ b/pages/api/schedules/[id].ts @@ -0,0 +1,130 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { ScheduleResponse } from "@lib/types"; +import { schemaScheduleBodyParams, schemaSchedulePublic } from "@lib/validations/schedule"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /api/schedules/{id}: + * get: + * summary: Get a schedule by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the schedule to get + * tags: + * - schedules + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Schedule was not found + * patch: + * summary: Edit an existing schedule + * consumes: + * - application/json + * parameters: + * - in: body + * name: schedule + * description: The schedule to edit + * schema: + * type: object + * $ref: '#/components/schemas/Schedule' + * required: true + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the schedule to edit + * tags: + * - schedules + * responses: + * 201: + * description: OK, schedule edited successfuly + * model: Schedule + * 400: + * description: Bad request. Schedule body is invalid. + * 401: + * description: Authorization information is missing or invalid. + * delete: + * summary: Remove an existing schedule + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the schedule to delete + * tags: + * - schedules + * responses: + * 201: + * description: OK, schedule removed successfuly + * model: Schedule + * 400: + * description: Bad request. Schedule id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function scheduleById(req: NextApiRequest, res: NextApiResponse) { + const { method, query, body } = req; + const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeBody = await schemaScheduleBodyParams.safeParse(body); + if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + + switch (method) { + case "GET": + await prisma.schedule + .findUnique({ where: { id: safeQuery.data.id } }) + .then((schedule) => schemaSchedulePublic.parse(schedule)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `Schedule with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "PATCH": + if (!safeBody.success) throw new Error("Invalid request body"); + await prisma.schedule + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((schedule) => schemaSchedulePublic.parse(schedule)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `Schedule with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "DELETE": + await prisma.schedule + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ message: `Schedule with id: ${safeQuery.data.id} deleted successfully` }) + ) + .catch((error: Error) => + res.status(404).json({ message: `Schedule with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } +} + +export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(scheduleById)); diff --git a/pages/api/schedules/[id]/delete.ts b/pages/api/schedules/[id]/delete.ts deleted file mode 100644 index 4a85704a21..0000000000 --- a/pages/api/schedules/[id]/delete.ts +++ /dev/null @@ -1,43 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BaseResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/schedules/{id}/delete: - * delete: - * summary: Remove an existing schedule - * tags: - * - schedules - * responses: - * 201: - * description: OK, schedule removed successfuly - * model: Schedule - * 400: - * description: Bad request. Schedule id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function deleteSchedule(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query", safe.error); - - const data = await prisma.schedule.delete({ where: { id: safe.data.id } }); - - if (data) res.status(200).json({ message: `Schedule with id: ${safe.data.id} deleted successfully` }); - else - (error: Error) => - res.status(400).json({ - message: `Schedule with id: ${safe.data.id} was not able to be processed`, - error, - }); -} - -export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteSchedule)); diff --git a/pages/api/schedules/[id]/edit.ts b/pages/api/schedules/[id]/edit.ts deleted file mode 100644 index 97fad524a0..0000000000 --- a/pages/api/schedules/[id]/edit.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { ScheduleResponse } from "@lib/types"; -import { schemaScheduleBodyParams, schemaSchedulePublic, withValidSchedule } from "@lib/validations/schedule"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/schedules/{id}/edit: - * patch: - * summary: Edits an existing schedule - * tags: - * - schedules - * responses: - * 201: - * description: OK, schedule edited successfuly - * model: Schedule - * 400: - * description: Bad request. Schedule body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function editSchedule(req: NextApiRequest, res: NextApiResponse) { - const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); - const safeBody = await schemaScheduleBodyParams.safeParse(req.body); - - if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); - const schedule = await prisma.schedule.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - const data = schemaSchedulePublic.parse(schedule); - - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, - error, - }); -} - -export default withMiddleware("HTTP_PATCH")( - withValidQueryIdTransformParseInt(withValidSchedule(editSchedule)) -); diff --git a/pages/api/schedules/[id]/index.ts b/pages/api/schedules/[id]/index.ts deleted file mode 100644 index 8bdab1fca0..0000000000 --- a/pages/api/schedules/[id]/index.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { ScheduleResponse } from "@lib/types"; -import { schemaSchedulePublic } from "@lib/validations/schedule"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /api/schedules/{id}: - * get: - * summary: Get schedule by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the schedule to delete - * tags: - * - schedules - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Schedule was not found - */ -export async function scheduleById(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query"); - - const schedule = await prisma.schedule.findUnique({ where: { id: safe.data.id } }); - const data = schemaSchedulePublic.parse(schedule); - - if (schedule) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "Schedule was not found", - error, - }); -} - -export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(scheduleById)); diff --git a/pages/api/teams/[id].ts b/pages/api/teams/[id].ts index 49895d6937..21defc76b8 100644 --- a/pages/api/teams/[id].ts +++ b/pages/api/teams/[id].ts @@ -90,7 +90,7 @@ export async function teamById(req: NextApiRequest, res: NextApiResponse schemaTeamPublic.parse(data)) - .then((data: TeamResponse) => res.status(200).json({ data })) + .then((data) => res.status(200).json({ data })) .catch((error: Error) => res.status(404).json({ message: `Team with id: ${safeQuery.data.id} not found`, error }) ); @@ -104,7 +104,7 @@ export async function teamById(req: NextApiRequest, res: NextApiResponse schemaTeamPublic.parse(team)) - .then((data: TeamResponse) => res.status(200).json({ data })) + .then((data) => res.status(200).json({ data })) .catch((error: Error) => res.status(404).json({ message: `Team with id: ${safeQuery.data.id} not found`, error }) ); diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index 35adf9fa08..fa0b4c7255 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -89,8 +89,8 @@ export async function userById(req: NextApiRequest, res: NextApiResponse schemaUserPublic.parse(data)) - .then((data: UserResponse) => res.status(200).json({ data })) + .then((user) => schemaUserPublic.parse(user)) + .then((data) => res.status(200).json({ data })) .catch((error: Error) => res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) ); @@ -104,7 +104,7 @@ export async function userById(req: NextApiRequest, res: NextApiResponse schemaUserPublic.parse(user)) - .then((data: UserResponse) => res.status(200).json({ data })) + .then((data) => res.status(200).json({ data })) .catch((error: Error) => res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) ); diff --git a/prettier.rc.js b/prettier.rc.js deleted file mode 100644 index aa497c0ac5..0000000000 --- a/prettier.rc.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - semi: false, - singleQuote: true, - arrowParens: "avoid", - trailingComma: "none", - endOfLine: "auto", -}; From 89dfa2efe1e7519d84e27cfe8312b94faccf81f7 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 4 Apr 2022 21:39:30 +0200 Subject: [PATCH 073/658] feat all endpoints one id file --- .eslintrc.js | 1 + .eslintrc.json | 17 -- pages/api/memberships/[id].ts | 147 ++++++++++++++++ pages/api/memberships/[id]/delete.ts | 55 ------ pages/api/memberships/[id]/edit.ts | 51 ------ pages/api/memberships/[id]/index.ts | 57 ------- pages/api/payments/[id].ts | 14 +- pages/api/selected-calendars/[id].ts | 177 ++++++++++++++++++++ pages/api/selected-calendars/[id]/delete.ts | 60 ------- pages/api/selected-calendars/[id]/edit.ts | 62 ------- pages/api/selected-calendars/[id]/index.ts | 66 -------- 11 files changed, 332 insertions(+), 375 deletions(-) create mode 100644 .eslintrc.js delete mode 100644 .eslintrc.json create mode 100644 pages/api/memberships/[id].ts delete mode 100644 pages/api/memberships/[id]/delete.ts delete mode 100644 pages/api/memberships/[id]/edit.ts delete mode 100644 pages/api/memberships/[id]/index.ts create mode 100644 pages/api/selected-calendars/[id].ts delete mode 100644 pages/api/selected-calendars/[id]/delete.ts delete mode 100644 pages/api/selected-calendars/[id]/edit.ts delete mode 100644 pages/api/selected-calendars/[id]/index.ts diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000000..0e71ec1eae --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1 @@ +module.exports = require("@calcom/config/eslint-preset"); diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 0378cf43af..0000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,17 +0,0 @@ -// FIXME: import eslint-config-calcom-base from '@calcom/config/eslint -{ - "root": true, - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:prettier/recommended", - "plugin:@next/next/recommended" - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { "project": ["./tsconfig.json"] }, - "plugins": ["@typescript-eslint", "prettier"], - "rules": { - "prettier/prettier": "error" - }, - "ignorePatterns": ["src/**/*.test.ts", "src/frontend/generated/*"] -} diff --git a/pages/api/memberships/[id].ts b/pages/api/memberships/[id].ts new file mode 100644 index 0000000000..d78d0f1c88 --- /dev/null +++ b/pages/api/memberships/[id].ts @@ -0,0 +1,147 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { MembershipResponse } from "@lib/types"; +import { schemaMembershipBodyParams, schemaMembershipPublic } from "@lib/validations/membership"; +import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; + +/** + * @swagger + * /api/memberships/{userId}_{teamId}: + * get: + * summary: Get a membership by userID and teamID + * parameters: + * - in: path + * name: userId + * schema: + * type: integer + * required: true + * description: Numeric userId of the membership to get + * - in: path + * name: teamId + * schema: + * type: integer + * required: true + * description: Numeric teamId of the membership to get + * tags: + * - memberships + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Membership was not found + * patch: + * summary: Edit an existing membership + * consumes: + * - application/json + * parameters: + * - in: body + * name: membership + * description: The membership to edit + * schema: + * type: object + * $ref: '#/components/schemas/Membership' + * required: true + * - in: path + * name: userId + * schema: + * type: integer + * required: true + * description: Numeric userId of the membership to get + * - in: path + * name: teamId + * schema: + * type: integer + * required: true + * description: Numeric teamId of the membership to get + * tags: + * - memberships + * responses: + * 201: + * description: OK, membership edited successfuly + * model: Membership + * 400: + * description: Bad request. Membership body is invalid. + * 401: + * description: Authorization information is missing or invalid. + * delete: + * summary: Remove an existing membership + * parameters: + * - in: path + * name: userId + * schema: + * type: integer + * required: true + * description: Numeric userId of the membership to get + * - in: path + * name: teamId + * schema: + * type: integer + * required: true + * description: Numeric teamId of the membership to get + * tags: + * - memberships + * responses: + * 201: + * description: OK, membership removed successfuly + * model: Membership + * 400: + * description: Bad request. Membership id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function membershipById(req: NextApiRequest, res: NextApiResponse) { + const { method, query, body } = req; + const safeQuery = await schemaQueryIdAsString.safeParse(query); + const safeBody = await schemaMembershipBodyParams.safeParse(body); + if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + // This is how we set the userId and teamId in the query for managing compoundId. + const [userId, teamId] = safeQuery.data.id.split("_"); + + switch (method) { + case "GET": + await prisma.membership + .findUnique({ where: { userId_teamId: { userId: parseInt(userId), teamId: parseInt(teamId) } } }) + .then((membership) => schemaMembershipPublic.parse(membership)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `Membership with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "PATCH": + if (!safeBody.success) throw new Error("Invalid request body"); + await prisma.membership + .update({ + where: { userId_teamId: { userId: parseInt(userId), teamId: parseInt(teamId) } }, + data: safeBody.data, + }) + .then((membership) => schemaMembershipPublic.parse(membership)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `Membership with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "DELETE": + await prisma.membership + .delete({ where: { userId_teamId: { userId: parseInt(userId), teamId: parseInt(teamId) } } }) + .then(() => + res.status(200).json({ message: `Membership with id: ${safeQuery.data.id} deleted successfully` }) + ) + .catch((error: Error) => + res.status(404).json({ message: `Membership with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } +} + +export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdString(membershipById)); diff --git a/pages/api/memberships/[id]/delete.ts b/pages/api/memberships/[id]/delete.ts deleted file mode 100644 index 8eb4e8ae4a..0000000000 --- a/pages/api/memberships/[id]/delete.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BaseResponse } from "@lib/types"; -import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; - -/** - * @swagger - * /api/memberships/{userId}_{teamId}/delete: - * delete: - * summary: Remove an existing membership - * parameters: - * - in: path - * name: userId - * schema: - * type: integer - * required: true - * description: Numeric ID of the user to get the membership of - * - in: path - * name: teamId - * schema: - * type: integer - * required: true - * description: Numeric ID of the team to get the membership of - * tags: - * - memberships - * responses: - * 201: - * description: OK, membership removed successfuly - * model: Membership - * 400: - * description: Bad request. Membership id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function deleteMembership(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdAsString.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query", safe.error); - const [userId, teamId] = safe.data.id.split("_"); - const data = await prisma.membership.delete({ - where: { userId_teamId: { userId: parseInt(userId), teamId: parseInt(teamId) } }, - }); - - if (data) res.status(200).json({ message: `Membership with id: ${safe.data.id} deleted successfully` }); - else - (error: Error) => - res.status(400).json({ - message: `Membership with id: ${safe.data.id} was not able to be processed`, - error, - }); -} - -export default withMiddleware("HTTP_DELETE")(withValidQueryIdString(deleteMembership)); diff --git a/pages/api/memberships/[id]/edit.ts b/pages/api/memberships/[id]/edit.ts deleted file mode 100644 index 66c6ccec24..0000000000 --- a/pages/api/memberships/[id]/edit.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { MembershipResponse } from "@lib/types"; -import { - schemaMembershipBodyParams, - schemaMembershipPublic, - withValidMembership, -} from "@lib/validations/membership"; -import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; - -/** - * @swagger - * /api/memberships/{id}/edit: - * patch: - * summary: Edits an existing membership - * tags: - * - memberships - * responses: - * 201: - * description: OK, membership edited successfuly - * model: Membership - * 400: - * description: Bad request. Membership body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function editMembership(req: NextApiRequest, res: NextApiResponse) { - const safeQuery = await schemaQueryIdAsString.safeParse(req.query); - const safeBody = await schemaMembershipBodyParams.safeParse(req.body); - if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); - const [userId, teamId] = safeQuery.data.id.split("_"); - - const membership = await prisma.membership.update({ - where: { userId_teamId: { userId: parseInt(userId), teamId: parseInt(teamId) } }, - data: safeBody.data, - }); - const data = schemaMembershipPublic.parse(membership); - - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, - error, - }); -} - -export default withMiddleware("HTTP_PATCH")(withValidQueryIdString(withValidMembership(editMembership))); diff --git a/pages/api/memberships/[id]/index.ts b/pages/api/memberships/[id]/index.ts deleted file mode 100644 index a1505f185e..0000000000 --- a/pages/api/memberships/[id]/index.ts +++ /dev/null @@ -1,57 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { MembershipResponse } from "@lib/types"; -import { schemaMembershipPublic } from "@lib/validations/membership"; -import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; - -/** - * @swagger - * /api/memberships/{userId}_{teamId}: - * get: - * summary: find membership by userID and teamID - * parameters: - * - in: path - * name: userId - * schema: - * type: integer - * required: true - * description: Numeric userId of the membership to get - * - in: path - * name: teamId - * schema: - * type: integer - * required: true - * description: Numeric teamId of the membership to get - * tags: - * - memberships - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Membership was not found - */ -export async function membershipById(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdAsString.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query"); - const [userId, teamId] = safe.data.id.split("_"); - - const membership = await prisma.membership.findUnique({ - where: { userId_teamId: { userId: parseInt(userId), teamId: parseInt(teamId) } }, - }); - const data = schemaMembershipPublic.parse(membership); - - if (membership) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "Membership was not found", - error, - }); -} - -export default withMiddleware("HTTP_GET")(withValidQueryIdString(membershipById)); diff --git a/pages/api/payments/[id].ts b/pages/api/payments/[id].ts index a9ee3c78fe..14b106ca43 100644 --- a/pages/api/payments/[id].ts +++ b/pages/api/payments/[id].ts @@ -5,10 +5,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { PaymentResponse } from "@lib/types"; import { schemaPaymentBodyParams, schemaPaymentPublic } from "@lib/validations/payment"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; /** * @swagger @@ -81,14 +78,17 @@ import { */ export async function paymentById(req: NextApiRequest, res: NextApiResponse) { const { method, query, body } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); + const safeQuery = await schemaQueryIdAsString.safeParse(query); const safeBody = await schemaPaymentBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + const [userId, teamId] = safeQuery.data.id.split("_"); switch (method) { case "GET": await prisma.payment - .findUnique({ where: { id: safeQuery.data.id } }) + .findUnique({ + where: { userId_teamId: { userId: parseInt(userId), teamId: parseInt(teamId) } }, + }) .then((payment) => schemaPaymentPublic.parse(payment)) .then((data) => res.status(200).json({ data })) .catch((error: Error) => @@ -127,4 +127,4 @@ export async function paymentById(req: NextApiRequest, res: NextApiResponse +) { + const { method, query, body } = req; + const safeQuery = await schemaQueryIdAsString.safeParse(query); + const safeBody = await schemaSelectedCalendarBodyParams.safeParse(body); + if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + // This is how we set the userId and teamId in the query for managing compoundId. + const [userId, integration, externalId] = safeQuery.data.id.split("_"); + + switch (method) { + case "GET": + await prisma.selectedCalendar + .findUnique({ + where: { + userId_integration_externalId: { + userId: parseInt(userId), + integration: integration, + externalId: externalId, + }, + }, + }) + .then((selectedCalendar) => schemaSelectedCalendarPublic.parse(selectedCalendar)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `SelectedCalendar with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "PATCH": + if (!safeBody.success) throw new Error("Invalid request body"); + await prisma.selectedCalendar + .update({ + where: { + userId_integration_externalId: { + userId: parseInt(userId), + integration: integration, + externalId: externalId, + }, + }, + data: safeBody.data, + }) + .then((selectedCalendar) => schemaSelectedCalendarPublic.parse(selectedCalendar)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `SelectedCalendar with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + case "DELETE": + await prisma.selectedCalendar + .delete({ + where: { + userId_integration_externalId: { + userId: parseInt(userId), + integration: integration, + externalId: externalId, + }, + }, + }) + .then(() => + res + .status(200) + .json({ message: `SelectedCalendar with id: ${safeQuery.data.id} deleted successfully` }) + ) + .catch((error: Error) => + res.status(404).json({ message: `SelectedCalendar with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } +} + +export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdString(selectedCalendarById)); diff --git a/pages/api/selected-calendars/[id]/delete.ts b/pages/api/selected-calendars/[id]/delete.ts deleted file mode 100644 index ec1abebed4..0000000000 --- a/pages/api/selected-calendars/[id]/delete.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BaseResponse } from "@lib/types"; -import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; - -/** - * @swagger - * /api/selected-calendars/{userId}_{teamId}/delete: - * delete: - * summary: Remove an existing record of a selected calendar - * parameters: - * - in: path - * - name: userId - * schema: - * type: integer - * required: true - * description: Numeric ID of the user to get the selected calendar of - * - name: teamId - * schema: - * type: integer - * required: true - * description: Numeric ID of the team to get the selected calendar of - * tags: - * - selected-calendars - * responses: - * 201: - * description: OK, selected calendar removed successfuly - * 400: - * description: Bad request. selected calendar id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function deleteSelectedCalendar(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdAsString.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query", safe.error); - const [userId, integration, externalId] = safe.data.id.split("_"); - const data = await prisma.selectedCalendar.delete({ - where: { - userId_integration_externalId: { - userId: parseInt(userId), - integration: integration, - externalId: externalId, - }, - }, - }); - - if (data) - res.status(200).json({ message: `SelectedCalendar with id: ${safe.data.id} deleted successfully` }); - else - (error: Error) => - res.status(400).json({ - message: `SelectedCalendar with id: ${safe.data.id} was not able to be processed`, - error, - }); -} - -export default withMiddleware("HTTP_DELETE")(withValidQueryIdString(deleteSelectedCalendar)); diff --git a/pages/api/selected-calendars/[id]/edit.ts b/pages/api/selected-calendars/[id]/edit.ts deleted file mode 100644 index c5737eb4e6..0000000000 --- a/pages/api/selected-calendars/[id]/edit.ts +++ /dev/null @@ -1,62 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { SelectedCalendarResponse } from "@lib/types"; -import { - schemaSelectedCalendarBodyParams, - schemaSelectedCalendarPublic, - withValidSelectedCalendar, -} from "@lib/validations/selected-calendar"; -import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; - -/** - * @swagger - * /api/selected-calendars/{id}/edit: - * patch: - * summary: Edits an existing selectedCalendar - * tags: - * - selected-calendars - * responses: - * 201: - * description: OK, selectedCalendar edited successfuly - * model: SelectedCalendar - * 400: - * description: Bad request. SelectedCalendar body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function editSelectedCalendar( - req: NextApiRequest, - res: NextApiResponse -) { - const safeQuery = await schemaQueryIdAsString.safeParse(req.query); - const safeBody = await schemaSelectedCalendarBodyParams.safeParse(req.body); - if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); - const [userId, integration, externalId] = safeQuery.data.id.split("_"); - - const selectedCalendar = await prisma.selectedCalendar.update({ - where: { - userId_integration_externalId: { - userId: parseInt(userId), - integration: integration, - externalId: externalId, - }, - }, - data: safeBody.data, - }); - const data = schemaSelectedCalendarPublic.parse(selectedCalendar); - - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, - error, - }); -} - -export default withMiddleware("HTTP_PATCH")( - withValidQueryIdString(withValidSelectedCalendar(editSelectedCalendar)) -); diff --git a/pages/api/selected-calendars/[id]/index.ts b/pages/api/selected-calendars/[id]/index.ts deleted file mode 100644 index bec8bcc600..0000000000 --- a/pages/api/selected-calendars/[id]/index.ts +++ /dev/null @@ -1,66 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { SelectedCalendarResponse } from "@lib/types"; -import { schemaSelectedCalendarPublic } from "@lib/validations/selected-calendar"; -import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; - -/** - * @swagger - * /api/selected-calendars/{userId}_{teamId}: - * get: - * summary: find selectedCalendar by userID and teamID - * parameters: - * - in: path - * name: userId - * schema: - * type: integer - * required: true - * description: Numeric userId of the selectedCalendar to get - * - in: path - * name: teamId - * schema: - * type: integer - * required: true - * description: Numeric teamId of the selectedCalendar to get - * tags: - * - selected-calendars - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: SelectedCalendar was not found - */ -export async function selectedCalendarById( - req: NextApiRequest, - res: NextApiResponse -) { - const safe = await schemaQueryIdAsString.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query"); - const [userId, integration, externalId] = safe.data.id.split("_"); - - const selectedCalendar = await prisma.selectedCalendar.findUnique({ - where: { - userId_integration_externalId: { - userId: parseInt(userId), - integration: integration, - externalId: externalId, - }, - }, - }); - const data = schemaSelectedCalendarPublic.parse(selectedCalendar); - - if (selectedCalendar) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "SelectedCalendar was not found", - error, - }); -} - -export default withMiddleware("HTTP_GET")(withValidQueryIdString(selectedCalendarById)); From 5b3f9ee95ccfd24f47c155e154e65fa569079211 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 4 Apr 2022 21:53:03 +0200 Subject: [PATCH 074/658] fix availabilities spelling --- lib/types.ts | 2 +- lib/validations/api-key.ts | 23 ----------------------- pages/api/availabilities/index.ts | 20 ++++++++++---------- pages/api/availabilities/new.ts | 4 ++-- 4 files changed, 13 insertions(+), 36 deletions(-) delete mode 100644 lib/validations/api-key.ts diff --git a/lib/types.ts b/lib/types.ts index d5a179f7b3..55c36392bb 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -70,7 +70,7 @@ export type AttendeesResponse = BaseResponse & { export type AvailabilityResponse = BaseResponse & { data?: Partial; }; -export type AvailabilitysResponse = BaseResponse & { +export type AvailabilitiesResponse = BaseResponse & { data?: Partial[]; }; diff --git a/lib/validations/api-key.ts b/lib/validations/api-key.ts deleted file mode 100644 index c0ffd6c9b3..0000000000 --- a/lib/validations/api-key.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { withValidation } from "next-validations"; -import { z } from "zod"; - -import { _ApiKeyModel as ApiKey } from "@calcom/prisma/zod"; - -export const schemaApiKeyBaseBodyParams = ApiKey.omit({ id: true, userId: true, createdAt: true }).partial(); - -const schemaApiKeyRequiredParams = z.object({ - email: z.string().email(), -}); - -export const schemaApiKeyBodyParams = schemaApiKeyBaseBodyParams.merge(schemaApiKeyRequiredParams); - -export const schemaApiKeyPublic = ApiKey.omit({ - id: true, - userId: true, -}); - -export const withValidApiKey = withValidation({ - schema: schemaApiKeyBodyParams, - type: "Zod", - mode: "body", -}); diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index d3a2168565..5449162d95 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -3,35 +3,35 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { AvailabilitysResponse } from "@lib/types"; +import { AvailabilitiesResponse } from "@lib/types"; import { schemaAvailabilityPublic } from "@lib/validations/availability"; /** * @swagger - * /api/availabilites: + * /api/availabilities: * get: - * summary: Get all availabilites + * summary: Get all availabilities * tags: - * - availabilites + * - availabilities * responses: * 200: * description: OK * 401: * description: Authorization information is missing or invalid. * 404: - * description: No availabilites were found + * description: No availabilities were found */ -async function allAvailabilitys(_: NextApiRequest, res: NextApiResponse) { - const availabilites = await prisma.availability.findMany(); - const data = availabilites.map((availability) => schemaAvailabilityPublic.parse(availability)); +async function allAvailabilities(_: NextApiRequest, res: NextApiResponse) { + const availabilities = await prisma.availability.findMany(); + const data = availabilities.map((availability) => schemaAvailabilityPublic.parse(availability)); if (data) res.status(200).json({ data }); else (error: Error) => res.status(404).json({ - message: "No Availabilitys were found", + message: "No Availabilities were found", error, }); } -export default withMiddleware("HTTP_GET")(allAvailabilitys); +export default withMiddleware("HTTP_GET")(allAvailabilities); diff --git a/pages/api/availabilities/new.ts b/pages/api/availabilities/new.ts index d049a42ded..d7461ba803 100644 --- a/pages/api/availabilities/new.ts +++ b/pages/api/availabilities/new.ts @@ -12,7 +12,7 @@ import { /** * @swagger - * /api/availabilites/new: + * /api/availabilities/new: * post: * summary: Creates a new availability * requestBody: @@ -23,7 +23,7 @@ import { * schema: * $ref: '#/components/schemas/Availability' * tags: - * - availabilites + * - availabilities * responses: * 201: * description: OK, availability created From 15cdbb134f11012b4243c4c56aab81f2b04a1543 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 4 Apr 2022 22:29:45 +0200 Subject: [PATCH 075/658] remove console statement --- lib/helpers/verifyApiKey.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 45f8acd9ce..55ee111451 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -17,7 +17,7 @@ export const verifyApiKey: NextMiddleware = async (req, res, next) => { res.status(401).json({ error: "Your api key is not valid" }); throw new Error("No api key found"); } - if (apiKey.expiresAt && apiKey.userId && dateInPast(apiKey.expiresAt, today)) { + if (apiKey.expiresAt && apiKey.userId && dateInPast(today, apiKey.expiresAt)) { res.setHeader("Calcom-User-ID", apiKey.userId); await next(); } else res.status(401).json({ error: "Your api key is not valid" }); From fc2978a61bdbe5b2ca26c96e4284cdfd88978fa8 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 7 Apr 2022 03:29:53 +0200 Subject: [PATCH 076/658] feat: initial work unifying new endpoint and generating api key --- .github/workflows/type-check.yml | 26 ------------ lib/helpers/httpMethods.ts | 5 ++- lib/helpers/withMiddleware.ts | 10 ++++- lib/validations/payment.ts | 4 +- pages/api/attendees/index.ts | 57 ++++++++++++++++++++------ pages/api/attendees/new.ts | 41 ------------------- pages/api/payments/[id].ts | 16 ++++---- templates/newIndex.ts | 68 ++++++++++++++++++++++++++++++++ 8 files changed, 135 insertions(+), 92 deletions(-) delete mode 100644 .github/workflows/type-check.yml delete mode 100644 pages/api/attendees/new.ts create mode 100644 templates/newIndex.ts diff --git a/.github/workflows/type-check.yml b/.github/workflows/type-check.yml deleted file mode 100644 index a8c933d87e..0000000000 --- a/.github/workflows/type-check.yml +++ /dev/null @@ -1,26 +0,0 @@ -name: Check types -on: - pull_request: - branches: - - main -jobs: - types: - name: Check types - strategy: - matrix: - node: ["14.x"] - os: [ubuntu-latest] - runs-on: ${{ matrix.os }} - - steps: - - name: Checkout repo - uses: actions/checkout@v2 - with: - fetch-depth: 0 - - - name: Use Node ${{ matrix.node }} - uses: actions/setup-node@v2 - with: - node-version: ${{ matrix.node }} - - run: yarn - - run: yarn type-check diff --git a/lib/helpers/httpMethods.ts b/lib/helpers/httpMethods.ts index 1454355f3a..0617208a90 100644 --- a/lib/helpers/httpMethods.ts +++ b/lib/helpers/httpMethods.ts @@ -10,7 +10,9 @@ export const httpMethod = (allowedHttpMethod: "GET" | "POST" | "PATCH" | "DELETE } }; }; - +// Made this so we can support several HTTP Methods in one route and use it there. +// Could be further extracted into a third function or refactored into one. +// that checks if it's just a string or an array and apply the correct logic to both cases. export const httpMethods = (allowedHttpMethod: string[]): NextMiddleware => { return async function (req, res, next) { if (allowedHttpMethod.map((method) => method === req.method)) { @@ -27,3 +29,4 @@ export const HTTP_GET = httpMethod("GET"); export const HTTP_PATCH = httpMethod("PATCH"); export const HTTP_DELETE = httpMethod("DELETE"); export const HTTP_GET_DELETE_PATCH = httpMethods(["GET", "DELETE", "PATCH"]); +export const HTTP_GET_OR_POST = httpMethods(["GET", "POST"]); diff --git a/lib/helpers/withMiddleware.ts b/lib/helpers/withMiddleware.ts index 4171fa774f..c926eff4ec 100644 --- a/lib/helpers/withMiddleware.ts +++ b/lib/helpers/withMiddleware.ts @@ -2,11 +2,19 @@ import { label } from "next-api-middleware"; import { addRequestId } from "./addRequestid"; import { captureErrors } from "./captureErrors"; -import { HTTP_POST, HTTP_DELETE, HTTP_PATCH, HTTP_GET, HTTP_GET_DELETE_PATCH } from "./httpMethods"; +import { + HTTP_POST, + HTTP_DELETE, + HTTP_PATCH, + HTTP_GET, + HTTP_GET_OR_POST, + HTTP_GET_DELETE_PATCH, +} from "./httpMethods"; import { verifyApiKey } from "./verifyApiKey"; const withMiddleware = label( { + HTTP_GET_OR_POST, HTTP_GET_DELETE_PATCH, HTTP_GET, HTTP_PATCH, diff --git a/lib/validations/payment.ts b/lib/validations/payment.ts index 7a9a138a13..5789d4a092 100644 --- a/lib/validations/payment.ts +++ b/lib/validations/payment.ts @@ -2,9 +2,9 @@ import { withValidation } from "next-validations"; import { _PaymentModel as Payment } from "@calcom/prisma/zod"; +// FIXME: Payment seems a delicate endpoint, do we need to remove anything here? export const schemaPaymentBodyParams = Payment.omit({ id: true }); - -export const schemaPaymentPublic = Payment.omit({}); +export const schemaPaymentPublic = Payment.omit({ externalId: true }); export const withValidPayment = withValidation({ schema: schemaPaymentBodyParams, diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index 4c94c6ed7d..60f6a35ebc 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -3,8 +3,8 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { AttendeesResponse } from "@lib/types"; -import { schemaAttendeePublic } from "@lib/validations/attendee"; +import { AttendeeResponse, AttendeesResponse } from "@lib/types"; +import { schemaAttendeeBodyParams, schemaAttendeePublic, withValidAttendee } from "@lib/validations/attendee"; /** * @swagger @@ -20,18 +20,49 @@ import { schemaAttendeePublic } from "@lib/validations/attendee"; * description: Authorization information is missing or invalid. * 404: * description: No attendees were found + * post: + * summary: Creates a new attendee + * tags: + * - attendees + * responses: + * 201: + * description: OK, attendee created + * model: Attendee + * 400: + * description: Bad request. Attendee body is invalid. + * 401: + * description: Authorization information is missing or invalid. */ -async function allAttendees(_: NextApiRequest, res: NextApiResponse) { - const attendees = await prisma.attendee.findMany(); - const data = attendees.map((attendee) => schemaAttendeePublic.parse(attendee)); +async function createOrlistAllAttendees( + req: NextApiRequest, + res: NextApiResponse +) { + const { method } = req; + if (method === "GET") { + const attendees = await prisma.attendee.findMany(); + const data = attendees.map((attendee) => schemaAttendeePublic.parse(attendee)); + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "No Attendees were found", + error, + }); + } else if (method === "POST") { + const safe = schemaAttendeeBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body", safe.error); - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "No Attendees were found", - error, - }); + const attendee = await prisma.attendee.create({ data: safe.data }); + const data = schemaAttendeePublic.parse(attendee); + + if (data) res.status(201).json({ data, message: "Attendee created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new attendee", + error, + }); + } else res.status(405).json({ message: `Method ${method} not allowed` }); } -export default withMiddleware("HTTP_GET")(allAttendees); +export default withMiddleware("HTTP_GET_OR_POST")(withValidAttendee(createOrlistAllAttendees)); diff --git a/pages/api/attendees/new.ts b/pages/api/attendees/new.ts deleted file mode 100644 index b934e5b62d..0000000000 --- a/pages/api/attendees/new.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { AttendeeResponse } from "@lib/types"; -import { schemaAttendeeBodyParams, schemaAttendeePublic, withValidAttendee } from "@lib/validations/attendee"; - -/** - * @swagger - * /api/attendees/new: - * post: - * summary: Creates a new attendee - * tags: - * - attendees - * responses: - * 201: - * description: OK, attendee created - * model: Attendee - * 400: - * description: Bad request. Attendee body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createAttendee(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaAttendeeBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body", safe.error); - - const attendee = await prisma.attendee.create({ data: safe.data }); - const data = schemaAttendeePublic.parse(attendee); - - if (data) res.status(201).json({ data, message: "Attendee created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new attendee", - error, - }); -} - -export default withMiddleware("HTTP_POST")(withValidAttendee(createAttendee)); diff --git a/pages/api/payments/[id].ts b/pages/api/payments/[id].ts index 14b106ca43..7637bb724d 100644 --- a/pages/api/payments/[id].ts +++ b/pages/api/payments/[id].ts @@ -5,13 +5,16 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { PaymentResponse } from "@lib/types"; import { schemaPaymentBodyParams, schemaPaymentPublic } from "@lib/validations/payment"; -import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; /** * @swagger * /api/payments/{id}: * get: - * summary: Get a payment by ID + * summary: Get an payment by ID * parameters: * - in: path * name: id @@ -78,17 +81,14 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ */ export async function paymentById(req: NextApiRequest, res: NextApiResponse) { const { method, query, body } = req; - const safeQuery = await schemaQueryIdAsString.safeParse(query); + const safeQuery = await schemaQueryIdParseInt.safeParse(query); const safeBody = await schemaPaymentBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const [userId, teamId] = safeQuery.data.id.split("_"); switch (method) { case "GET": await prisma.payment - .findUnique({ - where: { userId_teamId: { userId: parseInt(userId), teamId: parseInt(teamId) } }, - }) + .findUnique({ where: { id: safeQuery.data.id } }) .then((payment) => schemaPaymentPublic.parse(payment)) .then((data) => res.status(200).json({ data })) .catch((error: Error) => @@ -127,4 +127,4 @@ export async function paymentById(req: NextApiRequest, res: NextApiResponse +) { + const { method } = req; + if (method === "GET") { + const payments = await prisma.payment.findMany(); + const data = payments.map((payment) => schemaPaymentPublic.parse(payment)); + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "No Payments were found", + error, + }); + } else if (method === "POST") { + const safe = schemaPaymentBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body"); + + const payment = await prisma.payment.create({ data: safe.data }); + const data = schemaPaymentPublic.parse(payment); + + if (data) res.status(201).json({ data, message: "Payment created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new payment", + error, + }); + } else res.status(405).json({ message: `Method ${method} not allowed` }); +} + +export default withMiddleware("HTTP_GET_OR_POST")(withValidPayment(createOrlistAllPayments)); From 325b19ba3f335baa6384280bfc5a29f926e1ba49 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 7 Apr 2022 21:55:43 +0200 Subject: [PATCH 077/658] Add userId check in users getAll and id endpoints --- lib/helpers/verifyApiKey.ts | 4 +- lib/utils/getUserFromHeader.ts | 3 + lib/validations/shared/baseApiParams.ts | 2 +- .../api/reminder-mails}/newIndex.ts | 0 pages/api/schedules/newIndex.ts | 68 ++++++++++++++++ pages/api/selected-calendars/newIndex.ts | 68 ++++++++++++++++ pages/api/users/[id].ts | 81 ++++++++++--------- pages/api/users/index.ts | 14 +++- pages/api/users/new.ts | 51 ------------ templates/endpoints/newIndex.ts | 68 ++++++++++++++++ 10 files changed, 263 insertions(+), 96 deletions(-) create mode 100644 lib/utils/getUserFromHeader.ts rename {templates => pages/api/reminder-mails}/newIndex.ts (100%) create mode 100644 pages/api/schedules/newIndex.ts create mode 100644 pages/api/selected-calendars/newIndex.ts delete mode 100644 pages/api/users/new.ts create mode 100644 templates/endpoints/newIndex.ts diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 55ee111451..740c4a2de4 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -17,8 +17,10 @@ export const verifyApiKey: NextMiddleware = async (req, res, next) => { res.status(401).json({ error: "Your api key is not valid" }); throw new Error("No api key found"); } + if (apiKey.userId) { + res.setHeader("X-Calcom-User-ID", apiKey.userId); + } if (apiKey.expiresAt && apiKey.userId && dateInPast(today, apiKey.expiresAt)) { - res.setHeader("Calcom-User-ID", apiKey.userId); await next(); } else res.status(401).json({ error: "Your api key is not valid" }); }; diff --git a/lib/utils/getUserFromHeader.ts b/lib/utils/getUserFromHeader.ts new file mode 100644 index 0000000000..fc2e524954 --- /dev/null +++ b/lib/utils/getUserFromHeader.ts @@ -0,0 +1,3 @@ +import { NextApiResponse } from "next"; + +export const getCalcomUserId = (res: NextApiResponse) => res.getHeader("x-calcom-user-id") as number; diff --git a/lib/validations/shared/baseApiParams.ts b/lib/validations/shared/baseApiParams.ts index a7791a5b9d..b670be62d3 100644 --- a/lib/validations/shared/baseApiParams.ts +++ b/lib/validations/shared/baseApiParams.ts @@ -6,7 +6,7 @@ export const baseApiParams = z .object({ // since we added apiKey as query param this is required by next-validations helper // for query params to work properly and not fail. - apiKey: z.string().cuid().optional(), + apiKey: z.string().optional(), // version required for supporting /v1/ redirect to query in api as *?version=1 version: z.string().optional(), }) diff --git a/templates/newIndex.ts b/pages/api/reminder-mails/newIndex.ts similarity index 100% rename from templates/newIndex.ts rename to pages/api/reminder-mails/newIndex.ts diff --git a/pages/api/schedules/newIndex.ts b/pages/api/schedules/newIndex.ts new file mode 100644 index 0000000000..732eb013b2 --- /dev/null +++ b/pages/api/schedules/newIndex.ts @@ -0,0 +1,68 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { PaymentResponse, PaymentsResponse } from "@lib/types"; +import { schemaPaymentBodyParams, schemaPaymentPublic, withValidPayment } from "@lib/validations/payment"; + +/** + * @swagger + * /api/payments: + * get: + * summary: Get all payments + * tags: + * - payments + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No payments were found + * post: + * summary: Creates a new payment + * tags: + * - payments + * responses: + * 201: + * description: OK, payment created + * model: Payment + * 400: + * description: Bad request. Payment body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createOrlistAllPayments( + req: NextApiRequest, + res: NextApiResponse +) { + const { method } = req; + if (method === "GET") { + const payments = await prisma.payment.findMany(); + const data = payments.map((payment) => schemaPaymentPublic.parse(payment)); + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "No Payments were found", + error, + }); + } else if (method === "POST") { + const safe = schemaPaymentBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body"); + + const payment = await prisma.payment.create({ data: safe.data }); + const data = schemaPaymentPublic.parse(payment); + + if (data) res.status(201).json({ data, message: "Payment created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new payment", + error, + }); + } else res.status(405).json({ message: `Method ${method} not allowed` }); +} + +export default withMiddleware("HTTP_GET_OR_POST")(withValidPayment(createOrlistAllPayments)); diff --git a/pages/api/selected-calendars/newIndex.ts b/pages/api/selected-calendars/newIndex.ts new file mode 100644 index 0000000000..732eb013b2 --- /dev/null +++ b/pages/api/selected-calendars/newIndex.ts @@ -0,0 +1,68 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { PaymentResponse, PaymentsResponse } from "@lib/types"; +import { schemaPaymentBodyParams, schemaPaymentPublic, withValidPayment } from "@lib/validations/payment"; + +/** + * @swagger + * /api/payments: + * get: + * summary: Get all payments + * tags: + * - payments + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No payments were found + * post: + * summary: Creates a new payment + * tags: + * - payments + * responses: + * 201: + * description: OK, payment created + * model: Payment + * 400: + * description: Bad request. Payment body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createOrlistAllPayments( + req: NextApiRequest, + res: NextApiResponse +) { + const { method } = req; + if (method === "GET") { + const payments = await prisma.payment.findMany(); + const data = payments.map((payment) => schemaPaymentPublic.parse(payment)); + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "No Payments were found", + error, + }); + } else if (method === "POST") { + const safe = schemaPaymentBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body"); + + const payment = await prisma.payment.create({ data: safe.data }); + const data = schemaPaymentPublic.parse(payment); + + if (data) res.status(201).json({ data, message: "Payment created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new payment", + error, + }); + } else res.status(405).json({ message: `Method ${method} not allowed` }); +} + +export default withMiddleware("HTTP_GET_OR_POST")(withValidPayment(createOrlistAllPayments)); diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index fa0b4c7255..e309288253 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { UserResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getUserFromHeader"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, @@ -14,7 +15,7 @@ import { schemaUserBodyParams, schemaUserPublic } from "@lib/validations/user"; * @swagger * /api/users/{id}: * get: - * summary: Get a user by ID + * summary: Get a user by ID, returns your user if regular user. * parameters: * - in: path * name: id @@ -84,47 +85,49 @@ export async function userById(req: NextApiRequest, res: NextApiResponse schemaUserPublic.parse(user)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) + ); + break; - switch (method) { - case "GET": - await prisma.user - .findUnique({ where: { id: safeQuery.data.id } }) - .then((user) => schemaUserPublic.parse(user)) - .then((data) => res.status(200).json({ data })) - .catch((error: Error) => - res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "PATCH": + if (!safeBody.success) throw new Error("Invalid request body"); + await prisma.user + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((user) => schemaUserPublic.parse(user)) + .then((data) => res.status(200).json({ data })) + .catch((error: Error) => + res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) + ); + break; - case "PATCH": - if (!safeBody.success) throw new Error("Invalid request body"); - await prisma.user - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((user) => schemaUserPublic.parse(user)) - .then((data) => res.status(200).json({ data })) - .catch((error: Error) => - res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "DELETE": + await prisma.user + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ message: `User with id: ${safeQuery.data.id} deleted successfully` }) + ) + .catch((error: Error) => + res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) + ); + break; - case "DELETE": - await prisma.user - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ message: `User with id: ${safeQuery.data.id} deleted successfully` }) - ) - .catch((error: Error) => - res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } + } else res.status(401).json({ message: "Unauthorized" }); } export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(userById)); diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 6bb3763a88..23ec86eba0 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -4,13 +4,14 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { UsersResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getUserFromHeader"; import { schemaUserPublic } from "@lib/validations/user"; /** * @swagger * /api/users: * get: - * summary: Get all users + * summary: Get all users (admin only), returns your user if regular user. * tags: * - users * responses: @@ -21,10 +22,14 @@ import { schemaUserPublic } from "@lib/validations/user"; * 404: * description: No users were found */ -async function allUsers(_: NextApiRequest, res: NextApiResponse) { - const users = await prisma.user.findMany(); +async function allUsers(req: NextApiRequest, res: NextApiResponse) { + const userId = getCalcomUserId(res); + const users = await prisma.user.findMany({ + where: { + id: userId, + }, + }); const data = users.map((user) => schemaUserPublic.parse(user)); - if (data) res.status(200).json({ data }); else (error: Error) => @@ -33,5 +38,6 @@ async function allUsers(_: NextApiRequest, res: NextApiResponse) error, }); } +// No POST endpoint for users for now as a regular user you're expected to signup. export default withMiddleware("HTTP_GET")(allUsers); diff --git a/pages/api/users/new.ts b/pages/api/users/new.ts deleted file mode 100644 index df3310c09c..0000000000 --- a/pages/api/users/new.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { UserResponse } from "@lib/types"; -import { schemaUserBodyParams, schemaUserPublic, withValidUser } from "@lib/validations/user"; - -/** - * @swagger - * /api/users/new: - * post: - * summary: Add a new user - * consumes: - * - application/json - * parameters: - * - in: body - * name: user - * description: The user to edit - * schema: - * type: object - * $ref: '#/components/schemas/User' - * required: true - * tags: - * - users - * responses: - * 201: - * description: OK, user created - * model: User - * 400: - * description: Bad request. User body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createUser(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaUserBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body", safe.error); - - const user = await prisma.user.create({ data: safe.data }); - const data = schemaUserPublic.parse(user); - - if (data) res.status(201).json({ data, message: "User created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new user", - error, - }); -} - -export default withMiddleware("HTTP_POST")(withValidUser(createUser)); diff --git a/templates/endpoints/newIndex.ts b/templates/endpoints/newIndex.ts new file mode 100644 index 0000000000..732eb013b2 --- /dev/null +++ b/templates/endpoints/newIndex.ts @@ -0,0 +1,68 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { PaymentResponse, PaymentsResponse } from "@lib/types"; +import { schemaPaymentBodyParams, schemaPaymentPublic, withValidPayment } from "@lib/validations/payment"; + +/** + * @swagger + * /api/payments: + * get: + * summary: Get all payments + * tags: + * - payments + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No payments were found + * post: + * summary: Creates a new payment + * tags: + * - payments + * responses: + * 201: + * description: OK, payment created + * model: Payment + * 400: + * description: Bad request. Payment body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function createOrlistAllPayments( + req: NextApiRequest, + res: NextApiResponse +) { + const { method } = req; + if (method === "GET") { + const payments = await prisma.payment.findMany(); + const data = payments.map((payment) => schemaPaymentPublic.parse(payment)); + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "No Payments were found", + error, + }); + } else if (method === "POST") { + const safe = schemaPaymentBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body"); + + const payment = await prisma.payment.create({ data: safe.data }); + const data = schemaPaymentPublic.parse(payment); + + if (data) res.status(201).json({ data, message: "Payment created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new payment", + error, + }); + } else res.status(405).json({ message: `Method ${method} not allowed` }); +} + +export default withMiddleware("HTTP_GET_OR_POST")(withValidPayment(createOrlistAllPayments)); From 3d917e4dd486453da56d6241b308fab9c98a73c2 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 8 Apr 2022 01:59:04 +0200 Subject: [PATCH 078/658] make verifyApiKey check for hashed, need @calcom/ee in transpile modules next.config --- lib/helpers/verifyApiKey.ts | 5 ++++- next.config.js | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 740c4a2de4..275457d12c 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -1,5 +1,6 @@ import { NextMiddleware } from "next-api-middleware"; +import { hashAPIKey } from "@calcom/ee/lib/api/apiKeys"; // import { nanoid } from "nanoid"; import prisma from "@calcom/prisma"; @@ -12,7 +13,9 @@ const today = new Date(); export const verifyApiKey: NextMiddleware = async (req, res, next) => { if (!req.query.apiKey) res.status(401).json({ message: "No API key provided" }); - const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.apiKey as string } }); + const strippedApiKey = `${req.query.apiKey}`.replace("cal_", ""); + const hashedKey = hashAPIKey(strippedApiKey); + const apiKey = await prisma.apiKey.findUnique({ where: { hashedKey } }); if (!apiKey) { res.status(401).json({ error: "Your api key is not valid" }); throw new Error("No api key found"); diff --git a/next.config.js b/next.config.js index 1962fe9a8e..c6f75ad063 100644 --- a/next.config.js +++ b/next.config.js @@ -1,6 +1,6 @@ // https://www.npmjs.com/package/next-transpile-modules // This makes our @calcom/prisma package from the monorepo to be transpiled and usable by API -const withTM = require("next-transpile-modules")(["@calcom/prisma", "@calcom/lib"]); +const withTM = require("next-transpile-modules")(["@calcom/prisma", "@calcom/lib", "@calcom/ee"]); // use something like withPlugins([withTM], {}) if more plugins added later. From fc3677631fd2f809034bcfe9296184fc4ca322a9 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 8 Apr 2022 03:16:53 +0200 Subject: [PATCH 079/658] attendes of users bookings only --- lib/types.ts | 2 ++ lib/validations/attendee.ts | 1 + pages/api/attendees/index.ts | 31 ++++++++++++++++++++++++------- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/lib/types.ts b/lib/types.ts index 55c36392bb..cffd7c9841 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -62,6 +62,8 @@ export type SelectedCalendarsResponse = BaseResponse & { export type AttendeeResponse = BaseResponse & { data?: Partial; }; +// Grouping attendees in booking arrays for now, +// later might remove endpoint and move to booking endpoint altogether. export type AttendeesResponse = BaseResponse & { data?: Partial[]; }; diff --git a/lib/validations/attendee.ts b/lib/validations/attendee.ts index 856ab2bcae..290ea16adf 100644 --- a/lib/validations/attendee.ts +++ b/lib/validations/attendee.ts @@ -8,6 +8,7 @@ export const schemaAttendeeBaseBodyParams = Attendee.omit({ id: true }).partial( export const schemaAttendeePublic = Attendee.omit({}); const schemaAttendeeRequiredParams = z.object({ + bookingId: z.any(), email: z.string().email(), name: z.string(), timeZone: z.string(), diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index 60f6a35ebc..644bba575c 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { AttendeeResponse, AttendeesResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getUserFromHeader"; import { schemaAttendeeBodyParams, schemaAttendeePublic, withValidAttendee } from "@lib/validations/attendee"; /** @@ -38,10 +39,19 @@ async function createOrlistAllAttendees( res: NextApiResponse ) { const { method } = req; + const userId = getCalcomUserId(res); + // Here we make sure to only return attendee's of the user's own bookings. + const userBookings = await prisma.booking.findMany({ + where: { + userId, + }, + include: { + attendees: true, + }, + }); + const userBookingsAttendees = userBookings.map((booking) => booking.attendees).flat(); if (method === "GET") { - const attendees = await prisma.attendee.findMany(); - const data = attendees.map((attendee) => schemaAttendeePublic.parse(attendee)); - if (data) res.status(200).json({ data }); + if (userBookingsAttendees) res.status(200).json({ data: userBookingsAttendees }); else (error: Error) => res.status(404).json({ @@ -50,9 +60,16 @@ async function createOrlistAllAttendees( }); } else if (method === "POST") { const safe = schemaAttendeeBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body", safe.error); - - const attendee = await prisma.attendee.create({ data: safe.data }); + if (!safe.success) { + console.log(safe.error); + throw new Error("Invalid request body", safe.error); + } + const bookingId = safe.data.bookingId; + delete safe.data.bookingId; + const noBookingId = safe.data; + const attendee = await prisma.attendee.create({ + data: { ...noBookingId, booking: { connect: { id: parseInt(bookingId as string) } } }, + }); const data = schemaAttendeePublic.parse(attendee); if (data) res.status(201).json({ data, message: "Attendee created successfully" }); @@ -65,4 +82,4 @@ async function createOrlistAllAttendees( } else res.status(405).json({ message: `Method ${method} not allowed` }); } -export default withMiddleware("HTTP_GET_OR_POST")(withValidAttendee(createOrlistAllAttendees)); +export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllAttendees); From 9edc1dbd29aea3ec9ed7d34d4483fb61db1f9a23 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 8 Apr 2022 18:08:26 +0200 Subject: [PATCH 080/658] some fixes on helpers/middlewares --- .env.example | 1 + lib/helpers/addRequestid.ts | 2 +- lib/helpers/captureErrors.ts | 9 ++++----- lib/helpers/verifyApiKey.ts | 33 +++++++++++++++++++-------------- lib/helpers/withCost.ts | 23 ----------------------- lib/utils/getCalcomUserId.ts | 3 +++ lib/utils/getUserFromHeader.ts | 3 --- pages/api/attendees/index.ts | 2 +- 8 files changed, 29 insertions(+), 47 deletions(-) create mode 100644 .env.example delete mode 100644 lib/helpers/withCost.ts create mode 100644 lib/utils/getCalcomUserId.ts delete mode 100644 lib/utils/getUserFromHeader.ts diff --git a/.env.example b/.env.example new file mode 100644 index 0000000000..f3271e560c --- /dev/null +++ b/.env.example @@ -0,0 +1 @@ +API_KEY_PREFIX=cal_ \ No newline at end of file diff --git a/lib/helpers/addRequestid.ts b/lib/helpers/addRequestid.ts index af151e00cc..263c7aacc1 100644 --- a/lib/helpers/addRequestid.ts +++ b/lib/helpers/addRequestid.ts @@ -2,7 +2,7 @@ import { nanoid } from "nanoid"; import { NextMiddleware } from "next-api-middleware"; export const addRequestId: NextMiddleware = async (_req, res, next) => { - // Apply header + // Apply header with unique ID to every request res.setHeader("Calcom-Response-ID", nanoid()); // Let remaining middleware and API route execute await next(); diff --git a/lib/helpers/captureErrors.ts b/lib/helpers/captureErrors.ts index 109e4e2254..ff35ee3c89 100644 --- a/lib/helpers/captureErrors.ts +++ b/lib/helpers/captureErrors.ts @@ -6,10 +6,9 @@ export const captureErrors: NextMiddleware = async (_req, res, next) => { // Catch any errors that are thrown in remaining // middleware and the API route handler await next(); - } catch (err) { - Sentry.captureException(err); - console.log(err); - res.status(400).json({ message: "Something went wrong", error: err }); - // res.json({ error: err }); + } catch (error) { + Sentry.captureException(error); + console.log(error); + res.status(400).json({ message: "Something went wrong", error }); } }; diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 275457d12c..694de73593 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -1,29 +1,34 @@ import { NextMiddleware } from "next-api-middleware"; import { hashAPIKey } from "@calcom/ee/lib/api/apiKeys"; -// import { nanoid } from "nanoid"; import prisma from "@calcom/prisma"; -const dateInPast = function (firstDate: Date, secondDate: Date) { +// Used to check if the API key is not expired, could be extracted if reused. but not for now. +export const dateInPast = function (firstDate: Date, secondDate: Date) { if (firstDate.setHours(0, 0, 0, 0) <= secondDate.setHours(0, 0, 0, 0)) { return true; } }; const today = new Date(); +// This verifies the API key and sets the user if it is valid. export const verifyApiKey: NextMiddleware = async (req, res, next) => { if (!req.query.apiKey) res.status(401).json({ message: "No API key provided" }); - const strippedApiKey = `${req.query.apiKey}`.replace("cal_", ""); + + const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "cal_", ""); const hashedKey = hashAPIKey(strippedApiKey); - const apiKey = await prisma.apiKey.findUnique({ where: { hashedKey } }); - if (!apiKey) { - res.status(401).json({ error: "Your api key is not valid" }); - throw new Error("No api key found"); - } - if (apiKey.userId) { - res.setHeader("X-Calcom-User-ID", apiKey.userId); - } - if (apiKey.expiresAt && apiKey.userId && dateInPast(today, apiKey.expiresAt)) { - await next(); - } else res.status(401).json({ error: "Your api key is not valid" }); + + await prisma.apiKey + .findUnique({ where: { hashedKey } }) + .then(async (apiKey) => { + if (!apiKey) { + res.status(401).json({ error: "You did not provide an api key" }); + throw new Error("No api key found"); + } + if (apiKey.userId) res.setHeader("X-Calcom-User-ID", apiKey?.userId); + if (apiKey.expiresAt && apiKey.userId && dateInPast(today, apiKey.expiresAt)) await next(); + }) + .catch((error) => { + res.status(401).json({ error: "Your api key is not valid" }); + }); }; diff --git a/lib/helpers/withCost.ts b/lib/helpers/withCost.ts deleted file mode 100644 index d462536956..0000000000 --- a/lib/helpers/withCost.ts +++ /dev/null @@ -1,23 +0,0 @@ -// Make a middleware that adds a cost to running the request -// by calling stripeSubscription addCost() * pricePerBooking -// Initially to test out 0,5 cent per booking via API call -// withCost(5)(endpoint) -// Should add a charge of 0.5 cent per booking to the subscription of the user making the request -import { NextMiddleware } from "next-api-middleware"; - -export const withCost = (priceInCents: number): NextMiddleware => { - return async function (req, res, next) { - console.log(req.headers); - if ( - priceInCents > 0 - // && stripeCustomerId && stripeSubscriptionId - ) { - console.log(priceInCents); - // if (req.method === allowedHttpMethod || req.method == "OPTIONS") { - await next(); - } else { - res.status(405).json({ message: `We weren't able to process the payment for this transaction` }); - res.end(); - } - }; -}; diff --git a/lib/utils/getCalcomUserId.ts b/lib/utils/getCalcomUserId.ts new file mode 100644 index 0000000000..8670bc8759 --- /dev/null +++ b/lib/utils/getCalcomUserId.ts @@ -0,0 +1,3 @@ +import { NextApiResponse } from "next"; + +export const getCalcomUserId = (res: NextApiResponse): number => res.getHeader("x-calcom-user-id") as number; diff --git a/lib/utils/getUserFromHeader.ts b/lib/utils/getUserFromHeader.ts deleted file mode 100644 index fc2e524954..0000000000 --- a/lib/utils/getUserFromHeader.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { NextApiResponse } from "next"; - -export const getCalcomUserId = (res: NextApiResponse) => res.getHeader("x-calcom-user-id") as number; diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index 644bba575c..e15a3af0e0 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -4,7 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { AttendeeResponse, AttendeesResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getUserFromHeader"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaAttendeeBodyParams, schemaAttendeePublic, withValidAttendee } from "@lib/validations/attendee"; /** From 1f561e70be027a8b14b6949dc6d387feff79f632 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 8 Apr 2022 20:54:48 +0200 Subject: [PATCH 081/658] reanem getCalcomUserId util --- pages/api/users/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 23ec86eba0..17c975c32d 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -4,7 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { UsersResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getUserFromHeader"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaUserPublic } from "@lib/validations/user"; /** From 935e27f9ca610fc9370f0fd7d504252bf95a6a2d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 8 Apr 2022 21:08:25 +0200 Subject: [PATCH 082/658] Fix calcom user bad import --- pages/api/users/[id].ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index e309288253..3802a4fb90 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -4,7 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { UserResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getUserFromHeader"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, From 7fcc270fe828d3b97151bb73aa97e8be4e65b9c9 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 8 Apr 2022 23:20:52 +0200 Subject: [PATCH 083/658] adds index with message redirecting users to docs just so checkly doesn't fail --- pages/api/_middleware.ts | 21 --------------------- pages/api/index.ts | 5 +++++ 2 files changed, 5 insertions(+), 21 deletions(-) delete mode 100644 pages/api/_middleware.ts create mode 100644 pages/api/index.ts diff --git a/pages/api/_middleware.ts b/pages/api/_middleware.ts deleted file mode 100644 index 35529757ba..0000000000 --- a/pages/api/_middleware.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { NextRequest, NextResponse } from "next/server"; - -// Not much useful yet as prisma.client can't be used in the middlewares (client is not available) -// For now we just throw early if no apiKey is passed, -// but we could also check if the apiKey is valid if we had prisma here. - -export default async function requireApiKeyAsQueryParams({ nextUrl }: NextRequest) { - const response = NextResponse.next(); - const apiKey = nextUrl.searchParams.get("apiKey"); - - if (apiKey) return response; - // if no apiKey is passed, we throw early a 401 unauthorized asking for a valid apiKey - else - new NextResponse( - JSON.stringify({ - message: - "You need to pass an apiKey as query param: https://api.cal.com/resource?apiKey=", - }), - { status: 401, statusText: "Unauthorized" } - ); -} diff --git a/pages/api/index.ts b/pages/api/index.ts new file mode 100644 index 0000000000..17d29ee64b --- /dev/null +++ b/pages/api/index.ts @@ -0,0 +1,5 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +export default async function CalcomApi(req: NextApiRequest, res: NextApiResponse) { + res.status(201).json({ message: "Welcome to Cal.com API - docs are at https://docs.cal.com/api" }); +} From af72b1f5b5b6d183f8944b1e30e0a08de88f0c50 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 9 Apr 2022 01:29:26 +0200 Subject: [PATCH 084/658] feat: unitfy new/index of teams and selected calendars --- pages/api/index.ts | 2 +- pages/api/selected-calendars/[id].ts | 46 ++++++++++----- pages/api/selected-calendars/index.ts | 73 ++++++++++++++++++------ pages/api/selected-calendars/new.ts | 45 --------------- pages/api/selected-calendars/newIndex.ts | 68 ---------------------- pages/api/teams/[id].ts | 6 +- pages/api/teams/index.ts | 58 ++++++++++++++----- pages/api/teams/new.ts | 41 ------------- pages/api/users/index.ts | 2 +- 9 files changed, 135 insertions(+), 206 deletions(-) delete mode 100644 pages/api/selected-calendars/new.ts delete mode 100644 pages/api/selected-calendars/newIndex.ts delete mode 100644 pages/api/teams/new.ts diff --git a/pages/api/index.ts b/pages/api/index.ts index 17d29ee64b..94461cedce 100644 --- a/pages/api/index.ts +++ b/pages/api/index.ts @@ -1,5 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; -export default async function CalcomApi(req: NextApiRequest, res: NextApiResponse) { +export default async function CalcomApi(_: NextApiRequest, res: NextApiResponse) { res.status(201).json({ message: "Welcome to Cal.com API - docs are at https://docs.cal.com/api" }); } diff --git a/pages/api/selected-calendars/[id].ts b/pages/api/selected-calendars/[id].ts index f8fb8c99b2..ed3af1e7b7 100644 --- a/pages/api/selected-calendars/[id].ts +++ b/pages/api/selected-calendars/[id].ts @@ -12,7 +12,7 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ /** * @swagger - * /api/selected-calendars/{userId}_{teamId}: + * /v1/selected-calendars/{userId}_{integration}_{externalId}: * get: * summary: Get a selected-calendar by userID and teamID * parameters: @@ -21,13 +21,19 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * schema: * type: integer * required: true - * description: Numeric userId of the selected-calendar to get + * description: userId of the selected calendar to get * - in: path - * name: teamId + * name: externalId * schema: - * type: integer + * type: string * required: true - * description: Numeric teamId of the selected-calendar to get + * description: externalId of the selected calendar to get + * - in: path + * name: integration + * schema: + * type: string + * required: true + * description: integration of the selected calendar to get * tags: * - selected-calendars * responses: @@ -38,7 +44,7 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * 404: * description: SelectedCalendar was not found * patch: - * summary: Edit an existing selected-calendar + * summary: Edit an existing selected calendar * consumes: * - application/json * parameters: @@ -54,13 +60,19 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * schema: * type: integer * required: true - * description: Numeric userId of the selected-calendar to get + * description: userId of the selected calendar to get * - in: path - * name: teamId + * name: externalId * schema: - * type: integer + * type: string * required: true - * description: Numeric teamId of the selected-calendar to get + * description: externalId of the selected calendar to get + * - in: path + * name: integration + * schema: + * type: string + * required: true + * description: integration of the selected calendar to get * tags: * - selected-calendars * responses: @@ -79,13 +91,19 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * schema: * type: integer * required: true - * description: Numeric userId of the selected-calendar to get + * description: userId of the selected calendar to get * - in: path - * name: teamId + * name: externalId * schema: * type: integer * required: true - * description: Numeric teamId of the selected-calendar to get + * description: externalId of the selected-calendar to get + * - in: path + * name: integration + * schema: + * type: string + * required: true + * description: integration of the selected calendar to get * tags: * - selected-calendars * responses: @@ -105,7 +123,7 @@ export async function selectedCalendarById( const safeQuery = await schemaQueryIdAsString.safeParse(query); const safeBody = await schemaSelectedCalendarBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - // This is how we set the userId and teamId in the query for managing compoundId. + // This is how we set the userId and externalId in the query for managing compoundId. const [userId, integration, externalId] = safeQuery.data.id.split("_"); switch (method) { diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index bfc6e7b834..faa2eb0e5c 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -3,14 +3,18 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { SelectedCalendarsResponse } from "@lib/types"; -import { schemaSelectedCalendarPublic } from "@lib/validations/selected-calendar"; +import { SelectedCalendarResponse, SelectedCalendarsResponse } from "@lib/types"; +import { + schemaSelectedCalendarBodyParams, + schemaSelectedCalendarPublic, + withValidSelectedCalendar, +} from "@lib/validations/selected-calendar"; /** * @swagger - * /api/selected-calendars: + * /v1/selected-calendars: * get: - * summary: Returns all selected calendars + * summary: Get all selected calendars * tags: * - selected-calendars * responses: @@ -19,21 +23,54 @@ import { schemaSelectedCalendarPublic } from "@lib/validations/selected-calendar * 401: * description: Authorization information is missing or invalid. * 404: - * description: No selectedCalendars were found + * description: No selected calendars were found + * post: + * summary: Creates a new selected calendar + * tags: + * - selected-calendars + * responses: + * 201: + * description: OK, selected calendar created + * model: SelectedCalendar + * 400: + * description: Bad request. SelectedCalendar body is invalid. + * 401: + * description: Authorization information is missing or invalid. */ -async function allSelectedCalendars(_: NextApiRequest, res: NextApiResponse) { - const selectedCalendars = await prisma.selectedCalendar.findMany(); - const data = selectedCalendars.map((selectedCalendar) => - schemaSelectedCalendarPublic.parse(selectedCalendar) - ); +async function createOrlistAllSelectedCalendars( + req: NextApiRequest, + res: NextApiResponse +) { + const { method } = req; + if (method === "GET") { + const selectedCalendars = await prisma.selectedCalendar.findMany(); + const data = selectedCalendars.map((selectedCalendar) => + schemaSelectedCalendarPublic.parse(selectedCalendar) + ); + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "No SelectedCalendars were found", + error, + }); + } else if (method === "POST") { + const safe = schemaSelectedCalendarBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body"); - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "No SelectedCalendars were found", - error, - }); + const selectedCalendar = await prisma.selectedCalendar.create({ data: safe.data }); + const data = schemaSelectedCalendarPublic.parse(selectedCalendar); + + if (data) res.status(201).json({ data, message: "SelectedCalendar created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new selectedCalendar", + error, + }); + } else res.status(405).json({ message: `Method ${method} not allowed` }); } -export default withMiddleware("HTTP_GET")(allSelectedCalendars); +export default withMiddleware("HTTP_GET_OR_POST")( + withValidSelectedCalendar(createOrlistAllSelectedCalendars) +); diff --git a/pages/api/selected-calendars/new.ts b/pages/api/selected-calendars/new.ts deleted file mode 100644 index 4534215c0c..0000000000 --- a/pages/api/selected-calendars/new.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { SelectedCalendarResponse } from "@lib/types"; -import { - schemaSelectedCalendarBodyParams, - schemaSelectedCalendarPublic, - withValidSelectedCalendar, -} from "@lib/validations/selected-calendar"; - -/** - * @swagger - * /api/selected-calendars/new: - * post: - * summary: Creates a new selected calendar - * tags: - * - selected-calendars - * responses: - * 201: - * description: OK, selected calendar created - * model: SelectedCalendar - * 400: - * description: Bad request. SelectedCalendar body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createSelectedCalendar(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaSelectedCalendarBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body", safe.error); - - const selectedCalendar = await prisma.selectedCalendar.create({ data: safe.data }); - const data = schemaSelectedCalendarPublic.parse(selectedCalendar); - - if (data) res.status(201).json({ data, message: "SelectedCalendar created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new selectedCalendar", - error, - }); -} - -export default withMiddleware("HTTP_POST")(withValidSelectedCalendar(createSelectedCalendar)); diff --git a/pages/api/selected-calendars/newIndex.ts b/pages/api/selected-calendars/newIndex.ts deleted file mode 100644 index 732eb013b2..0000000000 --- a/pages/api/selected-calendars/newIndex.ts +++ /dev/null @@ -1,68 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { PaymentResponse, PaymentsResponse } from "@lib/types"; -import { schemaPaymentBodyParams, schemaPaymentPublic, withValidPayment } from "@lib/validations/payment"; - -/** - * @swagger - * /api/payments: - * get: - * summary: Get all payments - * tags: - * - payments - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No payments were found - * post: - * summary: Creates a new payment - * tags: - * - payments - * responses: - * 201: - * description: OK, payment created - * model: Payment - * 400: - * description: Bad request. Payment body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createOrlistAllPayments( - req: NextApiRequest, - res: NextApiResponse -) { - const { method } = req; - if (method === "GET") { - const payments = await prisma.payment.findMany(); - const data = payments.map((payment) => schemaPaymentPublic.parse(payment)); - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "No Payments were found", - error, - }); - } else if (method === "POST") { - const safe = schemaPaymentBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body"); - - const payment = await prisma.payment.create({ data: safe.data }); - const data = schemaPaymentPublic.parse(payment); - - if (data) res.status(201).json({ data, message: "Payment created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new payment", - error, - }); - } else res.status(405).json({ message: `Method ${method} not allowed` }); -} - -export default withMiddleware("HTTP_GET_OR_POST")(withValidPayment(createOrlistAllPayments)); diff --git a/pages/api/teams/[id].ts b/pages/api/teams/[id].ts index 21defc76b8..ef9f26845c 100644 --- a/pages/api/teams/[id].ts +++ b/pages/api/teams/[id].ts @@ -12,7 +12,7 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; /** * @swagger - * /api/teams/{id}: + * /v1/teams/{id}: * get: * summary: Get a team by ID * parameters: @@ -81,8 +81,8 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; */ export async function teamById(req: NextApiRequest, res: NextApiResponse) { const { method, query, body } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaTeamBodyParams.safeParse(body); + const safeQuery = schemaQueryIdParseInt.safeParse(query); + const safeBody = schemaTeamBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); switch (method) { diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index a4ed336c38..6184a5e1bd 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -3,14 +3,14 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { TeamsResponse } from "@lib/types"; -import { schemaTeamPublic } from "@lib/validations/team"; +import { TeamResponse, TeamsResponse } from "@lib/types"; +import { schemaTeamBodyParams, schemaTeamPublic, withValidTeam } from "@lib/validations/team"; /** * @swagger - * /api/teams: + * /v1/teams: * get: - * summary: Returns all teams + * summary: Get all teams * tags: * - teams * responses: @@ -20,18 +20,46 @@ import { schemaTeamPublic } from "@lib/validations/team"; * description: Authorization information is missing or invalid. * 404: * description: No teams were found + * post: + * summary: Creates a new team + * tags: + * - teams + * responses: + * 201: + * description: OK, team created + * model: Team + * 400: + * description: Bad request. Team body is invalid. + * 401: + * description: Authorization information is missing or invalid. */ -async function allTeams(_: NextApiRequest, res: NextApiResponse) { - const teams = await prisma.team.findMany(); - const data = teams.map((team) => schemaTeamPublic.parse(team)); +async function createOrlistAllTeams(req: NextApiRequest, res: NextApiResponse) { + const { method } = req; + if (method === "GET") { + const teams = await prisma.team.findMany(); + const data = teams.map((team) => schemaTeamPublic.parse(team)); + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "No Teams were found", + error, + }); + } else if (method === "POST") { + const safe = schemaTeamBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body"); - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "No Teams were found", - error, - }); + const team = await prisma.team.create({ data: safe.data }); + const data = schemaTeamPublic.parse(team); + + if (data) res.status(201).json({ data, message: "Team created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new team", + error, + }); + } else res.status(405).json({ message: `Method ${method} not allowed` }); } -export default withMiddleware("HTTP_GET")(allTeams); +export default withMiddleware("HTTP_GET_OR_POST")(withValidTeam(createOrlistAllTeams)); diff --git a/pages/api/teams/new.ts b/pages/api/teams/new.ts deleted file mode 100644 index 6100b5c42d..0000000000 --- a/pages/api/teams/new.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { TeamResponse } from "@lib/types"; -import { schemaTeamBodyParams, schemaTeamPublic, withValidTeam } from "@lib/validations/team"; - -/** - * @swagger - * /api/teams/new: - * post: - * summary: Creates a new team - * tags: - * - teams - * responses: - * 201: - * description: OK, team created - * model: Team - * 400: - * description: Bad request. Team body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createTeam(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaTeamBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body", safe.error); - - const team = await prisma.team.create({ data: safe.data }); - const data = schemaTeamPublic.parse(team); - - if (data) res.status(201).json({ data, message: "Team created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new team", - error, - }); -} - -export default withMiddleware("HTTP_POST")(withValidTeam(createTeam)); diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 17c975c32d..1d11d751d5 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -9,7 +9,7 @@ import { schemaUserPublic } from "@lib/validations/user"; /** * @swagger - * /api/users: + * /v1/users: * get: * summary: Get all users (admin only), returns your user if regular user. * tags: From d95325c06c753086cfe921950b829020fc55a231 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 10 Apr 2022 02:10:34 +0200 Subject: [PATCH 085/658] payments safe, unify endpoints for remindermails schedules --- pages/api/attendees/[id].ts | 4 +- pages/api/availabilities/[id].ts | 4 +- pages/api/booking-references/[id].ts | 4 +- pages/api/bookings/[id].ts | 4 +- pages/api/credentials/[id].ts | 4 +- pages/api/daily-event-references/[id].ts | 4 +- pages/api/destination-calendars/[id].ts | 4 +- pages/api/event-type-custom-inputs/[id].ts | 4 +- pages/api/event-types/[id].ts | 4 +- pages/api/memberships/[id].ts | 4 +- pages/api/payments/[id].ts | 120 +++++---------------- pages/api/payments/index.ts | 12 ++- pages/api/payments/new.ts | 48 --------- pages/api/reminder-mails/[id].ts | 4 +- pages/api/reminder-mails/index.ts | 65 ++++++++--- pages/api/reminder-mails/new.ts | 52 --------- pages/api/reminder-mails/newIndex.ts | 68 ------------ pages/api/schedules/[id].ts | 6 +- pages/api/schedules/index.ts | 59 +++++++--- pages/api/schedules/new.ts | 41 ------- pages/api/schedules/newIndex.ts | 68 ------------ pages/api/selected-calendars/[id].ts | 4 +- pages/api/users/[id].ts | 6 +- templates/endpoints/[id]/delete.ts | 2 +- templates/endpoints/[id]/edit.ts | 4 +- templates/endpoints/[id]/index.ts | 2 +- 26 files changed, 167 insertions(+), 434 deletions(-) delete mode 100644 pages/api/payments/new.ts delete mode 100644 pages/api/reminder-mails/new.ts delete mode 100644 pages/api/reminder-mails/newIndex.ts delete mode 100644 pages/api/schedules/new.ts delete mode 100644 pages/api/schedules/newIndex.ts diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index 502fb5d1c5..8152512d5c 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -81,8 +81,8 @@ import { */ export async function attendeeById(req: NextApiRequest, res: NextApiResponse) { const { method, query, body } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaAttendeeBodyParams.safeParse(body); + const safeQuery = schemaQueryIdParseInt.safeParse(query); + const safeBody = schemaAttendeeBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); switch (method) { diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index be9d9eb987..5e9e243e54 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -81,8 +81,8 @@ import { */ export async function availabilityById(req: NextApiRequest, res: NextApiResponse) { const { method, query, body } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaAvailabilityBodyParams.safeParse(body); + const safeQuery = schemaQueryIdParseInt.safeParse(query); + const safeBody = schemaAvailabilityBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); switch (method) { diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index 8c804321e0..216d1282ff 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -87,8 +87,8 @@ export async function bookingReferenceById( res: NextApiResponse ) { const { method, query, body } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaBookingReferenceBodyParams.safeParse(body); + const safeQuery = schemaQueryIdParseInt.safeParse(query); + const safeBody = schemaBookingReferenceBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); switch (method) { diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index 57b817464d..852b32b983 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -81,8 +81,8 @@ import { */ export async function bookingById(req: NextApiRequest, res: NextApiResponse) { const { method, query, body } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaBookingBodyParams.safeParse(body); + const safeQuery = schemaQueryIdParseInt.safeParse(query); + const safeBody = schemaBookingBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); switch (method) { diff --git a/pages/api/credentials/[id].ts b/pages/api/credentials/[id].ts index cc48ffab6a..16c60007a4 100644 --- a/pages/api/credentials/[id].ts +++ b/pages/api/credentials/[id].ts @@ -81,8 +81,8 @@ import { */ export async function credentialById(req: NextApiRequest, res: NextApiResponse) { const { method, query, body } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaCredentialBodyParams.safeParse(body); + const safeQuery = schemaQueryIdParseInt.safeParse(query); + const safeBody = schemaCredentialBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); switch (method) { diff --git a/pages/api/daily-event-references/[id].ts b/pages/api/daily-event-references/[id].ts index 21072a7a4e..d150cf69ce 100644 --- a/pages/api/daily-event-references/[id].ts +++ b/pages/api/daily-event-references/[id].ts @@ -87,8 +87,8 @@ export async function dailyEventReferenceById( res: NextApiResponse ) { const { method, query, body } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaDailyEventReferenceBodyParams.safeParse(body); + const safeQuery = schemaQueryIdParseInt.safeParse(query); + const safeBody = schemaDailyEventReferenceBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); switch (method) { diff --git a/pages/api/destination-calendars/[id].ts b/pages/api/destination-calendars/[id].ts index a08406f9fa..16c5fba7be 100644 --- a/pages/api/destination-calendars/[id].ts +++ b/pages/api/destination-calendars/[id].ts @@ -87,8 +87,8 @@ export async function destionationCalendarById( res: NextApiResponse ) { const { method, query, body } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaDestinationCalendarBodyParams.safeParse(body); + const safeQuery = schemaQueryIdParseInt.safeParse(query); + const safeBody = schemaDestinationCalendarBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); switch (method) { diff --git a/pages/api/event-type-custom-inputs/[id].ts b/pages/api/event-type-custom-inputs/[id].ts index 8b5d29ed8f..85b2df0ccd 100644 --- a/pages/api/event-type-custom-inputs/[id].ts +++ b/pages/api/event-type-custom-inputs/[id].ts @@ -84,8 +84,8 @@ import { */ async function eventTypeById(req: NextApiRequest, res: NextApiResponse) { const { method, query, body } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaEventTypeCustomInputBodyParams.safeParse(body); + const safeQuery = schemaQueryIdParseInt.safeParse(query); + const safeBody = schemaEventTypeCustomInputBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); switch (method) { diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index bf94bcdfa0..dd441f5cd3 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -81,8 +81,8 @@ import { */ export async function eventTypeById(req: NextApiRequest, res: NextApiResponse) { const { method, query, body } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaEventTypeBodyParams.safeParse(body); + const safeQuery = schemaQueryIdParseInt.safeParse(query); + const safeBody = schemaEventTypeBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); switch (method) { diff --git a/pages/api/memberships/[id].ts b/pages/api/memberships/[id].ts index d78d0f1c88..61f78cc6e8 100644 --- a/pages/api/memberships/[id].ts +++ b/pages/api/memberships/[id].ts @@ -96,8 +96,8 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ */ export async function membershipById(req: NextApiRequest, res: NextApiResponse) { const { method, query, body } = req; - const safeQuery = await schemaQueryIdAsString.safeParse(query); - const safeBody = await schemaMembershipBodyParams.safeParse(body); + const safeQuery = schemaQueryIdAsString.safeParse(query); + const safeBody = schemaMembershipBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); // This is how we set the userId and teamId in the query for managing compoundId. const [userId, teamId] = safeQuery.data.id.split("_"); diff --git a/pages/api/payments/[id].ts b/pages/api/payments/[id].ts index 7637bb724d..e026e62dc5 100644 --- a/pages/api/payments/[id].ts +++ b/pages/api/payments/[id].ts @@ -4,7 +4,8 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { PaymentResponse } from "@lib/types"; -import { schemaPaymentBodyParams, schemaPaymentPublic } from "@lib/validations/payment"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; +import { schemaPaymentPublic } from "@lib/validations/payment"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, @@ -14,7 +15,7 @@ import { * @swagger * /api/payments/{id}: * get: - * summary: Get an payment by ID + * summary: Get a payment by ID * parameters: * - in: path * name: id @@ -31,100 +32,33 @@ import { * description: Authorization information is missing or invalid. * 404: * description: Payment was not found - * patch: - * summary: Edit an existing payment - * consumes: - * - application/json - * parameters: - * - in: body - * name: payment - * description: The payment to edit - * schema: - * type: object - * $ref: '#/components/schemas/Payment' - * required: true - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the payment to edit - * tags: - * - payments - * responses: - * 201: - * description: OK, payment edited successfuly - * model: Payment - * 400: - * description: Bad request. Payment body is invalid. - * 401: - * description: Authorization information is missing or invalid. - * delete: - * summary: Remove an existing payment - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the payment to delete - * tags: - * - payments - * responses: - * 201: - * description: OK, payment removed successfuly - * model: Payment - * 400: - * description: Bad request. Payment id is invalid. - * 401: - * description: Authorization information is missing or invalid. */ export async function paymentById(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaPaymentBodyParams.safeParse(body); - if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + const { method, query } = req; + const safeQuery = schemaQueryIdParseInt.safeParse(query); + const userId = await getCalcomUserId(res); - switch (method) { - case "GET": - await prisma.payment - .findUnique({ where: { id: safeQuery.data.id } }) - .then((payment) => schemaPaymentPublic.parse(payment)) - .then((data) => res.status(200).json({ data })) - .catch((error: Error) => - res.status(404).json({ message: `Payment with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - case "PATCH": - if (!safeBody.success) throw new Error("Invalid request body"); - await prisma.payment - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, + if (safeQuery.success && method === "GET") { + const userWithBookings = await prisma.user.findUnique({ + where: { id: userId }, + include: { bookings: true }, + }); + await prisma.payment + .findUnique({ where: { id: safeQuery.data.id } }) + .then((payment) => schemaPaymentPublic.parse(payment)) + .then((data) => { + if (userWithBookings?.bookings.map((b) => b.id).includes(data.bookingId)) { + res.status(200).json({ data }); + } else { + res.status(401).json({ message: "Unauthorized" }); + } + }) + .catch((error: Error) => + res.status(404).json({ + message: `Payment with id: ${safeQuery.data.id} not found`, + error, }) - .then((payment) => schemaPaymentPublic.parse(payment)) - .then((data) => res.status(200).json({ data })) - .catch((error: Error) => - res.status(404).json({ message: `Payment with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - case "DELETE": - await prisma.payment - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ message: `Payment with id: ${safeQuery.data.id} deleted successfully` }) - ) - .catch((error: Error) => - res.status(404).json({ message: `Payment with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; + ); } } - -export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(paymentById)); +export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(paymentById)); diff --git a/pages/api/payments/index.ts b/pages/api/payments/index.ts index ccffac1161..73b32a7d1c 100644 --- a/pages/api/payments/index.ts +++ b/pages/api/payments/index.ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { PaymentsResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaPaymentPublic } from "@lib/validations/payment"; /** @@ -22,7 +23,16 @@ import { schemaPaymentPublic } from "@lib/validations/payment"; * description: No payments were found */ async function allPayments(_: NextApiRequest, res: NextApiResponse) { - const payments = await prisma.payment.findMany(); + const userId = await getCalcomUserId(res); + + const userWithBookings = await prisma.user.findUnique({ + where: { id: userId }, + include: { bookings: true }, + }); + if (!userWithBookings) throw new Error("No user found"); + const bookings = userWithBookings.bookings; + const bookingIds = bookings.map((booking) => booking.id); + const payments = await prisma.payment.findMany({ where: { bookingId: { in: bookingIds } } }); const data = payments.map((payment) => schemaPaymentPublic.parse(payment)); if (data) res.status(200).json({ data }); diff --git a/pages/api/payments/new.ts b/pages/api/payments/new.ts deleted file mode 100644 index 1886270fe2..0000000000 --- a/pages/api/payments/new.ts +++ /dev/null @@ -1,48 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { PaymentResponse } from "@lib/types"; -import { schemaPaymentBodyParams, schemaPaymentPublic, withValidPayment } from "@lib/validations/payment"; - -/** - * @swagger - * /api/payments/new: - * post: - * summary: Creates a new payment - * requestBody: - * description: Optional description in *Markdown* - * required: true - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/Payment' - * tags: - * - payments - * responses: - * 201: - * description: OK, payment created - * model: Payment - * 400: - * description: Bad request. Payment body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createPayment(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaPaymentBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body", safe.error); - - const payment = await prisma.payment.create({ data: safe.data }); - const data = schemaPaymentPublic.parse(payment); - - if (data) res.status(201).json({ data, message: "Payment created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new payment", - error, - }); -} - -export default withMiddleware("HTTP_POST")(withValidPayment(createPayment)); diff --git a/pages/api/reminder-mails/[id].ts b/pages/api/reminder-mails/[id].ts index 5d101b4c6d..543b84de9b 100644 --- a/pages/api/reminder-mails/[id].ts +++ b/pages/api/reminder-mails/[id].ts @@ -81,8 +81,8 @@ import { */ export async function reminderMailById(req: NextApiRequest, res: NextApiResponse) { const { method, query, body } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaReminderMailBodyParams.safeParse(body); + const safeQuery = schemaQueryIdParseInt.safeParse(query); + const safeBody = schemaReminderMailBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); switch (method) { diff --git a/pages/api/reminder-mails/index.ts b/pages/api/reminder-mails/index.ts index 3a847def6b..be7025ba21 100644 --- a/pages/api/reminder-mails/index.ts +++ b/pages/api/reminder-mails/index.ts @@ -3,12 +3,16 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { ReminderMailsResponse } from "@lib/types"; -import { schemaReminderMailPublic } from "@lib/validations/reminder-mail"; +import { ReminderMailResponse, ReminderMailsResponse } from "@lib/types"; +import { + schemaReminderMailBodyParams, + schemaReminderMailPublic, + withValidReminderMail, +} from "@lib/validations/reminder-mail"; /** * @swagger - * /api/reminder-mails: + * /v1/reminder-mails: * get: * summary: Get all reminder mails * tags: @@ -19,19 +23,50 @@ import { schemaReminderMailPublic } from "@lib/validations/reminder-mail"; * 401: * description: Authorization information is missing or invalid. * 404: - * description: No reminderMails were found + * description: No reminder mails were found + * post: + * summary: Creates a new reminder mail + * tags: + * - reminder-mails + * responses: + * 201: + * description: OK, reminder mail created + * model: ReminderMail + * 400: + * description: Bad request. ReminderMail body is invalid. + * 401: + * description: Authorization information is missing or invalid. */ -async function allReminderMails(_: NextApiRequest, res: NextApiResponse) { - const reminderMails = await prisma.reminderMail.findMany(); - const data = reminderMails.map((reminderMail) => schemaReminderMailPublic.parse(reminderMail)); +async function createOrlistAllReminderMails( + req: NextApiRequest, + res: NextApiResponse +) { + const { method } = req; + if (method === "GET") { + const reminderMails = await prisma.reminderMail.findMany(); + const data = reminderMails.map((reminderMail) => schemaReminderMailPublic.parse(reminderMail)); + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "No ReminderMails were found", + error, + }); + } else if (method === "POST") { + const safe = schemaReminderMailBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body"); - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "No ReminderMails were found", - error, - }); + const reminderMail = await prisma.reminderMail.create({ data: safe.data }); + const data = schemaReminderMailPublic.parse(reminderMail); + + if (data) res.status(201).json({ data, message: "reminder mail created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "could not create new reminder mail", + error, + }); + } else res.status(405).json({ message: `Method ${method} not allowed` }); } -export default withMiddleware("HTTP_GET")(allReminderMails); +export default withMiddleware("HTTP_GET_OR_POST")(withValidReminderMail(createOrlistAllReminderMails)); diff --git a/pages/api/reminder-mails/new.ts b/pages/api/reminder-mails/new.ts deleted file mode 100644 index dd82b7a78e..0000000000 --- a/pages/api/reminder-mails/new.ts +++ /dev/null @@ -1,52 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { ReminderMailResponse } from "@lib/types"; -import { - schemaReminderMailBodyParams, - schemaReminderMailPublic, - withValidReminderMail, -} from "@lib/validations/reminder-mail"; - -/** - * @swagger - * /api/reminder-mails/new: - * post: - * summary: Creates a new reminder mail - * requestBody: - * description: Optional description in *Markdown* - * required: true - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/ReminderMail' - * tags: - * - reminder-mails - * responses: - * 201: - * description: OK, reminderMail created - * model: ReminderMail - * 400: - * description: Bad request. ReminderMail body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createReminderMail(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaReminderMailBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body", safe.error); - - const reminderMail = await prisma.reminderMail.create({ data: safe.data }); - const data = schemaReminderMailPublic.parse(reminderMail); - - if (data) res.status(201).json({ data, message: "ReminderMail created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new reminderMail", - error, - }); -} - -export default withMiddleware("HTTP_POST")(withValidReminderMail(createReminderMail)); diff --git a/pages/api/reminder-mails/newIndex.ts b/pages/api/reminder-mails/newIndex.ts deleted file mode 100644 index 732eb013b2..0000000000 --- a/pages/api/reminder-mails/newIndex.ts +++ /dev/null @@ -1,68 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { PaymentResponse, PaymentsResponse } from "@lib/types"; -import { schemaPaymentBodyParams, schemaPaymentPublic, withValidPayment } from "@lib/validations/payment"; - -/** - * @swagger - * /api/payments: - * get: - * summary: Get all payments - * tags: - * - payments - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No payments were found - * post: - * summary: Creates a new payment - * tags: - * - payments - * responses: - * 201: - * description: OK, payment created - * model: Payment - * 400: - * description: Bad request. Payment body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createOrlistAllPayments( - req: NextApiRequest, - res: NextApiResponse -) { - const { method } = req; - if (method === "GET") { - const payments = await prisma.payment.findMany(); - const data = payments.map((payment) => schemaPaymentPublic.parse(payment)); - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "No Payments were found", - error, - }); - } else if (method === "POST") { - const safe = schemaPaymentBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body"); - - const payment = await prisma.payment.create({ data: safe.data }); - const data = schemaPaymentPublic.parse(payment); - - if (data) res.status(201).json({ data, message: "Payment created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new payment", - error, - }); - } else res.status(405).json({ message: `Method ${method} not allowed` }); -} - -export default withMiddleware("HTTP_GET_OR_POST")(withValidPayment(createOrlistAllPayments)); diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index 682dc334d2..162f7f9542 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -12,7 +12,7 @@ import { /** * @swagger - * /api/schedules/{id}: + * /v1/schedules/{id}: * get: * summary: Get a schedule by ID * parameters: @@ -81,8 +81,8 @@ import { */ export async function scheduleById(req: NextApiRequest, res: NextApiResponse) { const { method, query, body } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaScheduleBodyParams.safeParse(body); + const safeQuery = schemaQueryIdParseInt.safeParse(query); + const safeBody = schemaScheduleBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); switch (method) { diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index cd09534c99..3458e4896b 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -3,14 +3,14 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { SchedulesResponse } from "@lib/types"; -import { schemaSchedulePublic } from "@lib/validations/schedule"; +import { ScheduleResponse, SchedulesResponse } from "@lib/types"; +import { schemaScheduleBodyParams, schemaSchedulePublic, withValidSchedule } from "@lib/validations/schedule"; /** * @swagger * /api/schedules: * get: - * summary: Returns all schedules + * summary: Get all schedules * tags: * - schedules * responses: @@ -20,18 +20,49 @@ import { schemaSchedulePublic } from "@lib/validations/schedule"; * description: Authorization information is missing or invalid. * 404: * description: No schedules were found + * post: + * summary: Creates a new schedule + * tags: + * - schedules + * responses: + * 201: + * description: OK, schedule created + * model: Schedule + * 400: + * description: Bad request. Schedule body is invalid. + * 401: + * description: Authorization information is missing or invalid. */ -async function allSchedules(_: NextApiRequest, res: NextApiResponse) { - const schedules = await prisma.schedule.findMany(); - const data = schedules.map((schedule) => schemaSchedulePublic.parse(schedule)); +async function createOrlistAllSchedules( + req: NextApiRequest, + res: NextApiResponse +) { + const { method } = req; + if (method === "GET") { + const schedules = await prisma.schedule.findMany(); + const data = schedules.map((schedule) => schemaSchedulePublic.parse(schedule)); + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "No Schedules were found", + error, + }); + } else if (method === "POST") { + const safe = schemaScheduleBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body"); - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "No Schedules were found", - error, - }); + const schedule = await prisma.schedule.create({ data: safe.data }); + const data = schemaSchedulePublic.parse(schedule); + + if (data) res.status(201).json({ data, message: "Schedule created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new schedule", + error, + }); + } else res.status(405).json({ message: `Method ${method} not allowed` }); } -export default withMiddleware("HTTP_GET")(allSchedules); +export default withMiddleware("HTTP_GET_OR_POST")(withValidSchedule(createOrlistAllSchedules)); diff --git a/pages/api/schedules/new.ts b/pages/api/schedules/new.ts deleted file mode 100644 index d4a3ea4416..0000000000 --- a/pages/api/schedules/new.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { ScheduleResponse } from "@lib/types"; -import { schemaScheduleBodyParams, schemaSchedulePublic, withValidSchedule } from "@lib/validations/schedule"; - -/** - * @swagger - * /api/schedules/new: - * post: - * summary: Creates a new schedule - * tags: - * - schedules - * responses: - * 201: - * description: OK, schedule created - * model: Schedule - * 400: - * description: Bad request. Schedule body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createSchedule(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaScheduleBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body", safe.error); - - const schedule = await prisma.schedule.create({ data: safe.data }); - const data = schemaSchedulePublic.parse(schedule); - - if (data) res.status(201).json({ data, message: "Schedule created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new schedule", - error, - }); -} - -export default withMiddleware("HTTP_POST")(withValidSchedule(createSchedule)); diff --git a/pages/api/schedules/newIndex.ts b/pages/api/schedules/newIndex.ts deleted file mode 100644 index 732eb013b2..0000000000 --- a/pages/api/schedules/newIndex.ts +++ /dev/null @@ -1,68 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { PaymentResponse, PaymentsResponse } from "@lib/types"; -import { schemaPaymentBodyParams, schemaPaymentPublic, withValidPayment } from "@lib/validations/payment"; - -/** - * @swagger - * /api/payments: - * get: - * summary: Get all payments - * tags: - * - payments - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No payments were found - * post: - * summary: Creates a new payment - * tags: - * - payments - * responses: - * 201: - * description: OK, payment created - * model: Payment - * 400: - * description: Bad request. Payment body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createOrlistAllPayments( - req: NextApiRequest, - res: NextApiResponse -) { - const { method } = req; - if (method === "GET") { - const payments = await prisma.payment.findMany(); - const data = payments.map((payment) => schemaPaymentPublic.parse(payment)); - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "No Payments were found", - error, - }); - } else if (method === "POST") { - const safe = schemaPaymentBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body"); - - const payment = await prisma.payment.create({ data: safe.data }); - const data = schemaPaymentPublic.parse(payment); - - if (data) res.status(201).json({ data, message: "Payment created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new payment", - error, - }); - } else res.status(405).json({ message: `Method ${method} not allowed` }); -} - -export default withMiddleware("HTTP_GET_OR_POST")(withValidPayment(createOrlistAllPayments)); diff --git a/pages/api/selected-calendars/[id].ts b/pages/api/selected-calendars/[id].ts index ed3af1e7b7..900c2295db 100644 --- a/pages/api/selected-calendars/[id].ts +++ b/pages/api/selected-calendars/[id].ts @@ -120,8 +120,8 @@ export async function selectedCalendarById( res: NextApiResponse ) { const { method, query, body } = req; - const safeQuery = await schemaQueryIdAsString.safeParse(query); - const safeBody = await schemaSelectedCalendarBodyParams.safeParse(body); + const safeQuery = schemaQueryIdAsString.safeParse(query); + const safeBody = schemaSelectedCalendarBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); // This is how we set the userId and externalId in the query for managing compoundId. const [userId, integration, externalId] = safeQuery.data.id.split("_"); diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index 3802a4fb90..a264051726 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -13,7 +13,7 @@ import { schemaUserBodyParams, schemaUserPublic } from "@lib/validations/user"; /** * @swagger - * /api/users/{id}: + * /v1/users/{id}: * get: * summary: Get a user by ID, returns your user if regular user. * parameters: @@ -82,8 +82,8 @@ import { schemaUserBodyParams, schemaUserPublic } from "@lib/validations/user"; */ export async function userById(req: NextApiRequest, res: NextApiResponse) { const { method, query, body } = req; - const safeQuery = await schemaQueryIdParseInt.safeParse(query); - const safeBody = await schemaUserBodyParams.safeParse(body); + const safeQuery = schemaQueryIdParseInt.safeParse(query); + const safeBody = schemaUserBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); const userId = getCalcomUserId(res); if (safeQuery.data.id === userId) { diff --git a/templates/endpoints/[id]/delete.ts b/templates/endpoints/[id]/delete.ts index 95049ae799..a9816a3ab6 100644 --- a/templates/endpoints/[id]/delete.ts +++ b/templates/endpoints/[id]/delete.ts @@ -33,7 +33,7 @@ import { * description: Authorization information is missing or invalid. */ export async function deleteResource(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); + const safe = schemaQueryIdParseInt.safeParse(req.query); if (!safe.success) throw new Error("Invalid request query", safe.error); const data = await prisma.resource.delete({ where: { id: safe.data.id } }); diff --git a/templates/endpoints/[id]/edit.ts b/templates/endpoints/[id]/edit.ts index e4d2f382ec..2be7bd06c1 100644 --- a/templates/endpoints/[id]/edit.ts +++ b/templates/endpoints/[id]/edit.ts @@ -34,8 +34,8 @@ import { schemaResourceBodyParams, schemaResourcePublic, withValidResource } fro * description: Authorization information is missing or invalid. */ export async function editResource(req: NextApiRequest, res: NextApiResponse) { - const safeQuery = await schemaQueryIdParseInt.safeParse(req.query); - const safeBody = await schemaResourceBodyParams.safeParse(req.body); + const safeQuery = schemaQueryIdParseInt.safeParse(req.query); + const safeBody = schemaResourceBodyParams.safeParse(req.body); if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); const resource = await prisma.resource.update({ diff --git a/templates/endpoints/[id]/index.ts b/templates/endpoints/[id]/index.ts index 0ba07d382f..2ef4d18a67 100644 --- a/templates/endpoints/[id]/index.ts +++ b/templates/endpoints/[id]/index.ts @@ -33,7 +33,7 @@ import { schemaResourcePublic } from "@lib/validations/resource"; * description: Resource was not found */ export async function resourceById(req: NextApiRequest, res: NextApiResponse) { - const safe = await schemaQueryIdParseInt.safeParse(req.query); + const safe = schemaQueryIdParseInt.safeParse(req.query); if (!safe.success) throw new Error("Invalid request query"); const resource = await prisma.resource.findUnique({ where: { id: safe.data.id } }); From ddc1b4043c23bb1f6611878149ffea23b952b770 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 11 Apr 2022 00:10:38 +0200 Subject: [PATCH 086/658] fix: docs bad ref in event type --- pages/api/event-type-custom-inputs/[id].ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/event-type-custom-inputs/[id].ts b/pages/api/event-type-custom-inputs/[id].ts index 85b2df0ccd..c737b5fb84 100644 --- a/pages/api/event-type-custom-inputs/[id].ts +++ b/pages/api/event-type-custom-inputs/[id].ts @@ -44,7 +44,7 @@ import { * description: The eventTypeCustomInput to edit * schema: * type: object - * $ref: '#/comCustomInputponents/schemas/EventType' + * $ref: '#/components/schemas/EventTypeCustomInput' * required: true * - in: path * name: id From 963c8937272dc3ce50bded645f81a195cc6c61b4 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 11 Apr 2022 12:03:15 +0200 Subject: [PATCH 087/658] feat: unify new/index of attendees, availabilities, booking references, bookings, selected calendars, update response types --- lib/types.ts | 76 ++++++++++++--------------- pages/api/attendees/[id].ts | 8 +-- pages/api/attendees/index.ts | 10 ++-- pages/api/availabilities/[id].ts | 8 +-- pages/api/availabilities/index.ts | 57 +++++++++++++++----- pages/api/availabilities/new.ts | 51 ------------------ pages/api/booking-references/[id].ts | 6 +-- pages/api/booking-references/index.ts | 68 ++++++++++++++++++------ pages/api/booking-references/new.ts | 51 ------------------ pages/api/bookings/[id].ts | 8 +-- pages/api/bookings/index.ts | 57 +++++++++++++++----- pages/api/bookings/new.ts | 48 ----------------- pages/api/payments/[id].ts | 2 +- pages/api/schedules/index.ts | 2 +- pages/api/selected-calendars/[id].ts | 4 +- pages/api/selected-calendars/index.ts | 17 +++--- pages/api/teams/[id].ts | 11 ++-- pages/api/teams/index.ts | 21 +++++--- pages/api/users/[id].ts | 8 +-- pages/api/users/index.ts | 6 +-- templates/endpoints/newIndex.ts | 2 +- 21 files changed, 237 insertions(+), 284 deletions(-) delete mode 100644 pages/api/availabilities/new.ts delete mode 100644 pages/api/booking-references/new.ts delete mode 100644 pages/api/bookings/new.ts diff --git a/lib/types.ts b/lib/types.ts index cffd7c9841..91af310a62 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -27,147 +27,139 @@ export type BaseResponse = { // User export type UserResponse = BaseResponse & { - data?: Partial; + user?: Partial; }; export type UsersResponse = BaseResponse & { - data?: Partial[]; -}; - -// API Key -export type ApiKeyResponse = BaseResponse & { - data?: Partial; -}; -export type ApiKeysResponse = BaseResponse & { - data?: Partial[]; + users?: Partial[]; }; // Team export type TeamResponse = BaseResponse & { - data?: Partial; + team?: Partial; }; export type TeamsResponse = BaseResponse & { - data?: Partial[]; + teams?: Partial[]; }; // SelectedCalendar export type SelectedCalendarResponse = BaseResponse & { - data?: Partial; + selected_calendar?: Partial; }; export type SelectedCalendarsResponse = BaseResponse & { - data?: Partial[]; + selected_calendars?: Partial[]; }; // Attendee export type AttendeeResponse = BaseResponse & { - data?: Partial; + attendee?: Partial; }; // Grouping attendees in booking arrays for now, // later might remove endpoint and move to booking endpoint altogether. export type AttendeesResponse = BaseResponse & { - data?: Partial[]; + attendees?: Partial[]; }; // Availability export type AvailabilityResponse = BaseResponse & { - data?: Partial; + availability?: Partial; }; export type AvailabilitiesResponse = BaseResponse & { - data?: Partial[]; + availabilities?: Partial[]; }; // BookingReference export type BookingReferenceResponse = BaseResponse & { - data?: Partial; + booking_reference?: Partial; }; export type BookingReferencesResponse = BaseResponse & { - data?: Partial[]; + booking_references?: Partial[]; }; // Booking export type BookingResponse = BaseResponse & { - data?: Partial; + booking?: Partial; }; export type BookingsResponse = BaseResponse & { - data?: Partial[]; + bookings?: Partial[]; }; // Credential export type CredentialResponse = BaseResponse & { - data?: Partial; + credential?: Partial; }; export type CredentialsResponse = BaseResponse & { - data?: Partial[]; + credentials?: Partial[]; }; // DailyEventReference export type DailyEventReferenceResponse = BaseResponse & { - data?: Partial; + daily_event_reference?: Partial; }; export type DailyEventReferencesResponse = BaseResponse & { - data?: Partial[]; + daily_event_references?: Partial[]; }; // DestinationCalendar export type DestinationCalendarResponse = BaseResponse & { - data?: Partial; + destination_calendar?: Partial; }; export type DestinationCalendarsResponse = BaseResponse & { - data?: Partial[]; + destination_calendars?: Partial[]; }; // Membership export type MembershipResponse = BaseResponse & { - data?: Partial; + membership?: Partial; }; export type MembershipsResponse = BaseResponse & { - data?: Partial[]; + memberships?: Partial[]; }; // EventTypeCustomInput export type EventTypeCustomInputResponse = BaseResponse & { - data?: Partial; + event_type_custom_input?: Partial; }; export type EventTypeCustomInputsResponse = BaseResponse & { - data?: Partial[]; + event_type_custom_inputs?: Partial[]; }; // EventType export type EventTypeResponse = BaseResponse & { - data?: Partial; + event_type?: Partial; }; export type EventTypesResponse = BaseResponse & { - data?: Partial[]; + event_types?: Partial[]; }; // Payment export type PaymentResponse = BaseResponse & { - data?: Partial; + payment?: Partial; }; export type PaymentsResponse = BaseResponse & { - data?: Partial[]; + payments?: Partial[]; }; // Schedule export type ScheduleResponse = BaseResponse & { - data?: Partial; + schedule?: Partial; }; export type SchedulesResponse = BaseResponse & { - data?: Partial[]; + schedules?: Partial[]; }; // Webhook export type WebhookResponse = BaseResponse & { - data?: Partial; + webhook?: Partial; }; export type WebhooksResponse = BaseResponse & { - data?: Partial[]; + webhooks?: Partial[]; }; // ReminderMail export type ReminderMailResponse = BaseResponse & { - data?: Partial; + reminder_mail?: Partial; }; export type ReminderMailsResponse = BaseResponse & { - data?: Partial[]; + reminder_mails?: Partial[]; }; diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index 8152512d5c..6044c6cc74 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -89,8 +89,8 @@ export async function attendeeById(req: NextApiRequest, res: NextApiResponse schemaAttendeePublic.parse(attendee)) - .then((data) => res.status(200).json({ data })) + .then((data) => schemaAttendeePublic.parse(data)) + .then((attendee) => res.status(200).json({ attendee })) .catch((error: Error) => res.status(404).json({ message: `Attendee with id: ${safeQuery.data.id} not found`, error }) ); @@ -103,8 +103,8 @@ export async function attendeeById(req: NextApiRequest, res: NextApiResponse schemaAttendeePublic.parse(attendee)) - .then((data) => res.status(200).json({ data })) + .then((data) => schemaAttendeePublic.parse(data)) + .then((attendee) => res.status(200).json({ attendee })) .catch((error: Error) => res.status(404).json({ message: `Attendee with id: ${safeQuery.data.id} not found`, error }) ); diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index e15a3af0e0..d9f7429325 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -49,9 +49,9 @@ async function createOrlistAllAttendees( attendees: true, }, }); - const userBookingsAttendees = userBookings.map((booking) => booking.attendees).flat(); + const attendees = userBookings.map((booking) => booking.attendees).flat(); if (method === "GET") { - if (userBookingsAttendees) res.status(200).json({ data: userBookingsAttendees }); + if (attendees) res.status(200).json({ attendees }); else (error: Error) => res.status(404).json({ @@ -67,12 +67,12 @@ async function createOrlistAllAttendees( const bookingId = safe.data.bookingId; delete safe.data.bookingId; const noBookingId = safe.data; - const attendee = await prisma.attendee.create({ + const data = await prisma.attendee.create({ data: { ...noBookingId, booking: { connect: { id: parseInt(bookingId as string) } } }, }); - const data = schemaAttendeePublic.parse(attendee); + const attendee = schemaAttendeePublic.parse(data); - if (data) res.status(201).json({ data, message: "Attendee created successfully" }); + if (attendee) res.status(201).json({ attendee, message: "Attendee created successfully" }); else (error: Error) => res.status(400).json({ diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index 5e9e243e54..1c126ff2c2 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -89,8 +89,8 @@ export async function availabilityById(req: NextApiRequest, res: NextApiResponse case "GET": await prisma.availability .findUnique({ where: { id: safeQuery.data.id } }) - .then((availability) => schemaAvailabilityPublic.parse(availability)) - .then((data) => res.status(200).json({ data })) + .then((data) => schemaAvailabilityPublic.parse(data)) + .then((availability) => res.status(200).json({ availability })) .catch((error: Error) => res.status(404).json({ message: `Availability with id: ${safeQuery.data.id} not found`, error }) ); @@ -103,8 +103,8 @@ export async function availabilityById(req: NextApiRequest, res: NextApiResponse where: { id: safeQuery.data.id }, data: safeBody.data, }) - .then((availability) => schemaAvailabilityPublic.parse(availability)) - .then((data) => res.status(200).json({ data })) + .then((data) => schemaAvailabilityPublic.parse(data)) + .then((availability) => res.status(200).json({ availability })) .catch((error: Error) => res.status(404).json({ message: `Availability with id: ${safeQuery.data.id} not found`, error }) ); diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index 5449162d95..d0408a32aa 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -3,8 +3,8 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { AvailabilitiesResponse } from "@lib/types"; -import { schemaAvailabilityPublic } from "@lib/validations/availability"; +import { AvailabilityResponse, AvailabilitiesResponse } from "@lib/types"; +import { schemaAvailabilityBodyParams, schemaAvailabilityPublic } from "@lib/validations/availability"; /** * @swagger @@ -20,18 +20,49 @@ import { schemaAvailabilityPublic } from "@lib/validations/availability"; * description: Authorization information is missing or invalid. * 404: * description: No availabilities were found + * post: + * summary: Creates a new availability + * tags: + * - availabilities + * responses: + * 201: + * description: OK, availability created + * model: Availability + * 400: + * description: Bad request. Availability body is invalid. + * 401: + * description: Authorization information is missing or invalid. */ -async function allAvailabilities(_: NextApiRequest, res: NextApiResponse) { - const availabilities = await prisma.availability.findMany(); - const data = availabilities.map((availability) => schemaAvailabilityPublic.parse(availability)); +async function createOrlistAllAvailabilities( + req: NextApiRequest, + res: NextApiResponse +) { + const { method } = req; + if (method === "GET") { + const data = await prisma.availability.findMany(); + const availabilities = data.map((availability) => schemaAvailabilityPublic.parse(availability)); + if (availabilities) res.status(200).json({ availabilities }); + else + (error: Error) => + res.status(404).json({ + message: "No Availabilities were found", + error, + }); + } else if (method === "POST") { + const safe = schemaAvailabilityBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body"); - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "No Availabilities were found", - error, - }); + const data = await prisma.availability.create({ data: safe.data }); + const availability = schemaAvailabilityPublic.parse(data); + + if (availability) res.status(201).json({ availability, message: "Availability created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new availability", + error, + }); + } else res.status(405).json({ message: `Method ${method} not allowed` }); } -export default withMiddleware("HTTP_GET")(allAvailabilities); +export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllAvailabilities); diff --git a/pages/api/availabilities/new.ts b/pages/api/availabilities/new.ts deleted file mode 100644 index d7461ba803..0000000000 --- a/pages/api/availabilities/new.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { AvailabilityResponse } from "@lib/types"; -import { - schemaAvailabilityBodyParams, - schemaAvailabilityPublic, - withValidAvailability, -} from "@lib/validations/availability"; - -/** - * @swagger - * /api/availabilities/new: - * post: - * summary: Creates a new availability - * requestBody: - * description: Optional description in *Markdown* - * required: true - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/Availability' - * tags: - * - availabilities - * responses: - * 201: - * description: OK, availability created - * 400: - * description: Bad request. Availability body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createAvailability(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaAvailabilityBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body", safe.error); - - const availability = await prisma.availability.create({ data: safe.data }); - const data = schemaAvailabilityPublic.parse(availability); - - if (data) res.status(201).json({ data, message: "Availability created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new availability", - error, - }); -} - -export default withMiddleware("HTTP_POST")(withValidAvailability(createAvailability)); diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index 216d1282ff..659c48f46d 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -96,7 +96,7 @@ export async function bookingReferenceById( await prisma.bookingReference .findUnique({ where: { id: safeQuery.data.id } }) .then((data) => schemaBookingReferencePublic.parse(data)) - .then((data) => res.status(200).json({ data })) + .then((booking_reference) => res.status(200).json({ booking_reference })) .catch((error: Error) => res.status(404).json({ message: `BookingReference with id: ${safeQuery.data.id} not found`, error }) ); @@ -109,8 +109,8 @@ export async function bookingReferenceById( where: { id: safeQuery.data.id }, data: safeBody.data, }) - .then((bookingReference) => schemaBookingReferencePublic.parse(bookingReference)) - .then((data) => res.status(200).json({ data })) + .then((data) => schemaBookingReferencePublic.parse(data)) + .then((booking_reference) => res.status(200).json({ booking_reference })) .catch((error: Error) => res.status(404).json({ message: `BookingReference with id: ${safeQuery.data.id} not found`, error }) ); diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index 312ccf4b78..df12d1c882 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -3,14 +3,17 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { BookingReferencesResponse } from "@lib/types"; -import { schemaBookingReferencePublic } from "@lib/validations/booking-reference"; +import { BookingReferenceResponse, BookingReferencesResponse } from "@lib/types"; +import { + schemaBookingReferenceBodyParams, + schemaBookingReferencePublic, +} from "@lib/validations/booking-reference"; /** * @swagger * /api/booking-references: * get: - * summary: Get all bookingReferences + * summary: Get all booking references * tags: * - booking-references * responses: @@ -19,21 +22,52 @@ import { schemaBookingReferencePublic } from "@lib/validations/booking-reference * 401: * description: Authorization information is missing or invalid. * 404: - * description: No bookingReferences were found + * description: No booking references were found + * post: + * summary: Creates a new booking reference + * tags: + * - booking-references + * responses: + * 201: + * description: OK, booking reference created + * model: BookingReference + * 400: + * description: Bad request. BookingReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. */ -async function allBookingReferences(_: NextApiRequest, res: NextApiResponse) { - const bookingReferences = await prisma.bookingReference.findMany(); - const data = bookingReferences.map((bookingReference) => - schemaBookingReferencePublic.parse(bookingReference) - ); +async function createOrlistAllBookingReferences( + req: NextApiRequest, + res: NextApiResponse +) { + const { method } = req; + if (method === "GET") { + const data = await prisma.bookingReference.findMany(); + const booking_references = data.map((bookingReference) => + schemaBookingReferencePublic.parse(bookingReference) + ); + if (booking_references) res.status(200).json({ booking_references }); + else + (error: Error) => + res.status(404).json({ + message: "No BookingReferences were found", + error, + }); + } else if (method === "POST") { + const safe = schemaBookingReferenceBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body"); - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "No BookingReferences were found", - error, - }); + const data = await prisma.bookingReference.create({ data: safe.data }); + const booking_reference = schemaBookingReferencePublic.parse(data); + + if (data) res.status(201).json({ booking_reference, message: "BookingReference created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new booking reference", + error, + }); + } else res.status(405).json({ message: `Method ${method} not allowed` }); } -export default withMiddleware("HTTP_GET")(allBookingReferences); +export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllBookingReferences); diff --git a/pages/api/booking-references/new.ts b/pages/api/booking-references/new.ts deleted file mode 100644 index 737156ae3f..0000000000 --- a/pages/api/booking-references/new.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BookingReferenceResponse } from "@lib/types"; -import { - schemaBookingReferenceBodyParams, - schemaBookingReferencePublic, - withValidBookingReference, -} from "@lib/validations/booking-reference"; - -/** - * @swagger - * /api/booking-references/new: - * post: - * summary: Creates a new bookingReference - * requestBody: - * description: Optional description in *Markdown* - * required: true - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/BookingReference' - * tags: - * - booking-references - * responses: - * 201: - * description: OK, bookingReference created - * 400: - * description: Bad request. BookingReference body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createBookingReference(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaBookingReferenceBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body", safe.error); - - const bookingReference = await prisma.bookingReference.create({ data: safe.data }); - const data = schemaBookingReferencePublic.parse(bookingReference); - - if (data) res.status(201).json({ data, message: "BookingReference created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new bookingReference", - error, - }); -} - -export default withMiddleware("HTTP_POST")(withValidBookingReference(createBookingReference)); diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index 852b32b983..f3104fc44e 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -89,8 +89,8 @@ export async function bookingById(req: NextApiRequest, res: NextApiResponse schemaBookingPublic.parse(booking)) - .then((data) => res.status(200).json({ data })) + .then((data) => schemaBookingPublic.parse(data)) + .then((booking) => res.status(200).json({ booking })) .catch((error: Error) => res.status(404).json({ message: `Booking with id: ${safeQuery.data.id} not found`, error }) ); @@ -103,8 +103,8 @@ export async function bookingById(req: NextApiRequest, res: NextApiResponse schemaBookingPublic.parse(booking)) - .then((data) => res.status(200).json({ data })) + .then((data) => schemaBookingPublic.parse(data)) + .then((booking) => res.status(200).json({ booking })) .catch((error: Error) => res.status(404).json({ message: `Booking with id: ${safeQuery.data.id} not found`, error }) ); diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index f2d724071c..dabf90f245 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -3,8 +3,8 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { BookingsResponse } from "@lib/types"; -import { schemaBookingPublic } from "@lib/validations/booking"; +import { BookingResponse, BookingsResponse } from "@lib/types"; +import { schemaBookingBodyParams, schemaBookingPublic, withValidBooking } from "@lib/validations/booking"; /** * @swagger @@ -20,18 +20,49 @@ import { schemaBookingPublic } from "@lib/validations/booking"; * description: Authorization information is missing or invalid. * 404: * description: No bookings were found + * post: + * summary: Creates a new booking + * tags: + * - bookings + * responses: + * 201: + * description: OK, booking created + * model: Booking + * 400: + * description: Bad request. Booking body is invalid. + * 401: + * description: Authorization information is missing or invalid. */ -async function allBookings(_: NextApiRequest, res: NextApiResponse) { - const bookings = await prisma.booking.findMany(); - const data = bookings.map((booking) => schemaBookingPublic.parse(booking)); +async function createOrlistAllBookings( + req: NextApiRequest, + res: NextApiResponse +) { + const { method } = req; + if (method === "GET") { + const data = await prisma.booking.findMany(); + const bookings = data.map((booking) => schemaBookingPublic.parse(booking)); + if (bookings) res.status(200).json({ bookings }); + else + (error: Error) => + res.status(404).json({ + message: "No Bookings were found", + error, + }); + } else if (method === "POST") { + const safe = schemaBookingBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body"); - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "No Bookings were found", - error, - }); + const data = await prisma.booking.create({ data: safe.data }); + const booking = schemaBookingPublic.parse(data); + + if (booking) res.status(201).json({ booking, message: "Booking created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new booking", + error, + }); + } else res.status(405).json({ message: `Method ${method} not allowed` }); } -export default withMiddleware("HTTP_GET")(allBookings); +export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllBookings); diff --git a/pages/api/bookings/new.ts b/pages/api/bookings/new.ts deleted file mode 100644 index 3e10e1c143..0000000000 --- a/pages/api/bookings/new.ts +++ /dev/null @@ -1,48 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BookingResponse } from "@lib/types"; -import { schemaBookingBodyParams, schemaBookingPublic, withValidBooking } from "@lib/validations/booking"; - -/** - * @swagger - * /api/bookings/new: - * post: - * summary: Creates a new booking - * requestBody: - * description: Optional description in *Markdown* - * required: true - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/Booking' - * tags: - * - bookings - * responses: - * 201: - * description: OK, booking created - * model: Booking - * 400: - * description: Bad request. Booking body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createBooking(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaBookingBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body", safe.error); - - const booking = await prisma.booking.create({ data: safe.data }); - const data = schemaBookingPublic.parse(booking); - - if (data) res.status(201).json({ data, message: "Booking created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new booking", - error, - }); -} - -export default withMiddleware("HTTP_POST")(withValidBooking(createBooking)); diff --git a/pages/api/payments/[id].ts b/pages/api/payments/[id].ts index e026e62dc5..bdd8766c69 100644 --- a/pages/api/payments/[id].ts +++ b/pages/api/payments/[id].ts @@ -15,7 +15,7 @@ import { * @swagger * /api/payments/{id}: * get: - * summary: Get a payment by ID + * summary: Get one of your own payments by ID * parameters: * - in: path * name: id diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index 3458e4896b..e3b178d216 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -8,7 +8,7 @@ import { schemaScheduleBodyParams, schemaSchedulePublic, withValidSchedule } fro /** * @swagger - * /api/schedules: + * /v1/schedules: * get: * summary: Get all schedules * tags: diff --git a/pages/api/selected-calendars/[id].ts b/pages/api/selected-calendars/[id].ts index 900c2295db..b66fc5a888 100644 --- a/pages/api/selected-calendars/[id].ts +++ b/pages/api/selected-calendars/[id].ts @@ -139,7 +139,7 @@ export async function selectedCalendarById( }, }) .then((selectedCalendar) => schemaSelectedCalendarPublic.parse(selectedCalendar)) - .then((data) => res.status(200).json({ data })) + .then((selected_calendar) => res.status(200).json({ selected_calendar })) .catch((error: Error) => res.status(404).json({ message: `SelectedCalendar with id: ${safeQuery.data.id} not found`, error }) ); @@ -159,7 +159,7 @@ export async function selectedCalendarById( data: safeBody.data, }) .then((selectedCalendar) => schemaSelectedCalendarPublic.parse(selectedCalendar)) - .then((data) => res.status(200).json({ data })) + .then((selected_calendar) => res.status(200).json({ selected_calendar })) .catch((error: Error) => res.status(404).json({ message: `SelectedCalendar with id: ${safeQuery.data.id} not found`, error }) ); diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index faa2eb0e5c..a6a8a39c16 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -43,11 +43,11 @@ async function createOrlistAllSelectedCalendars( ) { const { method } = req; if (method === "GET") { - const selectedCalendars = await prisma.selectedCalendar.findMany(); - const data = selectedCalendars.map((selectedCalendar) => - schemaSelectedCalendarPublic.parse(selectedCalendar) + const data = await prisma.selectedCalendar.findMany(); + const selected_calendars = data.map((selected_calendar) => + schemaSelectedCalendarPublic.parse(selected_calendar) ); - if (data) res.status(200).json({ data }); + if (selected_calendars) res.status(200).json({ selected_calendars }); else (error: Error) => res.status(404).json({ @@ -58,14 +58,15 @@ async function createOrlistAllSelectedCalendars( const safe = schemaSelectedCalendarBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body"); - const selectedCalendar = await prisma.selectedCalendar.create({ data: safe.data }); - const data = schemaSelectedCalendarPublic.parse(selectedCalendar); + const data = await prisma.selectedCalendar.create({ data: safe.data }); + const selected_calendar = schemaSelectedCalendarPublic.parse(data); - if (data) res.status(201).json({ data, message: "SelectedCalendar created successfully" }); + if (selected_calendar) + res.status(201).json({ selected_calendar, message: "SelectedCalendar created successfully" }); else (error: Error) => res.status(400).json({ - message: "Could not create new selectedCalendar", + message: "Could not create new selected calendar", error, }); } else res.status(405).json({ message: `Method ${method} not allowed` }); diff --git a/pages/api/teams/[id].ts b/pages/api/teams/[id].ts index ef9f26845c..5435b18dc5 100644 --- a/pages/api/teams/[id].ts +++ b/pages/api/teams/[id].ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { TeamResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, @@ -84,13 +85,17 @@ export async function teamById(req: NextApiRequest, res: NextApiResponse schemaTeamPublic.parse(data)) - .then((data) => res.status(200).json({ data })) + .then((team) => res.status(200).json({ team })) .catch((error: Error) => res.status(404).json({ message: `Team with id: ${safeQuery.data.id} not found`, error }) ); @@ -104,7 +109,7 @@ export async function teamById(req: NextApiRequest, res: NextApiResponse schemaTeamPublic.parse(team)) - .then((data) => res.status(200).json({ data })) + .then((team) => res.status(200).json({ team })) .catch((error: Error) => res.status(404).json({ message: `Team with id: ${safeQuery.data.id} not found`, error }) ); diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index 6184a5e1bd..5e68236e2e 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { TeamResponse, TeamsResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaTeamBodyParams, schemaTeamPublic, withValidTeam } from "@lib/validations/team"; /** @@ -35,10 +36,14 @@ import { schemaTeamBodyParams, schemaTeamPublic, withValidTeam } from "@lib/vali */ async function createOrlistAllTeams(req: NextApiRequest, res: NextApiResponse) { const { method } = req; + const userId = getCalcomUserId(res); if (method === "GET") { - const teams = await prisma.team.findMany(); - const data = teams.map((team) => schemaTeamPublic.parse(team)); - if (data) res.status(200).json({ data }); + const userWithMemberships = await prisma.membership.findMany({ + where: { userId: userId }, + }); + const teamIds = userWithMemberships.map((membership) => membership.teamId); + const teams = await prisma.team.findMany({ where: { id: { in: teamIds } } }); + if (teams) res.status(200).json({ teams }); else (error: Error) => res.status(404).json({ @@ -46,13 +51,17 @@ async function createOrlistAllTeams(req: NextApiRequest, res: NextApiResponse res.status(400).json({ @@ -62,4 +71,4 @@ async function createOrlistAllTeams(req: NextApiRequest, res: NextApiResponse schemaUserPublic.parse(user)) - .then((data) => res.status(200).json({ data })) + .then((data) => schemaUserPublic.parse(data)) + .then((user) => res.status(200).json({ user })) .catch((error: Error) => res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) ); @@ -105,8 +105,8 @@ export async function userById(req: NextApiRequest, res: NextApiResponse schemaUserPublic.parse(user)) - .then((data) => res.status(200).json({ data })) + .then((data) => schemaUserPublic.parse(data)) + .then((user) => res.status(200).json({ user })) .catch((error: Error) => res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) ); diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 1d11d751d5..138395adba 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -24,13 +24,13 @@ import { schemaUserPublic } from "@lib/validations/user"; */ async function allUsers(req: NextApiRequest, res: NextApiResponse) { const userId = getCalcomUserId(res); - const users = await prisma.user.findMany({ + const data = await prisma.user.findMany({ where: { id: userId, }, }); - const data = users.map((user) => schemaUserPublic.parse(user)); - if (data) res.status(200).json({ data }); + const users = data.map((user) => schemaUserPublic.parse(user)); + if (users) res.status(200).json({ users }); else (error: Error) => res.status(404).json({ diff --git a/templates/endpoints/newIndex.ts b/templates/endpoints/newIndex.ts index 732eb013b2..5d608ee0cb 100644 --- a/templates/endpoints/newIndex.ts +++ b/templates/endpoints/newIndex.ts @@ -65,4 +65,4 @@ async function createOrlistAllPayments( } else res.status(405).json({ message: `Method ${method} not allowed` }); } -export default withMiddleware("HTTP_GET_OR_POST")(withValidPayment(createOrlistAllPayments)); +export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllPayments); From 0bda98867665ba9e5745b315b6525085abc8925c Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 11 Apr 2022 15:10:16 +0200 Subject: [PATCH 088/658] feat: all resources endpoints for get all and new unified --- pages/api/attendees/[id].ts | 2 +- pages/api/attendees/index.ts | 2 +- pages/api/availabilities/[id].ts | 2 +- pages/api/availabilities/index.ts | 2 +- pages/api/booking-references/[id].ts | 3 +- pages/api/booking-references/index.ts | 2 +- pages/api/bookings/[id].ts | 4 +- pages/api/bookings/index.ts | 4 +- pages/api/credentials/[id].ts | 10 +-- pages/api/credentials/index.ts | 57 ++++++++++---- pages/api/credentials/new.ts | 52 ------------- pages/api/daily-event-references/[id].ts | 8 +- pages/api/daily-event-references/index.ts | 74 +++++++++++++------ pages/api/daily-event-references/new.ts | 55 -------------- pages/api/destination-calendars/[id].ts | 8 +- pages/api/destination-calendars/index.ts | 70 +++++++++++++----- pages/api/destination-calendars/new.ts | 55 -------------- pages/api/event-type-custom-inputs/[id].ts | 8 +- pages/api/event-type-custom-inputs/index.ts | 68 ++++++++++++----- pages/api/event-type-custom-inputs/new.ts | 55 -------------- pages/api/event-types/[id].ts | 8 +- pages/api/event-types/index.ts | 63 ++++++++++++---- pages/api/event-types/new.ts | 45 ----------- pages/api/memberships/[id].ts | 10 +-- pages/api/memberships/index.ts | 61 +++++++++++---- pages/api/memberships/new.ts | 45 ----------- pages/api/payments/[id].ts | 10 +-- pages/api/payments/index.ts | 10 +-- pages/api/reminder-mails/[id].ts | 6 +- pages/api/reminder-mails/index.ts | 12 +-- pages/api/schedules/[id].ts | 8 +- pages/api/schedules/index.ts | 12 +-- templates/endpoints/[id]/delete.ts | 2 +- templates/endpoints/[id]/edit.ts | 8 +- templates/endpoints/[id]/index.ts | 4 +- templates/endpoints/{index.ts => get_all.ts} | 2 +- .../{newIndex.ts => get_all_and_post.ts} | 4 +- templates/endpoints/{new.ts => post.ts} | 2 +- 38 files changed, 370 insertions(+), 483 deletions(-) delete mode 100644 pages/api/credentials/new.ts delete mode 100644 pages/api/daily-event-references/new.ts delete mode 100644 pages/api/destination-calendars/new.ts delete mode 100644 pages/api/event-type-custom-inputs/new.ts delete mode 100644 pages/api/event-types/new.ts delete mode 100644 pages/api/memberships/new.ts rename templates/endpoints/{index.ts => get_all.ts} (98%) rename templates/endpoints/{newIndex.ts => get_all_and_post.ts} (94%) rename templates/endpoints/{new.ts => post.ts} (98%) diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index 6044c6cc74..093579a799 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -12,7 +12,7 @@ import { /** * @swagger - * /api/attendees/{id}: + * /v1/attendees/{id}: * get: * summary: Get an attendee by ID * parameters: diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index d9f7429325..509907bb8d 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -9,7 +9,7 @@ import { schemaAttendeeBodyParams, schemaAttendeePublic, withValidAttendee } fro /** * @swagger - * /api/attendees: + * /v1/attendees: * get: * summary: Get all attendees * tags: diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index 1c126ff2c2..34bab03008 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -12,7 +12,7 @@ import { /** * @swagger - * /api/availabilities/{id}: + * /v1/availabilities/{id}: * get: * summary: Get an availability by ID * parameters: diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index d0408a32aa..9778bfdbfa 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -8,7 +8,7 @@ import { schemaAvailabilityBodyParams, schemaAvailabilityPublic } from "@lib/val /** * @swagger - * /api/availabilities: + * /v1/availabilities: * get: * summary: Get all availabilities * tags: diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index 659c48f46d..2d48aa7413 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -15,7 +15,7 @@ import { /** * @swagger - * /api/booking-references/{id}: + * /v1/booking-references/{id}: * get: * summary: Get a daily event reference by ID * parameters: @@ -90,6 +90,7 @@ export async function bookingReferenceById( const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaBookingReferenceBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + // FIXME: Allow only userId owner of booking ref to edit it switch (method) { case "GET": diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index df12d1c882..0ca58c2f8a 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -11,7 +11,7 @@ import { /** * @swagger - * /api/booking-references: + * /v1/booking-references: * get: * summary: Get all booking references * tags: diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index f3104fc44e..45f24774e6 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -12,7 +12,7 @@ import { /** * @swagger - * /api/bookings/{id}: + * /v1/bookings/{id}: * get: * summary: Get a booking by ID * parameters: @@ -84,7 +84,7 @@ export async function bookingById(req: NextApiRequest, res: NextApiResponse ) { const { method } = req; + // FIXME: List only bookings owner by userId + if (method === "GET") { const data = await prisma.booking.findMany(); const bookings = data.map((booking) => schemaBookingPublic.parse(booking)); diff --git a/pages/api/credentials/[id].ts b/pages/api/credentials/[id].ts index 16c60007a4..bb82d0f019 100644 --- a/pages/api/credentials/[id].ts +++ b/pages/api/credentials/[id].ts @@ -12,7 +12,7 @@ import { /** * @swagger - * /api/credentials/{id}: + * /v1/credentials/{id}: * get: * summary: Get a credential by ID * parameters: @@ -89,8 +89,8 @@ export async function credentialById(req: NextApiRequest, res: NextApiResponse schemaCredentialPublic.parse(credential)) - .then((data) => res.status(200).json({ data })) + .then((data) => schemaCredentialPublic.parse(data)) + .then((credential) => res.status(200).json({ credential })) .catch((error: Error) => res.status(404).json({ message: `Credential with id: ${safeQuery.data.id} not found`, error }) ); @@ -103,8 +103,8 @@ export async function credentialById(req: NextApiRequest, res: NextApiResponse schemaCredentialPublic.parse(credential)) - .then((data) => res.status(200).json({ data })) + .then((data) => schemaCredentialPublic.parse(data)) + .then((credential) => res.status(200).json({ credential })) .catch((error: Error) => res.status(404).json({ message: `Credential with id: ${safeQuery.data.id} not found`, error }) ); diff --git a/pages/api/credentials/index.ts b/pages/api/credentials/index.ts index 1ef98a95df..8ba9a5aeb5 100644 --- a/pages/api/credentials/index.ts +++ b/pages/api/credentials/index.ts @@ -3,8 +3,8 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { CredentialsResponse } from "@lib/types"; -import { schemaCredentialPublic } from "@lib/validations/credential"; +import { CredentialResponse, CredentialsResponse } from "@lib/types"; +import { schemaCredentialBodyParams, schemaCredentialPublic } from "@lib/validations/credential"; /** * @swagger @@ -20,18 +20,49 @@ import { schemaCredentialPublic } from "@lib/validations/credential"; * description: Authorization information is missing or invalid. * 404: * description: No credentials were found + * post: + * summary: Creates a new credential + * tags: + * - credentials + * responses: + * 201: + * description: OK, credential created + * model: Credential + * 400: + * description: Bad request. Credential body is invalid. + * 401: + * description: Authorization information is missing or invalid. */ -async function allCredentials(_: NextApiRequest, res: NextApiResponse) { - const credentials = await prisma.credential.findMany(); - const data = credentials.map((credential) => schemaCredentialPublic.parse(credential)); +async function createOrlistAllCredentials( + req: NextApiRequest, + res: NextApiResponse +) { + const { method } = req; + if (method === "GET") { + const data = await prisma.credential.findMany(); + const credentials = data.map((credential) => schemaCredentialPublic.parse(credential)); + if (credentials) res.status(200).json({ credentials }); + else + (error: Error) => + res.status(404).json({ + message: "No Credentials were found", + error, + }); + } else if (method === "POST") { + const safe = schemaCredentialBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body"); - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "No Credentials were found", - error, - }); + const data = await prisma.credential.create({ data: safe.data }); + const credential = schemaCredentialPublic.parse(data); + + if (credential) res.status(201).json({ credential, message: "Credential created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new credential", + error, + }); + } else res.status(405).json({ message: `Method ${method} not allowed` }); } -export default withMiddleware("HTTP_GET")(allCredentials); +export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllCredentials); diff --git a/pages/api/credentials/new.ts b/pages/api/credentials/new.ts deleted file mode 100644 index 39302c7a1d..0000000000 --- a/pages/api/credentials/new.ts +++ /dev/null @@ -1,52 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { CredentialResponse } from "@lib/types"; -import { - schemaCredentialBodyParams, - schemaCredentialPublic, - withValidCredential, -} from "@lib/validations/credential"; - -/** - * @swagger - * /api/credentials/new: - * post: - * summary: Creates a new credential - * requestBody: - * description: Optional description in *Markdown* - * required: true - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/Credential' - * tags: - * - credentials - * responses: - * 201: - * description: OK, credential created - * model: Credential - * 400: - * description: Bad request. Credential body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createCredential(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaCredentialBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body", safe.error); - - const credential = await prisma.credential.create({ data: safe.data }); - const data = schemaCredentialPublic.parse(credential); - - if (data) res.status(201).json({ data, message: "Credential created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new credential", - error, - }); -} - -export default withMiddleware("HTTP_POST")(withValidCredential(createCredential)); diff --git a/pages/api/daily-event-references/[id].ts b/pages/api/daily-event-references/[id].ts index d150cf69ce..482aab6ec1 100644 --- a/pages/api/daily-event-references/[id].ts +++ b/pages/api/daily-event-references/[id].ts @@ -15,7 +15,7 @@ import { /** * @swagger - * /api/daily-event-references/{id}: + * /v1/daily-event-references/{id}: * get: * summary: Get a daily event reference by ID * parameters: @@ -96,7 +96,7 @@ export async function dailyEventReferenceById( await prisma.dailyEventReference .findUnique({ where: { id: safeQuery.data.id } }) .then((data) => schemaDailyEventReferencePublic.parse(data)) - .then((data) => res.status(200).json({ data })) + .then((daily_event_reference) => res.status(200).json({ daily_event_reference })) .catch((error: Error) => res .status(404) @@ -111,8 +111,8 @@ export async function dailyEventReferenceById( where: { id: safeQuery.data.id }, data: safeBody.data, }) - .then((dailyEventReference) => schemaDailyEventReferencePublic.parse(dailyEventReference)) - .then((data) => res.status(200).json({ data })) + .then((data) => schemaDailyEventReferencePublic.parse(data)) + .then((daily_event_reference) => res.status(200).json({ daily_event_reference })) .catch((error: Error) => res .status(404) diff --git a/pages/api/daily-event-references/index.ts b/pages/api/daily-event-references/index.ts index d4495ef0f1..1a1762157d 100644 --- a/pages/api/daily-event-references/index.ts +++ b/pages/api/daily-event-references/index.ts @@ -3,40 +3,72 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { DailyEventReferencesResponse } from "@lib/types"; -import { schemaDailyEventReferencePublic } from "@lib/validations/daily-event-reference"; +import { DailyEventReferenceResponse, DailyEventReferencesResponse } from "@lib/types"; +import { + schemaDailyEventReferenceBodyParams, + schemaDailyEventReferencePublic, +} from "@lib/validations/daily-event-reference"; /** * @swagger - * /api/daily-event-references: + * /v1/daily-event-references: * get: - * summary: Get all dailyEventReferences + * summary: Get all daily event reference * tags: - * - daily-event-references + * - daily-event-reference * responses: * 200: * description: OK * 401: * description: Authorization information is missing or invalid. * 404: - * description: No dailyEventReferences were found + * description: No daily event references were found + * post: + * summary: Creates a new daily event reference + * tags: + * - daily-event-reference + * responses: + * 201: + * description: OK, daily event reference created + * model: DailyEventReference + * 400: + * description: Bad request. DailyEventReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. */ -async function allDailyEventReferences( - _: NextApiRequest, - res: NextApiResponse +async function createOrlistAllDailyEventReferences( + req: NextApiRequest, + res: NextApiResponse ) { - const dailyEventReferences = await prisma.dailyEventReference.findMany(); - const data = dailyEventReferences.map((dailyEventReference) => - schemaDailyEventReferencePublic.parse(dailyEventReference) - ); + const { method } = req; + if (method === "GET") { + const data = await prisma.dailyEventReference.findMany(); + const daily_event_references = data.map((dailyEventReference) => + schemaDailyEventReferencePublic.parse(dailyEventReference) + ); + if (daily_event_references) res.status(200).json({ daily_event_references }); + else + (error: Error) => + res.status(404).json({ + message: "No DailyEventReferences were found", + error, + }); + } else if (method === "POST") { + const safe = schemaDailyEventReferenceBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body"); - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "No DailyEventReferences were found", - error, - }); + const data = await prisma.dailyEventReference.create({ data: safe.data }); + const daily_event_reference = schemaDailyEventReferencePublic.parse(data); + + if (daily_event_reference) + res.status(201).json({ daily_event_reference, message: "DailyEventReference created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new daily event reference", + error, + }); + } else res.status(405).json({ message: `Method ${method} not allowed` }); } -export default withMiddleware("HTTP_GET")(allDailyEventReferences); +export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllDailyEventReferences); diff --git a/pages/api/daily-event-references/new.ts b/pages/api/daily-event-references/new.ts deleted file mode 100644 index 1e61a7fa59..0000000000 --- a/pages/api/daily-event-references/new.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { DailyEventReferenceResponse } from "@lib/types"; -import { - schemaDailyEventReferenceBodyParams, - schemaDailyEventReferencePublic, - withValidDailyEventReference, -} from "@lib/validations/daily-event-reference"; - -/** - * @swagger - * /api/daily-event-references/new: - * post: - * summary: Creates a new dailyEventReference - * requestBody: - * description: Optional description in *Markdown* - * required: true - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/DailyEventReference' - * tags: - * - daily-event-references - * responses: - * 201: - * description: OK, dailyEventReference created - * model: DailyEventReference - * 400: - * description: Bad request. DailyEventReference body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createDailyEventReference( - req: NextApiRequest, - res: NextApiResponse -) { - const safe = schemaDailyEventReferenceBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body", safe.error); - - const dailyEventReference = await prisma.dailyEventReference.create({ data: safe.data }); - const data = schemaDailyEventReferencePublic.parse(dailyEventReference); - - if (data) res.status(201).json({ data, message: "DailyEventReference created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new dailyEventReference", - error, - }); -} - -export default withMiddleware("HTTP_POST")(withValidDailyEventReference(createDailyEventReference)); diff --git a/pages/api/destination-calendars/[id].ts b/pages/api/destination-calendars/[id].ts index 16c5fba7be..a72bcecba1 100644 --- a/pages/api/destination-calendars/[id].ts +++ b/pages/api/destination-calendars/[id].ts @@ -15,7 +15,7 @@ import { /** * @swagger - * /api/destination-calendars/{id}: + * /v1/destination-calendars/{id}: * get: * summary: Get a destination calendar by ID * parameters: @@ -96,7 +96,7 @@ export async function destionationCalendarById( await prisma.destinationCalendar .findUnique({ where: { id: safeQuery.data.id } }) .then((data) => schemaDestinationCalendarPublic.parse(data)) - .then((data) => res.status(200).json({ data })) + .then((destination_calendar) => res.status(200).json({ destination_calendar })) .catch((error: Error) => res .status(404) @@ -111,8 +111,8 @@ export async function destionationCalendarById( where: { id: safeQuery.data.id }, data: safeBody.data, }) - .then((destinationCalendar) => schemaDestinationCalendarPublic.parse(destinationCalendar)) - .then((data) => res.status(200).json({ data })) + .then((data) => schemaDestinationCalendarPublic.parse(data)) + .then((destination_calendar) => res.status(200).json({ destination_calendar })) .catch((error: Error) => res .status(404) diff --git a/pages/api/destination-calendars/index.ts b/pages/api/destination-calendars/index.ts index b031b8a27e..3557272970 100644 --- a/pages/api/destination-calendars/index.ts +++ b/pages/api/destination-calendars/index.ts @@ -3,12 +3,15 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { DestinationCalendarsResponse } from "@lib/types"; -import { schemaDestinationCalendarPublic } from "@lib/validations/destination-calendar"; +import { DestinationCalendarResponse, DestinationCalendarsResponse } from "@lib/types"; +import { + schemaDestinationCalendarBodyParams, + schemaDestinationCalendarPublic, +} from "@lib/validations/destination-calendar"; /** * @swagger - * /api/destination-calendars: + * /v1/destination-calendars: * get: * summary: Get all destination calendars * tags: @@ -19,24 +22,53 @@ import { schemaDestinationCalendarPublic } from "@lib/validations/destination-ca * 401: * description: Authorization information is missing or invalid. * 404: - * description: No destinationCalendars were found + * description: No destination calendars were found + * post: + * summary: Creates a new destination calendar + * tags: + * - destination-calendars + * responses: + * 201: + * description: OK, destination calendar created + * model: DestinationCalendar + * 400: + * description: Bad request. DestinationCalendar body is invalid. + * 401: + * description: Authorization information is missing or invalid. */ -async function allDestinationCalendars( - _: NextApiRequest, - res: NextApiResponse +async function createOrlistAllDestinationCalendars( + req: NextApiRequest, + res: NextApiResponse ) { - const destinationCalendars = await prisma.destinationCalendar.findMany(); - const data = destinationCalendars.map((destinationCalendar) => - schemaDestinationCalendarPublic.parse(destinationCalendar) - ); + const { method } = req; + if (method === "GET") { + const data = await prisma.destinationCalendar.findMany(); + const destination_calendars = data.map((destinationCalendar) => + schemaDestinationCalendarPublic.parse(destinationCalendar) + ); + if (data) res.status(200).json({ destination_calendars }); + else + (error: Error) => + res.status(404).json({ + message: "No DestinationCalendars were found", + error, + }); + } else if (method === "POST") { + const safe = schemaDestinationCalendarBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body"); - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "No DestinationCalendars were found", - error, - }); + const data = await prisma.destinationCalendar.create({ data: safe.data }); + const destination_calendar = schemaDestinationCalendarPublic.parse(data); + + if (destination_calendar) + res.status(201).json({ destination_calendar, message: "DestinationCalendar created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new destinationCalendar", + error, + }); + } else res.status(405).json({ message: `Method ${method} not allowed` }); } -export default withMiddleware("HTTP_GET")(allDestinationCalendars); +export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllDestinationCalendars); diff --git a/pages/api/destination-calendars/new.ts b/pages/api/destination-calendars/new.ts deleted file mode 100644 index e98472b216..0000000000 --- a/pages/api/destination-calendars/new.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { DestinationCalendarResponse } from "@lib/types"; -import { - schemaDestinationCalendarBodyParams, - schemaDestinationCalendarPublic, - withValidDestinationCalendar, -} from "@lib/validations/destination-calendar"; - -/** - * @swagger - * /api/destination-calendars/new: - * post: - * summary: Creates a new destination calendar - * requestBody: - * description: Optional description in *Markdown* - * required: true - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/DestinationCalendar' - * tags: - * - destination-calendars - * responses: - * 201: - * description: OK, destinationCalendar created - * model: DestinationCalendar - * 400: - * description: Bad request. DestinationCalendar body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createDestinationCalendar( - req: NextApiRequest, - res: NextApiResponse -) { - const safe = schemaDestinationCalendarBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body", safe.error); - - const destinationCalendar = await prisma.destinationCalendar.create({ data: safe.data }); - const data = schemaDestinationCalendarPublic.parse(destinationCalendar); - - if (data) res.status(201).json({ data, message: "DestinationCalendar created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new destinationCalendar", - error, - }); -} - -export default withMiddleware("HTTP_POST")(withValidDestinationCalendar(createDestinationCalendar)); diff --git a/pages/api/event-type-custom-inputs/[id].ts b/pages/api/event-type-custom-inputs/[id].ts index c737b5fb84..62b61d9c92 100644 --- a/pages/api/event-type-custom-inputs/[id].ts +++ b/pages/api/event-type-custom-inputs/[id].ts @@ -15,7 +15,7 @@ import { /** * @swagger - * /api/event-type-custom-inputs/{id}: + * /v1/event-type-custom-inputs/{id}: * get: * summary: Get a eventTypeCustomInput by ID * parameters: @@ -93,7 +93,7 @@ async function eventTypeById(req: NextApiRequest, res: NextApiResponse schemaEventTypeCustomInputPublic.parse(data)) - .then((data) => res.status(200).json({ data })) + .then((event_type_custom_input) => res.status(200).json({ event_type_custom_input })) .catch((error: Error) => res.status(404).json({ message: `EventType with id: ${safeQuery.data.id} not found`, error }) ); @@ -106,8 +106,8 @@ async function eventTypeById(req: NextApiRequest, res: NextApiResponse schemaEventTypeCustomInputPublic.parse(eventTypeCustomInput)) - .then((data) => res.status(200).json({ data })) + .then((data) => schemaEventTypeCustomInputPublic.parse(data)) + .then((event_type_custom_input) => res.status(200).json({ event_type_custom_input })) .catch((error: Error) => res.status(404).json({ message: `EventType with id: ${safeQuery.data.id} not found`, error }) ); diff --git a/pages/api/event-type-custom-inputs/index.ts b/pages/api/event-type-custom-inputs/index.ts index d1c8e3ad90..f988adc281 100644 --- a/pages/api/event-type-custom-inputs/index.ts +++ b/pages/api/event-type-custom-inputs/index.ts @@ -3,12 +3,15 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { EventTypeCustomInputsResponse } from "@lib/types"; -import { schemaEventTypeCustomInputPublic } from "@lib/validations/event-type-custom-input"; +import { EventTypeCustomInputResponse, EventTypeCustomInputsResponse } from "@lib/types"; +import { + schemaEventTypeCustomInputBodyParams, + schemaEventTypeCustomInputPublic, +} from "@lib/validations/event-type-custom-input"; /** * @swagger - * /api/event-type-custom-inputs: + * /v1/event-type-custom-inputs: * get: * summary: Get all eventTypeCustomInputs * tags: @@ -20,23 +23,52 @@ import { schemaEventTypeCustomInputPublic } from "@lib/validations/event-type-cu * description: Authorization information is missing or invalid. * 404: * description: No eventTypeCustomInputs were found + * post: + * summary: Creates a new eventTypeCustomInput + * tags: + * - event-type-custom-inputs + * responses: + * 201: + * description: OK, eventTypeCustomInput created + * model: EventTypeCustomInput + * 400: + * description: Bad request. EventTypeCustomInput body is invalid. + * 401: + * description: Authorization information is missing or invalid. */ -async function allEventTypeCustomInputs( - _: NextApiRequest, - res: NextApiResponse +async function createOrlistAllEventTypeCustomInputs( + req: NextApiRequest, + res: NextApiResponse ) { - const eventTypeCustomInputs = await prisma.eventTypeCustomInput.findMany(); - const data = eventTypeCustomInputs.map((eventTypeCustomInput) => - schemaEventTypeCustomInputPublic.parse(eventTypeCustomInput) - ); + const { method } = req; + if (method === "GET") { + const data = await prisma.eventTypeCustomInput.findMany(); + const event_type_custom_inputs = data.map((eventTypeCustomInput) => + schemaEventTypeCustomInputPublic.parse(eventTypeCustomInput) + ); + if (event_type_custom_inputs) res.status(200).json({ event_type_custom_inputs }); + else + (error: Error) => + res.status(404).json({ + message: "No EventTypeCustomInputs were found", + error, + }); + } else if (method === "POST") { + const safe = schemaEventTypeCustomInputBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body"); - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "No EventTypeCustomInputs were found", - error, - }); + const data = await prisma.eventTypeCustomInput.create({ data: safe.data }); + const event_type_custom_input = schemaEventTypeCustomInputPublic.parse(data); + + if (event_type_custom_input) + res.status(201).json({ event_type_custom_input, message: "EventTypeCustomInput created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new eventTypeCustomInput", + error, + }); + } else res.status(405).json({ message: `Method ${method} not allowed` }); } -export default withMiddleware("HTTP_GET")(allEventTypeCustomInputs); +export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllEventTypeCustomInputs); diff --git a/pages/api/event-type-custom-inputs/new.ts b/pages/api/event-type-custom-inputs/new.ts deleted file mode 100644 index 3d64c296dd..0000000000 --- a/pages/api/event-type-custom-inputs/new.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { EventTypeCustomInputResponse } from "@lib/types"; -import { - schemaEventTypeCustomInputBodyParams, - schemaEventTypeCustomInputPublic, - withValidEventTypeCustomInput, -} from "@lib/validations/event-type-custom-input"; - -/** - * @swagger - * /api/event-type-custom-inputs/new: - * post: - * summary: Creates a new eventTypeCustomInput - * requestBody: - * description: Optional description in *Markdown* - * required: true - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/EventTypeCustomInput' - * tags: - * - event-type-custom-inputs - * responses: - * 201: - * description: OK, eventTypeCustomInput created - * model: EventTypeCustomInput - * 400: - * description: Bad request. EventTypeCustomInput body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createEventTypeCustomInput( - req: NextApiRequest, - res: NextApiResponse -) { - const safe = schemaEventTypeCustomInputBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body", safe.error); - - const eventTypeCustomInput = await prisma.eventTypeCustomInput.create({ data: safe.data }); - const data = schemaEventTypeCustomInputPublic.parse(eventTypeCustomInput); - - if (data) res.status(201).json({ data, message: "EventTypeCustomInput created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new eventTypeCustomInput", - error, - }); -} - -export default withMiddleware("HTTP_POST")(withValidEventTypeCustomInput(createEventTypeCustomInput)); diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index dd441f5cd3..e3ffe87f9b 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -12,7 +12,7 @@ import { /** * @swagger - * /api/event-types/{id}: + * /v1/event-types/{id}: * get: * summary: Get a eventType by ID * parameters: @@ -90,7 +90,7 @@ export async function eventTypeById(req: NextApiRequest, res: NextApiResponse schemaEventTypePublic.parse(data)) - .then((data) => res.status(200).json({ data })) + .then((event_type) => res.status(200).json({ event_type })) .catch((error: Error) => res.status(404).json({ message: `EventType with id: ${safeQuery.data.id} not found`, error }) ); @@ -103,8 +103,8 @@ export async function eventTypeById(req: NextApiRequest, res: NextApiResponse schemaEventTypePublic.parse(eventType)) - .then((data) => res.status(200).json({ data })) + .then((data) => schemaEventTypePublic.parse(data)) + .then((event_type) => res.status(200).json({ event_type })) .catch((error: Error) => res.status(404).json({ message: `EventType with id: ${safeQuery.data.id} not found`, error }) ); diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index a626490919..724f0e9769 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -3,14 +3,14 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { EventTypesResponse } from "@lib/types"; -import { schemaEventTypePublic } from "@lib/validations/event-type"; +import { EventTypeResponse, EventTypesResponse } from "@lib/types"; +import { schemaEventTypeBodyParams, schemaEventTypePublic } from "@lib/validations/event-type"; /** * @swagger - * /api/eventTypes: + * /v1/event-types: * get: - * summary: Returns all eventTypes + * summary: Get all event types * tags: * - event-types * responses: @@ -19,19 +19,50 @@ import { schemaEventTypePublic } from "@lib/validations/event-type"; * 401: * description: Authorization information is missing or invalid. * 404: - * description: No eventTypes were found + * description: No event types were found + * post: + * summary: Creates a new event type + * tags: + * - event-types + * responses: + * 201: + * description: OK, event type created + * model: EventType + * 400: + * description: Bad request. EventType body is invalid. + * 401: + * description: Authorization information is missing or invalid. */ -async function allEventTypes(_: NextApiRequest, res: NextApiResponse) { - const eventTypes = await prisma.eventType.findMany(); - const data = eventTypes.map((eventType) => schemaEventTypePublic.parse(eventType)); +async function createOrlistAllEventTypes( + req: NextApiRequest, + res: NextApiResponse +) { + const { method } = req; + if (method === "GET") { + const data = await prisma.eventType.findMany(); + const event_types = data.map((eventType) => schemaEventTypePublic.parse(eventType)); + if (event_types) res.status(200).json({ event_types }); + else + (error: Error) => + res.status(404).json({ + message: "No EventTypes were found", + error, + }); + } else if (method === "POST") { + const safe = schemaEventTypeBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body"); - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "No EventTypes were found", - error, - }); + const data = await prisma.eventType.create({ data: safe.data }); + const event_type = schemaEventTypePublic.parse(data); + + if (data) res.status(201).json({ event_type, message: "EventType created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new event type", + error, + }); + } else res.status(405).json({ message: `Method ${method} not allowed` }); } -export default withMiddleware("HTTP_GET")(allEventTypes); +export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllEventTypes); diff --git a/pages/api/event-types/new.ts b/pages/api/event-types/new.ts deleted file mode 100644 index 491057c453..0000000000 --- a/pages/api/event-types/new.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { EventTypeResponse } from "@lib/types"; -import { - schemaEventTypeBodyParams, - schemaEventTypePublic, - withValidEventType, -} from "@lib/validations/event-type"; - -/** - * @swagger - * /api/event-types/new: - * post: - * summary: Creates a new eventType - * tags: - * - event-types - * responses: - * 201: - * description: OK, eventType created - * model: EventType - * 400: - * description: Bad request. EventType body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createEventType(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaEventTypeBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body", safe.error); - - const eventType = await prisma.eventType.create({ data: safe.data }); - const data = schemaEventTypePublic.parse(eventType); - - if (data) res.status(201).json({ data, message: "EventType created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new eventType", - error, - }); -} - -export default withMiddleware("HTTP_POST")(withValidEventType(createEventType)); diff --git a/pages/api/memberships/[id].ts b/pages/api/memberships/[id].ts index 61f78cc6e8..a963c023f5 100644 --- a/pages/api/memberships/[id].ts +++ b/pages/api/memberships/[id].ts @@ -9,7 +9,7 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ /** * @swagger - * /api/memberships/{userId}_{teamId}: + * /v1/memberships/{userId}_{teamId}: * get: * summary: Get a membership by userID and teamID * parameters: @@ -106,8 +106,8 @@ export async function membershipById(req: NextApiRequest, res: NextApiResponse schemaMembershipPublic.parse(membership)) - .then((data) => res.status(200).json({ data })) + .then((data) => schemaMembershipPublic.parse(data)) + .then((membership) => res.status(200).json({ membership })) .catch((error: Error) => res.status(404).json({ message: `Membership with id: ${safeQuery.data.id} not found`, error }) ); @@ -120,8 +120,8 @@ export async function membershipById(req: NextApiRequest, res: NextApiResponse schemaMembershipPublic.parse(membership)) - .then((data) => res.status(200).json({ data })) + .then((data) => schemaMembershipPublic.parse(data)) + .then((membership) => res.status(200).json({ membership })) .catch((error: Error) => res.status(404).json({ message: `Membership with id: ${safeQuery.data.id} not found`, error }) ); diff --git a/pages/api/memberships/index.ts b/pages/api/memberships/index.ts index d53670ce92..54b6e70c16 100644 --- a/pages/api/memberships/index.ts +++ b/pages/api/memberships/index.ts @@ -3,14 +3,14 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { MembershipsResponse } from "@lib/types"; -import { schemaMembershipPublic } from "@lib/validations/membership"; +import { MembershipResponse, MembershipsResponse } from "@lib/types"; +import { schemaMembershipBodyParams, schemaMembershipPublic } from "@lib/validations/membership"; /** * @swagger - * /api/memberships: + * /v1/memberships: * get: - * summary: Returns all memberships + * summary: Get all memberships * tags: * - memberships * responses: @@ -20,18 +20,49 @@ import { schemaMembershipPublic } from "@lib/validations/membership"; * description: Authorization information is missing or invalid. * 404: * description: No memberships were found + * post: + * summary: Creates a new membership + * tags: + * - memberships + * responses: + * 201: + * description: OK, membership created + * model: Membership + * 400: + * description: Bad request. Membership body is invalid. + * 401: + * description: Authorization information is missing or invalid. */ -async function allMemberships(_: NextApiRequest, res: NextApiResponse) { - const memberships = await prisma.membership.findMany(); - const data = memberships.map((membership) => schemaMembershipPublic.parse(membership)); +async function createOrlistAllMemberships( + req: NextApiRequest, + res: NextApiResponse +) { + const { method } = req; + if (method === "GET") { + const data = await prisma.membership.findMany(); + const memberships = data.map((membership) => schemaMembershipPublic.parse(membership)); + if (memberships) res.status(200).json({ memberships }); + else + (error: Error) => + res.status(404).json({ + message: "No Memberships were found", + error, + }); + } else if (method === "POST") { + const safe = schemaMembershipBodyParams.safeParse(req.body); + if (!safe.success) throw new Error("Invalid request body"); - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "No Memberships were found", - error, - }); + const data = await prisma.membership.create({ data: safe.data }); + const membership = schemaMembershipPublic.parse(data); + + if (membership) res.status(201).json({ membership, message: "Membership created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new membership", + error, + }); + } else res.status(405).json({ message: `Method ${method} not allowed` }); } -export default withMiddleware("HTTP_GET")(allMemberships); +export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllMemberships); diff --git a/pages/api/memberships/new.ts b/pages/api/memberships/new.ts deleted file mode 100644 index e3b9dbe02f..0000000000 --- a/pages/api/memberships/new.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { MembershipResponse } from "@lib/types"; -import { - schemaMembershipBodyParams, - schemaMembershipPublic, - withValidMembership, -} from "@lib/validations/membership"; - -/** - * @swagger - * /api/memberships/new: - * post: - * summary: Creates a new membership - * tags: - * - memberships - * responses: - * 201: - * description: OK, membership created - * model: Membership - * 400: - * description: Bad request. Membership body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createMembership(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaMembershipBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body", safe.error); - - const membership = await prisma.membership.create({ data: safe.data }); - const data = schemaMembershipPublic.parse(membership); - - if (data) res.status(201).json({ data, message: "Membership created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new membership", - error, - }); -} - -export default withMiddleware("HTTP_POST")(withValidMembership(createMembership)); diff --git a/pages/api/payments/[id].ts b/pages/api/payments/[id].ts index bdd8766c69..cdedf473ec 100644 --- a/pages/api/payments/[id].ts +++ b/pages/api/payments/[id].ts @@ -13,7 +13,7 @@ import { /** * @swagger - * /api/payments/{id}: + * /v1/payments/{id}: * get: * summary: Get one of your own payments by ID * parameters: @@ -45,10 +45,10 @@ export async function paymentById(req: NextApiRequest, res: NextApiResponse schemaPaymentPublic.parse(payment)) - .then((data) => { - if (userWithBookings?.bookings.map((b) => b.id).includes(data.bookingId)) { - res.status(200).json({ data }); + .then((data) => schemaPaymentPublic.parse(data)) + .then((payment) => { + if (userWithBookings?.bookings.map((b) => b.id).includes(payment.bookingId)) { + res.status(200).json({ payment }); } else { res.status(401).json({ message: "Unauthorized" }); } diff --git a/pages/api/payments/index.ts b/pages/api/payments/index.ts index 73b32a7d1c..955cff0725 100644 --- a/pages/api/payments/index.ts +++ b/pages/api/payments/index.ts @@ -9,7 +9,7 @@ import { schemaPaymentPublic } from "@lib/validations/payment"; /** * @swagger - * /api/payments: + * /v1/payments: * get: * summary: Get all payments * tags: @@ -32,10 +32,10 @@ async function allPayments(_: NextApiRequest, res: NextApiResponse booking.id); - const payments = await prisma.payment.findMany({ where: { bookingId: { in: bookingIds } } }); - const data = payments.map((payment) => schemaPaymentPublic.parse(payment)); + const data = await prisma.payment.findMany({ where: { bookingId: { in: bookingIds } } }); + const payments = data.map((payment) => schemaPaymentPublic.parse(payment)); - if (data) res.status(200).json({ data }); + if (payments) res.status(200).json({ payments }); else (error: Error) => res.status(404).json({ @@ -43,5 +43,5 @@ async function allPayments(_: NextApiRequest, res: NextApiResponse schemaReminderMailPublic.parse(data)) - .then((data) => res.status(200).json({ data })) + .then((reminder_mail) => res.status(200).json({ reminder_mail })) .catch((error: Error) => res.status(404).json({ message: `ReminderMail with id: ${safeQuery.data.id} not found`, error }) ); @@ -104,7 +104,7 @@ export async function reminderMailById(req: NextApiRequest, res: NextApiResponse data: safeBody.data, }) .then((reminderMail) => schemaReminderMailPublic.parse(reminderMail)) - .then((data) => res.status(200).json({ data })) + .then((reminder_mail) => res.status(200).json({ reminder_mail })) .catch((error: Error) => res.status(404).json({ message: `ReminderMail with id: ${safeQuery.data.id} not found`, error }) ); diff --git a/pages/api/reminder-mails/index.ts b/pages/api/reminder-mails/index.ts index be7025ba21..2c743c0474 100644 --- a/pages/api/reminder-mails/index.ts +++ b/pages/api/reminder-mails/index.ts @@ -43,9 +43,9 @@ async function createOrlistAllReminderMails( ) { const { method } = req; if (method === "GET") { - const reminderMails = await prisma.reminderMail.findMany(); - const data = reminderMails.map((reminderMail) => schemaReminderMailPublic.parse(reminderMail)); - if (data) res.status(200).json({ data }); + const data = await prisma.reminderMail.findMany(); + const reminder_mails = data.map((reminderMail) => schemaReminderMailPublic.parse(reminderMail)); + if (reminder_mails) res.status(200).json({ reminder_mails }); else (error: Error) => res.status(404).json({ @@ -56,10 +56,10 @@ async function createOrlistAllReminderMails( const safe = schemaReminderMailBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body"); - const reminderMail = await prisma.reminderMail.create({ data: safe.data }); - const data = schemaReminderMailPublic.parse(reminderMail); + const data = await prisma.reminderMail.create({ data: safe.data }); + const reminder_mail = schemaReminderMailPublic.parse(data); - if (data) res.status(201).json({ data, message: "reminder mail created successfully" }); + if (reminder_mail) res.status(201).json({ reminder_mail, message: "reminder mail created successfully" }); else (error: Error) => res.status(400).json({ diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index 162f7f9542..c75034e5d1 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -89,8 +89,8 @@ export async function scheduleById(req: NextApiRequest, res: NextApiResponse schemaSchedulePublic.parse(schedule)) - .then((data) => res.status(200).json({ data })) + .then((data) => schemaSchedulePublic.parse(data)) + .then((schedule) => res.status(200).json({ schedule })) .catch((error: Error) => res.status(404).json({ message: `Schedule with id: ${safeQuery.data.id} not found`, error }) ); @@ -103,8 +103,8 @@ export async function scheduleById(req: NextApiRequest, res: NextApiResponse schemaSchedulePublic.parse(schedule)) - .then((data) => res.status(200).json({ data })) + .then((data) => schemaSchedulePublic.parse(data)) + .then((schedule) => res.status(200).json({ schedule })) .catch((error: Error) => res.status(404).json({ message: `Schedule with id: ${safeQuery.data.id} not found`, error }) ); diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index e3b178d216..f8eedf599f 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -39,9 +39,9 @@ async function createOrlistAllSchedules( ) { const { method } = req; if (method === "GET") { - const schedules = await prisma.schedule.findMany(); - const data = schedules.map((schedule) => schemaSchedulePublic.parse(schedule)); - if (data) res.status(200).json({ data }); + const data = await prisma.schedule.findMany(); + const schedules = data.map((schedule) => schemaSchedulePublic.parse(schedule)); + if (schedules) res.status(200).json({ schedules }); else (error: Error) => res.status(404).json({ @@ -52,10 +52,10 @@ async function createOrlistAllSchedules( const safe = schemaScheduleBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body"); - const schedule = await prisma.schedule.create({ data: safe.data }); - const data = schemaSchedulePublic.parse(schedule); + const data = await prisma.schedule.create({ data: safe.data }); + const schedule = schemaSchedulePublic.parse(data); - if (data) res.status(201).json({ data, message: "Schedule created successfully" }); + if (schedule) res.status(201).json({ schedule, message: "Schedule created successfully" }); else (error: Error) => res.status(400).json({ diff --git a/templates/endpoints/[id]/delete.ts b/templates/endpoints/[id]/delete.ts index a9816a3ab6..2b59baee90 100644 --- a/templates/endpoints/[id]/delete.ts +++ b/templates/endpoints/[id]/delete.ts @@ -11,7 +11,7 @@ import { /** * @swagger - * /api/resources/{id}/delete: + * /v1/resources/{id}/delete: * delete: * summary: Remove an existing resource * parameters: diff --git a/templates/endpoints/[id]/edit.ts b/templates/endpoints/[id]/edit.ts index 2be7bd06c1..0e73604fb4 100644 --- a/templates/endpoints/[id]/edit.ts +++ b/templates/endpoints/[id]/edit.ts @@ -4,15 +4,15 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { ResourceResponse } from "@lib/types"; +import { schemaResourceBodyParams, schemaResourcePublic, withValidResource } from "@lib/validations/resource"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -import { schemaResourceBodyParams, schemaResourcePublic, withValidResource } from "@lib/validations/resource"; /** * @swagger - * /api/resources/{id}/edit: + * /v1/resources/{id}/edit: * patch: * summary: Edit an existing resource * parameters: @@ -53,4 +53,6 @@ export async function editResource(req: NextApiRequest, res: NextApiResponse Date: Mon, 11 Apr 2022 15:20:38 +0200 Subject: [PATCH 089/658] Make attendees id endpoint return only user owned resources --- pages/api/attendees/[id].ts | 104 ++++++++++++++++++++++-------------- 1 file changed, 63 insertions(+), 41 deletions(-) diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index 093579a799..50b6b10cec 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { AttendeeResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaAttendeeBodyParams, schemaAttendeePublic } from "@lib/validations/attendee"; import { schemaQueryIdParseInt, @@ -83,48 +84,69 @@ export async function attendeeById(req: NextApiRequest, res: NextApiResponse schemaAttendeePublic.parse(data)) - .then((attendee) => res.status(200).json({ attendee })) - .catch((error: Error) => - res.status(404).json({ message: `Attendee with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - case "PATCH": - if (!safeBody.success) throw new Error("Invalid request body"); - await prisma.attendee - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((data) => schemaAttendeePublic.parse(data)) - .then((attendee) => res.status(200).json({ attendee })) - .catch((error: Error) => - res.status(404).json({ message: `Attendee with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - case "DELETE": - await prisma.attendee - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ message: `Attendee with id: ${safeQuery.data.id} deleted successfully` }) - ) - .catch((error: Error) => - res.status(404).json({ message: `Attendee with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; + if (!safeQuery.success) { + throw new Error("Invalid request query", safeQuery.error); } + const userId = getCalcomUserId(res); + const userBookings = await prisma.booking.findMany({ + where: { userId }, + include: { attendees: true }, + }); + const attendees = userBookings.map((booking) => booking.attendees).flat(); + const attendeeIds = attendees.map((attendee) => attendee.id); + // Here we make sure to only return attendee's of the user's own bookings. + if (attendeeIds.includes(safeQuery.data.id)) { + switch (method) { + case "GET": + await prisma.attendee + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data) => schemaAttendeePublic.parse(data)) + .then((attendee) => res.status(200).json({ attendee })) + .catch((error: Error) => + res.status(404).json({ + message: `Attendee with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; + + case "PATCH": + if (!safeBody.success) { + throw new Error("Invalid request body"); + } + await prisma.attendee + .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) + .then((data) => schemaAttendeePublic.parse(data)) + .then((attendee) => res.status(200).json({ attendee })) + .catch((error: Error) => + res.status(404).json({ + message: `Attendee with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; + + case "DELETE": + await prisma.attendee + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ + message: `Attendee with id: ${safeQuery.data.id} deleted successfully`, + }) + ) + .catch((error: Error) => + res.status(404).json({ + message: `Attendee with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; + + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } + } else res.status(401).json({ message: "Unauthorized" }); } export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(attendeeById)); From fca49a23c59b772186d92721402abb1f9110820c Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 11 Apr 2022 15:26:06 +0200 Subject: [PATCH 090/658] feat: make availabilities safe and return only userId related resources --- pages/api/availabilities/[id].ts | 83 +++++++++++++++++-------------- pages/api/availabilities/index.ts | 5 +- 2 files changed, 50 insertions(+), 38 deletions(-) diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index 34bab03008..db660b1074 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { AvailabilityResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaAvailabilityBodyParams, schemaAvailabilityPublic } from "@lib/validations/availability"; import { schemaQueryIdParseInt, @@ -84,46 +85,54 @@ export async function availabilityById(req: NextApiRequest, res: NextApiResponse const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaAvailabilityBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + const userId = await getCalcomUserId(res); + const data = await prisma.availability.findMany({ where: { userId } }); + const availabiltiesIds = data.map((availability) => availability.id); + if (availabiltiesIds.includes(safeQuery.data.id)) { + switch (method) { + case "GET": + await prisma.availability + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data) => schemaAvailabilityPublic.parse(data)) + .then((availability) => res.status(200).json({ availability })) + .catch((error: Error) => + res.status(404).json({ message: `Availability with id: ${safeQuery.data.id} not found`, error }) + ); + break; - switch (method) { - case "GET": - await prisma.availability - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaAvailabilityPublic.parse(data)) - .then((availability) => res.status(200).json({ availability })) - .catch((error: Error) => - res.status(404).json({ message: `Availability with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "PATCH": + if (!safeBody.success) throw new Error("Invalid request body"); + await prisma.availability + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((data) => schemaAvailabilityPublic.parse(data)) + .then((availability) => res.status(200).json({ availability })) + .catch((error: Error) => + res.status(404).json({ message: `Availability with id: ${safeQuery.data.id} not found`, error }) + ); + break; - case "PATCH": - if (!safeBody.success) throw new Error("Invalid request body"); - await prisma.availability - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((data) => schemaAvailabilityPublic.parse(data)) - .then((availability) => res.status(200).json({ availability })) - .catch((error: Error) => - res.status(404).json({ message: `Availability with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "DELETE": + await prisma.availability + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res + .status(200) + .json({ message: `Availability with id: ${safeQuery.data.id} deleted successfully` }) + ) + .catch((error: Error) => + res.status(404).json({ message: `Availability with id: ${safeQuery.data.id} not found`, error }) + ); + break; - case "DELETE": - await prisma.availability - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ message: `Availability with id: ${safeQuery.data.id} deleted successfully` }) - ) - .catch((error: Error) => - res.status(404).json({ message: `Availability with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } + } else { + res.status(401).json({ message: "Unauthorized" }); } } diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index 9778bfdbfa..425436bb14 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { AvailabilityResponse, AvailabilitiesResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaAvailabilityBodyParams, schemaAvailabilityPublic } from "@lib/validations/availability"; /** @@ -38,8 +39,10 @@ async function createOrlistAllAvailabilities( res: NextApiResponse ) { const { method } = req; + const userId = await getCalcomUserId(res); + if (method === "GET") { - const data = await prisma.availability.findMany(); + const data = await prisma.availability.findMany({ where: { userId } }); const availabilities = data.map((availability) => schemaAvailabilityPublic.parse(availability)); if (availabilities) res.status(200).json({ availabilities }); else From 9cefd119ee306f5a8eb81b055d02a7005eb13cca Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 11 Apr 2022 15:42:50 +0200 Subject: [PATCH 091/658] feat: make booking-references only return user booking related resources --- pages/api/booking-references/[id].ts | 101 ++++++++++++++++---------- pages/api/booking-references/index.ts | 11 ++- 2 files changed, 73 insertions(+), 39 deletions(-) diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index 2d48aa7413..2fac6f79db 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -1,9 +1,11 @@ +import { BookingModel } from "@/../../packages/prisma/zod"; import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { BookingReferenceResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaBookingReferenceBodyParams, schemaBookingReferencePublic, @@ -91,47 +93,70 @@ export async function bookingReferenceById( const safeBody = schemaBookingReferenceBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); // FIXME: Allow only userId owner of booking ref to edit it + const userId = await getCalcomUserId(res); + const userWithBookings = await prisma.user.findUnique({ + where: { id: userId }, + include: { bookings: true }, + }); + if (!userWithBookings) throw new Error("User not found"); + const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); + console.log(userBookingIds); + const bookingReference = await prisma.bookingReference.findUnique({ where: { id: safeQuery.data.id } }); + if (!bookingReference) throw new Error("BookingReference not found"); + if (userBookingIds.includes(bookingReference.bookingId)) { + switch (method) { + case "GET": + await prisma.bookingReference + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data) => schemaBookingReferencePublic.parse(data)) + .then((booking_reference) => res.status(200).json({ booking_reference })) + .catch((error: Error) => + res.status(404).json({ + message: `BookingReference with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - switch (method) { - case "GET": - await prisma.bookingReference - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaBookingReferencePublic.parse(data)) - .then((booking_reference) => res.status(200).json({ booking_reference })) - .catch((error: Error) => - res.status(404).json({ message: `BookingReference with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "PATCH": + if (!safeBody.success) { + throw new Error("Invalid request body"); + } + await prisma.bookingReference + .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) + .then((data) => schemaBookingReferencePublic.parse(data)) + .then((booking_reference) => res.status(200).json({ booking_reference })) + .catch((error: Error) => + res.status(404).json({ + message: `BookingReference with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - case "PATCH": - if (!safeBody.success) throw new Error("Invalid request body"); - await prisma.bookingReference - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((data) => schemaBookingReferencePublic.parse(data)) - .then((booking_reference) => res.status(200).json({ booking_reference })) - .catch((error: Error) => - res.status(404).json({ message: `BookingReference with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "DELETE": + await prisma.bookingReference + .delete({ + where: { id: safeQuery.data.id }, + }) + .then(() => + res.status(200).json({ + message: `BookingReference with id: ${safeQuery.data.id} deleted`, + }) + ) + .catch((error: Error) => + res.status(404).json({ + message: `BookingReference with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - case "DELETE": - await prisma.bookingReference - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ message: `BookingReference with id: ${safeQuery.data.id} deleted` }) - ) - .catch((error: Error) => - res.status(404).json({ message: `BookingReference with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } + } else res.status(401).json({ message: "Unauthorized" }); } export default withMiddleware("HTTP_GET_DELETE_PATCH")( diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index 0ca58c2f8a..13519a67ec 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { BookingReferenceResponse, BookingReferencesResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaBookingReferenceBodyParams, schemaBookingReferencePublic, @@ -41,8 +42,16 @@ async function createOrlistAllBookingReferences( res: NextApiResponse ) { const { method } = req; + const userId = await getCalcomUserId(res); + const userWithBookings = await prisma.user.findUnique({ + where: { id: userId }, + include: { bookings: true }, + }); + if (!userWithBookings) throw new Error("User not found"); + const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); + console.log(userBookingIds); if (method === "GET") { - const data = await prisma.bookingReference.findMany(); + const data = await prisma.bookingReference.findMany({ where: { id: { in: userBookingIds } } }); const booking_references = data.map((bookingReference) => schemaBookingReferencePublic.parse(bookingReference) ); From 9447bd859de40b735afc366caefa171abc1d7120 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 11 Apr 2022 16:47:01 +0200 Subject: [PATCH 092/658] feat hardened attendees, availabilites, booking-references, and bookings --- pages/api/attendees/index.ts | 41 ++++++++---- pages/api/availabilities/index.ts | 2 +- pages/api/booking-references/[id].ts | 2 - pages/api/bookings/[id].ts | 98 +++++++++++++++++----------- pages/api/bookings/index.ts | 7 +- 5 files changed, 95 insertions(+), 55 deletions(-) diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index 509907bb8d..59561c736e 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -65,20 +65,39 @@ async function createOrlistAllAttendees( throw new Error("Invalid request body", safe.error); } const bookingId = safe.data.bookingId; - delete safe.data.bookingId; - const noBookingId = safe.data; - const data = await prisma.attendee.create({ - data: { ...noBookingId, booking: { connect: { id: parseInt(bookingId as string) } } }, + const userId = await getCalcomUserId(res); + const userWithBookings = await prisma.user.findUnique({ + where: { id: userId }, + include: { bookings: true }, }); - const attendee = schemaAttendeePublic.parse(data); + if (!userWithBookings) { + throw new Error("User not found"); + } + const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); + if (userBookingIds.includes(bookingId)) { + delete safe.data.bookingId; + const noBookingId = safe.data; + const data = await prisma.attendee.create({ + data: { + ...noBookingId, + booking: { connect: { id: bookingId } }, + }, + }); + const attendee = schemaAttendeePublic.parse(data); - if (attendee) res.status(201).json({ attendee, message: "Attendee created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new attendee", - error, + if (attendee) { + res.status(201).json({ + attendee, + message: "Attendee created successfully", }); + } else { + (error: Error) => + res.status(400).json({ + message: "Could not create new attendee", + error, + }); + } + } else res.status(401).json({ message: "Unauthorized" }); } else res.status(405).json({ message: `Method ${method} not allowed` }); } diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index 425436bb14..45349b6b3f 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -55,7 +55,7 @@ async function createOrlistAllAvailabilities( const safe = schemaAvailabilityBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body"); - const data = await prisma.availability.create({ data: safe.data }); + const data = await prisma.availability.create({ data: { ...safe.data, userId } }); const availability = schemaAvailabilityPublic.parse(data); if (availability) res.status(201).json({ availability, message: "Availability created successfully" }); diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index 2fac6f79db..c9527e3f99 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -92,7 +92,6 @@ export async function bookingReferenceById( const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaBookingReferenceBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - // FIXME: Allow only userId owner of booking ref to edit it const userId = await getCalcomUserId(res); const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, @@ -100,7 +99,6 @@ export async function bookingReferenceById( }); if (!userWithBookings) throw new Error("User not found"); const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); - console.log(userBookingIds); const bookingReference = await prisma.bookingReference.findUnique({ where: { id: safeQuery.data.id } }); if (!bookingReference) throw new Error("BookingReference not found"); if (userBookingIds.includes(bookingReference.bookingId)) { diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index 45f24774e6..54e21b5109 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { BookingResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaBookingBodyParams, schemaBookingPublic } from "@lib/validations/booking"; import { schemaQueryIdParseInt, @@ -84,47 +85,68 @@ export async function bookingById(req: NextApiRequest, res: NextApiResponse schemaBookingPublic.parse(data)) - .then((booking) => res.status(200).json({ booking })) - .catch((error: Error) => - res.status(404).json({ message: `Booking with id: ${safeQuery.data.id} not found`, error }) - ); - break; + const userId = await getCalcomUserId(res); + const userWithBookings = await prisma.user.findUnique({ + where: { id: userId }, + include: { bookings: true }, + }); + if (!userWithBookings) throw new Error("User not found"); + const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); + if (userBookingIds.includes(safeQuery.data.id)) { + switch (method) { + case "GET": + await prisma.booking + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data) => schemaBookingPublic.parse(data)) + .then((booking) => res.status(200).json({ booking })) + .catch((error: Error) => + res.status(404).json({ + message: `Booking with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - case "PATCH": - if (!safeBody.success) throw new Error("Invalid request body"); - await prisma.booking - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((data) => schemaBookingPublic.parse(data)) - .then((booking) => res.status(200).json({ booking })) - .catch((error: Error) => - res.status(404).json({ message: `Booking with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "PATCH": + if (!safeBody.success) { + throw new Error("Invalid request body"); + } + await prisma.booking + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((data) => schemaBookingPublic.parse(data)) + .then((booking) => res.status(200).json({ booking })) + .catch((error: Error) => + res.status(404).json({ + message: `Booking with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - case "DELETE": - await prisma.booking - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ message: `Booking with id: ${safeQuery.data.id} deleted successfully` }) - ) - .catch((error: Error) => - res.status(404).json({ message: `Booking with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "DELETE": + await prisma.booking + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ + message: `Booking with id: ${safeQuery.data.id} deleted successfully`, + }) + ) + .catch((error: Error) => + res.status(404).json({ + message: `Booking with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } + } else res.status(401).json({ message: "Unauthorized" }); } export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(bookingById)); diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index fd5f8b19af..2b2b55bf21 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { BookingResponse, BookingsResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaBookingBodyParams, schemaBookingPublic, withValidBooking } from "@lib/validations/booking"; /** @@ -38,10 +39,10 @@ async function createOrlistAllBookings( res: NextApiResponse ) { const { method } = req; - // FIXME: List only bookings owner by userId + const userId = await getCalcomUserId(res); if (method === "GET") { - const data = await prisma.booking.findMany(); + const data = await prisma.booking.findMany({ where: { userId } }); const bookings = data.map((booking) => schemaBookingPublic.parse(booking)); if (bookings) res.status(200).json({ bookings }); else @@ -54,7 +55,7 @@ async function createOrlistAllBookings( const safe = schemaBookingBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body"); - const data = await prisma.booking.create({ data: safe.data }); + const data = await prisma.booking.create({ data: { ...safe.data, userId } }); const booking = schemaBookingPublic.parse(data); if (booking) res.status(201).json({ booking, message: "Booking created successfully" }); From d987d52dbbacfa4c62e01ac77953b1d11b123033 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 13 Apr 2022 02:12:16 +0200 Subject: [PATCH 093/658] feat: credentials, teams --- .env.example | 2 +- lib/helpers/verifyApiKey.ts | 4 +- pages/api/attendees/index.ts | 1 - pages/api/booking-references/index.ts | 38 +++++++++---- pages/api/credentials/[id].ts | 82 ++++++++++++++------------- pages/api/credentials/index.ts | 10 +++- pages/api/teams/[id].ts | 1 + pages/api/teams/index.ts | 2 +- 8 files changed, 85 insertions(+), 55 deletions(-) diff --git a/.env.example b/.env.example index f3271e560c..038c1ebd26 100644 --- a/.env.example +++ b/.env.example @@ -1 +1 @@ -API_KEY_PREFIX=cal_ \ No newline at end of file +API_KEY_PREFIX=pt_secret_ \ No newline at end of file diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 694de73593..9986707884 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -15,7 +15,7 @@ const today = new Date(); export const verifyApiKey: NextMiddleware = async (req, res, next) => { if (!req.query.apiKey) res.status(401).json({ message: "No API key provided" }); - const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "cal_", ""); + const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "pt_secret_", ""); const hashedKey = hashAPIKey(strippedApiKey); await prisma.apiKey @@ -25,7 +25,7 @@ export const verifyApiKey: NextMiddleware = async (req, res, next) => { res.status(401).json({ error: "You did not provide an api key" }); throw new Error("No api key found"); } - if (apiKey.userId) res.setHeader("X-Calcom-User-ID", apiKey?.userId); + if (apiKey.userId) res.setHeader("X-Calcom-User-ID", apiKey.userId); if (apiKey.expiresAt && apiKey.userId && dateInPast(today, apiKey.expiresAt)) await next(); }) .catch((error) => { diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index 59561c736e..5185acda2c 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -61,7 +61,6 @@ async function createOrlistAllAttendees( } else if (method === "POST") { const safe = schemaAttendeeBodyParams.safeParse(req.body); if (!safe.success) { - console.log(safe.error); throw new Error("Invalid request body", safe.error); } const bookingId = safe.data.bookingId; diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index 13519a67ec..bef6acdca1 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -49,7 +49,6 @@ async function createOrlistAllBookingReferences( }); if (!userWithBookings) throw new Error("User not found"); const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); - console.log(userBookingIds); if (method === "GET") { const data = await prisma.bookingReference.findMany({ where: { id: { in: userBookingIds } } }); const booking_references = data.map((bookingReference) => @@ -64,18 +63,37 @@ async function createOrlistAllBookingReferences( }); } else if (method === "POST") { const safe = schemaBookingReferenceBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body"); + if (!safe.success) { + throw new Error("Invalid request body"); + } - const data = await prisma.bookingReference.create({ data: safe.data }); + const data = await prisma.bookingReference.create({ + data: { ...safe.data }, + }); const booking_reference = schemaBookingReferencePublic.parse(data); - - if (data) res.status(201).json({ booking_reference, message: "BookingReference created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new booking reference", - error, + const userId = await getCalcomUserId(res); + const userWithBookings = await prisma.user.findUnique({ + where: { id: userId }, + include: { bookings: true }, + }); + if (!userWithBookings) { + throw new Error("User not found"); + } + const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); + if (userBookingIds.includes(safe.data.bookingId)) { + if (data) { + res.status(201).json({ + booking_reference, + message: "BookingReference created successfully", }); + } else { + (error: Error) => + res.status(400).json({ + message: "Could not create new booking reference", + error, + }); + } + } else res.status(401).json({ message: "Unauthorized" }); } else res.status(405).json({ message: `Method ${method} not allowed` }); } diff --git a/pages/api/credentials/[id].ts b/pages/api/credentials/[id].ts index bb82d0f019..52c95fd023 100644 --- a/pages/api/credentials/[id].ts +++ b/pages/api/credentials/[id].ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { CredentialResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaCredentialBodyParams, schemaCredentialPublic } from "@lib/validations/credential"; import { schemaQueryIdParseInt, @@ -84,47 +85,52 @@ export async function credentialById(req: NextApiRequest, res: NextApiResponse credential.id); + // res.status(200).json({ data }); + if (credentialIds.includes(safeQuery.data.id)) { + switch (method) { + case "GET": + await prisma.credential + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data) => schemaCredentialPublic.parse(data)) + .then((credential) => res.status(200).json({ credential })) + .catch((error: Error) => + res.status(404).json({ message: `Credential with id: ${safeQuery.data.id} not found`, error }) + ); + break; - switch (method) { - case "GET": - await prisma.credential - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaCredentialPublic.parse(data)) - .then((credential) => res.status(200).json({ credential })) - .catch((error: Error) => - res.status(404).json({ message: `Credential with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "PATCH": + if (!safeBody.success) throw new Error("Invalid request body"); + await prisma.credential + .update({ + where: { id: safeQuery.data.id }, + data: safeBody.data, + }) + .then((data) => schemaCredentialPublic.parse(data)) + .then((credential) => res.status(200).json({ credential })) + .catch((error: Error) => + res.status(404).json({ message: `Credential with id: ${safeQuery.data.id} not found`, error }) + ); + break; - case "PATCH": - if (!safeBody.success) throw new Error("Invalid request body"); - await prisma.credential - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((data) => schemaCredentialPublic.parse(data)) - .then((credential) => res.status(200).json({ credential })) - .catch((error: Error) => - res.status(404).json({ message: `Credential with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "DELETE": + await prisma.credential + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ message: `Credential with id: ${safeQuery.data.id} deleted successfully` }) + ) + .catch((error: Error) => + res.status(404).json({ message: `Credential with id: ${safeQuery.data.id} not found`, error }) + ); + break; - case "DELETE": - await prisma.credential - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ message: `Credential with id: ${safeQuery.data.id} deleted successfully` }) - ) - .catch((error: Error) => - res.status(404).json({ message: `Credential with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } + } else res.status(401).json({ message: "Unauthorized" }); } export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(credentialById)); diff --git a/pages/api/credentials/index.ts b/pages/api/credentials/index.ts index 8ba9a5aeb5..d7b9ed651f 100644 --- a/pages/api/credentials/index.ts +++ b/pages/api/credentials/index.ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { CredentialResponse, CredentialsResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaCredentialBodyParams, schemaCredentialPublic } from "@lib/validations/credential"; /** @@ -38,8 +39,10 @@ async function createOrlistAllCredentials( res: NextApiResponse ) { const { method } = req; + const userId = getCalcomUserId(res); + if (method === "GET") { - const data = await prisma.credential.findMany(); + const data = await prisma.credential.findMany({ where: { userId } }); const credentials = data.map((credential) => schemaCredentialPublic.parse(credential)); if (credentials) res.status(200).json({ credentials }); else @@ -55,7 +58,10 @@ async function createOrlistAllCredentials( const data = await prisma.credential.create({ data: safe.data }); const credential = schemaCredentialPublic.parse(data); - if (credential) res.status(201).json({ credential, message: "Credential created successfully" }); + if (credential) + res + .status(201) + .json({ credential: { ...credential, userId }, message: "Credential created successfully" }); else (error: Error) => res.status(400).json({ diff --git a/pages/api/teams/[id].ts b/pages/api/teams/[id].ts index 5435b18dc5..70f88c1b35 100644 --- a/pages/api/teams/[id].ts +++ b/pages/api/teams/[id].ts @@ -89,6 +89,7 @@ export async function teamById(req: NextApiRequest, res: NextApiResponse Date: Wed, 13 Apr 2022 18:53:44 +0200 Subject: [PATCH 094/658] adds app-store to be transpiled to fix build --- next.config.js | 7 ++++++- pages/api/booking-references/index.ts | 10 +++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/next.config.js b/next.config.js index c6f75ad063..acf9c9830c 100644 --- a/next.config.js +++ b/next.config.js @@ -1,6 +1,11 @@ // https://www.npmjs.com/package/next-transpile-modules // This makes our @calcom/prisma package from the monorepo to be transpiled and usable by API -const withTM = require("next-transpile-modules")(["@calcom/prisma", "@calcom/lib", "@calcom/ee"]); +const withTM = require("next-transpile-modules")([ + "@calcom/app-store", + "@calcom/prisma", + "@calcom/lib", + "@calcom/ee", +]); // use something like withPlugins([withTM], {}) if more plugins added later. diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index bef6acdca1..4fba496dd3 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -67,10 +67,7 @@ async function createOrlistAllBookingReferences( throw new Error("Invalid request body"); } - const data = await prisma.bookingReference.create({ - data: { ...safe.data }, - }); - const booking_reference = schemaBookingReferencePublic.parse(data); + // const booking_reference = schemaBookingReferencePublic.parse(data); const userId = await getCalcomUserId(res); const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, @@ -81,7 +78,10 @@ async function createOrlistAllBookingReferences( } const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); if (userBookingIds.includes(safe.data.bookingId)) { - if (data) { + const booking_reference = await prisma.bookingReference.create({ + data: { ...safe.data }, + }); + if (booking_reference) { res.status(201).json({ booking_reference, message: "BookingReference created successfully", From 187b97afa169f61511cbce4e75e1c6affab56f17 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 14 Apr 2022 21:46:26 +0200 Subject: [PATCH 095/658] fix: update prefix to cal_ --- .env.example | 2 +- lib/helpers/verifyApiKey.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 038c1ebd26..f3271e560c 100644 --- a/.env.example +++ b/.env.example @@ -1 +1 @@ -API_KEY_PREFIX=pt_secret_ \ No newline at end of file +API_KEY_PREFIX=cal_ \ No newline at end of file diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 9986707884..6fe33c6ad3 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -15,7 +15,7 @@ const today = new Date(); export const verifyApiKey: NextMiddleware = async (req, res, next) => { if (!req.query.apiKey) res.status(401).json({ message: "No API key provided" }); - const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "pt_secret_", ""); + const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "cal_", ""); const hashedKey = hashAPIKey(strippedApiKey); await prisma.apiKey From babfc6d7cfcb0218903425114d540621b936b89f Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 15 Apr 2022 16:10:57 +0200 Subject: [PATCH 096/658] adds cors support to docs endpoint --- lib/helpers/withCors.ts | 17 +++++++++++++++++ package.json | 1 + pages/api/docs.ts | 5 ++++- 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 lib/helpers/withCors.ts diff --git a/lib/helpers/withCors.ts b/lib/helpers/withCors.ts new file mode 100644 index 0000000000..e0034ae1dd --- /dev/null +++ b/lib/helpers/withCors.ts @@ -0,0 +1,17 @@ +import type { NextMiddleware } from "next-api-middleware"; +import NextCors from "nextjs-cors"; + +export const withCors: NextMiddleware = async (req, res, next) => { + // Run the cors middleware + // nextjs-cors uses the cors package, so we invite you to check the documentation https://github.com/expressjs/cors + await NextCors(req, res, { + // Options + methods: ["GET", "HEAD", "PUT", "PATCH", "POST", "DELETE"], + origin: "*", + optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204 + }); + + // Rest of the API logic + // Execute the remaining middleware + await next(); +}; diff --git a/package.json b/package.json index 16dc0f9b9f..971c197c42 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "next-swagger-doc": "^0.2.1", "next-transpile-modules": "^9.0.0", "next-validations": "^0.1.11", + "nextjs-cors": "^2.1.1", "typescript": "^4.6.3" } } diff --git a/pages/api/docs.ts b/pages/api/docs.ts index d9aa75d18c..39b36362f5 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -2,6 +2,9 @@ import jsonSchema from "@/json-schema/json-schema.json"; import pjson from "@/package.json"; import { withSwagger } from "next-swagger-doc"; +import { withCors } from "@lib/helpers/withCors"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; + const swaggerHandler = withSwagger({ definition: { openapi: "3.0.0", @@ -16,4 +19,4 @@ const swaggerHandler = withSwagger({ tags: ["users", "teams", "memeberships"], sort: true, }); -export default swaggerHandler(); +export default withMiddleware(withCors)(swaggerHandler()); From 09d8b48cccf332c9a063f9721857a715c56f380e Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 15 Apr 2022 16:46:50 +0200 Subject: [PATCH 097/658] make verifyApiKey not apply in docs --- lib/helpers/verifyApiKey.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 6fe33c6ad3..998f783c77 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -13,11 +13,12 @@ const today = new Date(); // This verifies the API key and sets the user if it is valid. export const verifyApiKey: NextMiddleware = async (req, res, next) => { + const pathIsDocs = req.url?.startsWith("/docs"); + if (pathIsDocs) await next() if (!req.query.apiKey) res.status(401).json({ message: "No API key provided" }); const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "cal_", ""); const hashedKey = hashAPIKey(strippedApiKey); - await prisma.apiKey .findUnique({ where: { hashedKey } }) .then(async (apiKey) => { From e251fccb61769d376a6c1db69df49d28a012b3ee Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 15 Apr 2022 16:47:08 +0200 Subject: [PATCH 098/658] make verifyApiKey not apply in docs --- lib/helpers/verifyApiKey.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 998f783c77..653d8067ee 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -14,7 +14,7 @@ const today = new Date(); // This verifies the API key and sets the user if it is valid. export const verifyApiKey: NextMiddleware = async (req, res, next) => { const pathIsDocs = req.url?.startsWith("/docs"); - if (pathIsDocs) await next() + if (pathIsDocs) await next(); if (!req.query.apiKey) res.status(401).json({ message: "No API key provided" }); const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "cal_", ""); From ca8ca913a8c0b82bd797b49e9d708cfaee2a100f Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 15 Apr 2022 16:55:55 +0200 Subject: [PATCH 099/658] add else if to api key request --- lib/helpers/verifyApiKey.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 653d8067ee..9a40ce5f25 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -15,7 +15,7 @@ const today = new Date(); export const verifyApiKey: NextMiddleware = async (req, res, next) => { const pathIsDocs = req.url?.startsWith("/docs"); if (pathIsDocs) await next(); - if (!req.query.apiKey) res.status(401).json({ message: "No API key provided" }); + else if (!req.query.apiKey) res.status(401).json({ message: "No API key provided" }); const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "cal_", ""); const hashedKey = hashAPIKey(strippedApiKey); From a4851bd0b69e6091b14830a9b745f0a28cb5a142 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 15 Apr 2022 17:04:17 +0200 Subject: [PATCH 100/658] fix add new withCorsMiddleware --- lib/helpers/verifyApiKey.ts | 5 ++--- lib/helpers/withCorsMiddleware.ts | 12 ++++++++++++ pages/api/docs.ts | 4 ++-- 3 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 lib/helpers/withCorsMiddleware.ts diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 9a40ce5f25..6fe33c6ad3 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -13,12 +13,11 @@ const today = new Date(); // This verifies the API key and sets the user if it is valid. export const verifyApiKey: NextMiddleware = async (req, res, next) => { - const pathIsDocs = req.url?.startsWith("/docs"); - if (pathIsDocs) await next(); - else if (!req.query.apiKey) res.status(401).json({ message: "No API key provided" }); + if (!req.query.apiKey) res.status(401).json({ message: "No API key provided" }); const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "cal_", ""); const hashedKey = hashAPIKey(strippedApiKey); + await prisma.apiKey .findUnique({ where: { hashedKey } }) .then(async (apiKey) => { diff --git a/lib/helpers/withCorsMiddleware.ts b/lib/helpers/withCorsMiddleware.ts new file mode 100644 index 0000000000..14182eff99 --- /dev/null +++ b/lib/helpers/withCorsMiddleware.ts @@ -0,0 +1,12 @@ +import { label } from "next-api-middleware"; + +import { withCors } from "./withCors"; + +const withCorsMiddleware = label( + { + withCors, + }, + ["withCors"] // <-- Provide a list of middleware to call automatically +); + +export { withCorsMiddleware }; diff --git a/pages/api/docs.ts b/pages/api/docs.ts index 39b36362f5..e4f721bb8f 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -3,7 +3,7 @@ import pjson from "@/package.json"; import { withSwagger } from "next-swagger-doc"; import { withCors } from "@lib/helpers/withCors"; -import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { withCorsMiddleware } from "@lib/helpers/withCorsMiddleware"; const swaggerHandler = withSwagger({ definition: { @@ -19,4 +19,4 @@ const swaggerHandler = withSwagger({ tags: ["users", "teams", "memeberships"], sort: true, }); -export default withMiddleware(withCors)(swaggerHandler()); +export default withCorsMiddleware()(swaggerHandler()); From a543d1fde32da3ba53e27eeb3333852da7adb86b Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 15 Apr 2022 17:29:03 +0200 Subject: [PATCH 101/658] disable middleware for cors --- pages/api/docs.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pages/api/docs.ts b/pages/api/docs.ts index e4f721bb8f..34ad0d7c5e 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -2,7 +2,6 @@ import jsonSchema from "@/json-schema/json-schema.json"; import pjson from "@/package.json"; import { withSwagger } from "next-swagger-doc"; -import { withCors } from "@lib/helpers/withCors"; import { withCorsMiddleware } from "@lib/helpers/withCorsMiddleware"; const swaggerHandler = withSwagger({ @@ -19,4 +18,4 @@ const swaggerHandler = withSwagger({ tags: ["users", "teams", "memeberships"], sort: true, }); -export default withCorsMiddleware()(swaggerHandler()); +export default swaggerHandler(); From 02855ef0202c51a93d61e2c9ac5d95ef1b1a1f6c Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 15 Apr 2022 17:35:05 +0200 Subject: [PATCH 102/658] disable cors --- next.config.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/next.config.js b/next.config.js index acf9c9830c..fa5bc84e10 100644 --- a/next.config.js +++ b/next.config.js @@ -10,6 +10,24 @@ const withTM = require("next-transpile-modules")([ // use something like withPlugins([withTM], {}) if more plugins added later. module.exports = withTM({ + async headers() { + return [ + { + // matching all API routes + source: "/api/:path*", + headers: [ + { key: "Access-Control-Allow-Credentials", value: "true" }, + { key: "Access-Control-Allow-Origin", value: "*" }, + { key: "Access-Control-Allow-Methods", value: "GET,OPTIONS,PATCH,DELETE,POST,PUT" }, + { + key: "Access-Control-Allow-Headers", + value: + "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version, Content-Type, api_key, Authorization", + }, + ], + }, + ]; + }, async rewrites() { return [ // This redirects requests recieved at / the root to the /api/ folder. From 04052c53b459ab1d13cdbce589c7c913b0826b44 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 15 Apr 2022 18:12:25 +0200 Subject: [PATCH 103/658] cleanup no cors middleware --- lib/helpers/withCors.ts | 17 ----------------- lib/helpers/withCorsMiddleware.ts | 12 ------------ pages/api/docs.ts | 2 -- 3 files changed, 31 deletions(-) delete mode 100644 lib/helpers/withCors.ts delete mode 100644 lib/helpers/withCorsMiddleware.ts diff --git a/lib/helpers/withCors.ts b/lib/helpers/withCors.ts deleted file mode 100644 index e0034ae1dd..0000000000 --- a/lib/helpers/withCors.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { NextMiddleware } from "next-api-middleware"; -import NextCors from "nextjs-cors"; - -export const withCors: NextMiddleware = async (req, res, next) => { - // Run the cors middleware - // nextjs-cors uses the cors package, so we invite you to check the documentation https://github.com/expressjs/cors - await NextCors(req, res, { - // Options - methods: ["GET", "HEAD", "PUT", "PATCH", "POST", "DELETE"], - origin: "*", - optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204 - }); - - // Rest of the API logic - // Execute the remaining middleware - await next(); -}; diff --git a/lib/helpers/withCorsMiddleware.ts b/lib/helpers/withCorsMiddleware.ts deleted file mode 100644 index 14182eff99..0000000000 --- a/lib/helpers/withCorsMiddleware.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { label } from "next-api-middleware"; - -import { withCors } from "./withCors"; - -const withCorsMiddleware = label( - { - withCors, - }, - ["withCors"] // <-- Provide a list of middleware to call automatically -); - -export { withCorsMiddleware }; diff --git a/pages/api/docs.ts b/pages/api/docs.ts index 34ad0d7c5e..d9aa75d18c 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -2,8 +2,6 @@ import jsonSchema from "@/json-schema/json-schema.json"; import pjson from "@/package.json"; import { withSwagger } from "next-swagger-doc"; -import { withCorsMiddleware } from "@lib/helpers/withCorsMiddleware"; - const swaggerHandler = withSwagger({ definition: { openapi: "3.0.0", From 91eff191f6066e037fada40f84e36f2d4238c293 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 15 Apr 2022 18:13:21 +0200 Subject: [PATCH 104/658] remove next-cors --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 971c197c42..16dc0f9b9f 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,6 @@ "next-swagger-doc": "^0.2.1", "next-transpile-modules": "^9.0.0", "next-validations": "^0.1.11", - "nextjs-cors": "^2.1.1", "typescript": "^4.6.3" } } From 51cada224b7f32c0c4e36f721f0a3e7f6ac4747b Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 15 Apr 2022 18:55:47 +0200 Subject: [PATCH 105/658] fix rewrite headres --- next.config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/next.config.js b/next.config.js index fa5bc84e10..fd93748c8c 100644 --- a/next.config.js +++ b/next.config.js @@ -13,8 +13,8 @@ module.exports = withTM({ async headers() { return [ { - // matching all API routes - source: "/api/:path*", + // matching all routes, because we redirect to API in rewrites + source: "/:path*", headers: [ { key: "Access-Control-Allow-Credentials", value: "true" }, { key: "Access-Control-Allow-Origin", value: "*" }, From 3ad84a7c15ad41f026971eeac295781532219d11 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 15 Apr 2022 19:09:35 +0200 Subject: [PATCH 106/658] fix back api to rewrite --- next.config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/next.config.js b/next.config.js index fd93748c8c..fa5bc84e10 100644 --- a/next.config.js +++ b/next.config.js @@ -13,8 +13,8 @@ module.exports = withTM({ async headers() { return [ { - // matching all routes, because we redirect to API in rewrites - source: "/:path*", + // matching all API routes + source: "/api/:path*", headers: [ { key: "Access-Control-Allow-Credentials", value: "true" }, { key: "Access-Control-Allow-Origin", value: "*" }, From 5013ea2ef5d62b3e7a9856e74803cc1c88556446 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 17 Apr 2022 16:18:42 +0200 Subject: [PATCH 107/658] feat: adds apiKey auth as query params in docs and users endpoint --- pages/api/docs.ts | 7 +++++-- pages/api/users/index.ts | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/pages/api/docs.ts b/pages/api/docs.ts index d9aa75d18c..bb63cb79a3 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -9,8 +9,11 @@ const swaggerHandler = withSwagger({ title: `${pjson.name}: ${pjson.description}`, version: pjson.version, }, - components: { schemas: { ...jsonSchema.definitions } }, - definitions: jsonSchema.definitions, + components: { + securitySchemes: { ApiKeyAuth: { type: "apiKey", in: "query", name: "apiKey" } }, + schemas: { ...jsonSchema.definitions }, + }, + // definitions: jsonSchema.definitions, }, apiFolder: "pages/api", tags: ["users", "teams", "memeberships"], diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 138395adba..84c2e7ec57 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -12,6 +12,8 @@ import { schemaUserPublic } from "@lib/validations/user"; * /v1/users: * get: * summary: Get all users (admin only), returns your user if regular user. + * security: + * - ApiKeyAuth: [] * tags: * - users * responses: From 25a2a405da31f4b8bdcc7d6619fbba07874a435f Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 17 Apr 2022 16:39:38 +0200 Subject: [PATCH 108/658] feat: adds apikeyAuth in swagger ui for all endpoints --- pages/api/attendees/[id].ts | 6 ++++++ pages/api/attendees/index.ts | 4 ++++ pages/api/availabilities/[id].ts | 6 ++++++ pages/api/availabilities/index.ts | 4 ++++ pages/api/booking-references/[id].ts | 6 ++++++ pages/api/booking-references/index.ts | 4 ++++ pages/api/bookings/[id].ts | 6 ++++++ pages/api/bookings/index.ts | 4 ++++ pages/api/credentials/[id].ts | 6 ++++++ pages/api/credentials/index.ts | 4 ++++ pages/api/daily-event-references/[id].ts | 6 ++++++ pages/api/daily-event-references/index.ts | 4 ++++ pages/api/destination-calendars/[id].ts | 6 ++++++ pages/api/destination-calendars/index.ts | 4 ++++ pages/api/docs.ts | 1 - pages/api/event-type-custom-inputs/[id].ts | 6 ++++++ pages/api/event-type-custom-inputs/index.ts | 4 ++++ pages/api/event-types/[id].ts | 6 ++++++ pages/api/event-types/index.ts | 4 ++++ pages/api/memberships/[id].ts | 6 ++++++ pages/api/memberships/index.ts | 4 ++++ pages/api/payments/[id].ts | 2 ++ pages/api/payments/index.ts | 2 ++ pages/api/reminder-mails/[id].ts | 6 ++++++ pages/api/reminder-mails/index.ts | 4 ++++ pages/api/schedules/[id].ts | 6 ++++++ pages/api/schedules/index.ts | 4 ++++ pages/api/selected-calendars/[id].ts | 6 ++++++ pages/api/selected-calendars/index.ts | 4 ++++ pages/api/teams/[id].ts | 6 ++++++ pages/api/teams/index.ts | 4 ++++ pages/api/users/[id].ts | 6 ++++++ templates/endpoints/[id]/delete.ts | 2 ++ templates/endpoints/[id]/edit.ts | 2 ++ templates/endpoints/[id]/index.ts | 2 ++ templates/endpoints/get_all.ts | 2 ++ templates/endpoints/get_all_and_post.ts | 4 ++++ templates/endpoints/post.ts | 2 ++ 38 files changed, 164 insertions(+), 1 deletion(-) diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index 50b6b10cec..a7b573cc87 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -23,6 +23,8 @@ import { * type: integer * required: true * description: Numeric ID of the attendee to get + * security: + * - ApiKeyAuth: [] * tags: * - attendees * responses: @@ -50,6 +52,8 @@ import { * type: integer * required: true * description: Numeric ID of the attendee to edit + * security: + * - ApiKeyAuth: [] * tags: * - attendees * responses: @@ -69,6 +73,8 @@ import { * type: integer * required: true * description: Numeric ID of the attendee to delete + * security: + * - ApiKeyAuth: [] * tags: * - attendees * responses: diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index 5185acda2c..ed0707d636 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -12,6 +12,8 @@ import { schemaAttendeeBodyParams, schemaAttendeePublic, withValidAttendee } fro * /v1/attendees: * get: * summary: Get all attendees + * security: + * - ApiKeyAuth: [] * tags: * - attendees * responses: @@ -23,6 +25,8 @@ import { schemaAttendeeBodyParams, schemaAttendeePublic, withValidAttendee } fro * description: No attendees were found * post: * summary: Creates a new attendee + * security: + * - ApiKeyAuth: [] * tags: * - attendees * responses: diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index db660b1074..feeef587c0 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -23,6 +23,8 @@ import { * type: integer * required: true * description: Numeric ID of the availability to get + * security: + * - ApiKeyAuth: [] * tags: * - availabilities * responses: @@ -50,6 +52,8 @@ import { * type: integer * required: true * description: Numeric ID of the availability to edit + * security: + * - ApiKeyAuth: [] * tags: * - availabilities * responses: @@ -69,6 +73,8 @@ import { * type: integer * required: true * description: Numeric ID of the availability to delete + * security: + * - ApiKeyAuth: [] * tags: * - availabilities * responses: diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index 45349b6b3f..558b948d30 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -12,6 +12,8 @@ import { schemaAvailabilityBodyParams, schemaAvailabilityPublic } from "@lib/val * /v1/availabilities: * get: * summary: Get all availabilities + * security: + * - ApiKeyAuth: [] * tags: * - availabilities * responses: @@ -23,6 +25,8 @@ import { schemaAvailabilityBodyParams, schemaAvailabilityPublic } from "@lib/val * description: No availabilities were found * post: * summary: Creates a new availability + * security: + * - ApiKeyAuth: [] * tags: * - availabilities * responses: diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index c9527e3f99..3067dc3c15 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -27,6 +27,8 @@ import { * type: integer * required: true * description: Numeric ID of the daily event reference to get + * security: + * - ApiKeyAuth: [] * tags: * - booking-references * responses: @@ -54,6 +56,8 @@ import { * type: integer * required: true * description: Numeric ID of the daily event reference to edit + * security: + * - ApiKeyAuth: [] * tags: * - booking-references * responses: @@ -73,6 +77,8 @@ import { * type: integer * required: true * description: Numeric ID of the daily event reference to delete + * security: + * - ApiKeyAuth: [] * tags: * - booking-references * responses: diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index 4fba496dd3..d256936ce5 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -15,6 +15,8 @@ import { * /v1/booking-references: * get: * summary: Get all booking references + * security: + * - ApiKeyAuth: [] * tags: * - booking-references * responses: @@ -26,6 +28,8 @@ import { * description: No booking references were found * post: * summary: Creates a new booking reference + * security: + * - ApiKeyAuth: [] * tags: * - booking-references * responses: diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index 54e21b5109..e3e56b9a36 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -23,6 +23,8 @@ import { * type: integer * required: true * description: Numeric ID of the booking to get + * security: + * - ApiKeyAuth: [] * tags: * - bookings * responses: @@ -50,6 +52,8 @@ import { * type: integer * required: true * description: Numeric ID of the booking to edit + * security: + * - ApiKeyAuth: [] * tags: * - bookings * responses: @@ -69,6 +73,8 @@ import { * type: integer * required: true * description: Numeric ID of the booking to delete + * security: + * - ApiKeyAuth: [] * tags: * - bookings * responses: diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 2b2b55bf21..c3d11a91e0 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -12,6 +12,8 @@ import { schemaBookingBodyParams, schemaBookingPublic, withValidBooking } from " * /v1/bookings: * get: * summary: Get all bookings + * security: + * - ApiKeyAuth: [] * tags: * - bookings * responses: @@ -23,6 +25,8 @@ import { schemaBookingBodyParams, schemaBookingPublic, withValidBooking } from " * description: No bookings were found * post: * summary: Creates a new booking + * security: + * - ApiKeyAuth: [] * tags: * - bookings * responses: diff --git a/pages/api/credentials/[id].ts b/pages/api/credentials/[id].ts index 52c95fd023..279ad3c2b4 100644 --- a/pages/api/credentials/[id].ts +++ b/pages/api/credentials/[id].ts @@ -23,6 +23,8 @@ import { * type: integer * required: true * description: Numeric ID of the credential to get + * security: + * - ApiKeyAuth: [] * tags: * - credentials * responses: @@ -50,6 +52,8 @@ import { * type: integer * required: true * description: Numeric ID of the credential to edit + * security: + * - ApiKeyAuth: [] * tags: * - credentials * responses: @@ -69,6 +73,8 @@ import { * type: integer * required: true * description: Numeric ID of the credential to delete + * security: + * - ApiKeyAuth: [] * tags: * - credentials * responses: diff --git a/pages/api/credentials/index.ts b/pages/api/credentials/index.ts index d7b9ed651f..5e94ee17cd 100644 --- a/pages/api/credentials/index.ts +++ b/pages/api/credentials/index.ts @@ -12,6 +12,8 @@ import { schemaCredentialBodyParams, schemaCredentialPublic } from "@lib/validat * /api/credentials: * get: * summary: Get all credentials + * security: + * - ApiKeyAuth: [] * tags: * - credentials * responses: @@ -23,6 +25,8 @@ import { schemaCredentialBodyParams, schemaCredentialPublic } from "@lib/validat * description: No credentials were found * post: * summary: Creates a new credential + * security: + * - ApiKeyAuth: [] * tags: * - credentials * responses: diff --git a/pages/api/daily-event-references/[id].ts b/pages/api/daily-event-references/[id].ts index 482aab6ec1..17d6ced278 100644 --- a/pages/api/daily-event-references/[id].ts +++ b/pages/api/daily-event-references/[id].ts @@ -25,6 +25,8 @@ import { * type: integer * required: true * description: Numeric ID of the daily event reference to get + * security: + * - ApiKeyAuth: [] * tags: * - daily-event-references * responses: @@ -52,6 +54,8 @@ import { * type: integer * required: true * description: Numeric ID of the daily event reference to edit + * security: + * - ApiKeyAuth: [] * tags: * - daily-event-references * responses: @@ -71,6 +75,8 @@ import { * type: integer * required: true * description: Numeric ID of the daily event reference to delete + * security: + * - ApiKeyAuth: [] * tags: * - daily-event-references * responses: diff --git a/pages/api/daily-event-references/index.ts b/pages/api/daily-event-references/index.ts index 1a1762157d..aa60482bb1 100644 --- a/pages/api/daily-event-references/index.ts +++ b/pages/api/daily-event-references/index.ts @@ -14,6 +14,8 @@ import { * /v1/daily-event-references: * get: * summary: Get all daily event reference + * security: + * - ApiKeyAuth: [] * tags: * - daily-event-reference * responses: @@ -25,6 +27,8 @@ import { * description: No daily event references were found * post: * summary: Creates a new daily event reference + * security: + * - ApiKeyAuth: [] * tags: * - daily-event-reference * responses: diff --git a/pages/api/destination-calendars/[id].ts b/pages/api/destination-calendars/[id].ts index a72bcecba1..ef7712e525 100644 --- a/pages/api/destination-calendars/[id].ts +++ b/pages/api/destination-calendars/[id].ts @@ -25,6 +25,8 @@ import { * type: integer * required: true * description: Numeric ID of the destination calendar to get + * security: + * - ApiKeyAuth: [] * tags: * - destination-calendars * responses: @@ -52,6 +54,8 @@ import { * type: integer * required: true * description: Numeric ID of the destination calendar to edit + * security: + * - ApiKeyAuth: [] * tags: * - destination-calendars * responses: @@ -71,6 +75,8 @@ import { * type: integer * required: true * description: Numeric ID of the destination calendar to delete + * security: + * - ApiKeyAuth: [] * tags: * - destination-calendars * responses: diff --git a/pages/api/destination-calendars/index.ts b/pages/api/destination-calendars/index.ts index 3557272970..3980b3e203 100644 --- a/pages/api/destination-calendars/index.ts +++ b/pages/api/destination-calendars/index.ts @@ -14,6 +14,8 @@ import { * /v1/destination-calendars: * get: * summary: Get all destination calendars + * security: + * - ApiKeyAuth: [] * tags: * - destination-calendars * responses: @@ -25,6 +27,8 @@ import { * description: No destination calendars were found * post: * summary: Creates a new destination calendar + * security: + * - ApiKeyAuth: [] * tags: * - destination-calendars * responses: diff --git a/pages/api/docs.ts b/pages/api/docs.ts index bb63cb79a3..3c9f50cfed 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -13,7 +13,6 @@ const swaggerHandler = withSwagger({ securitySchemes: { ApiKeyAuth: { type: "apiKey", in: "query", name: "apiKey" } }, schemas: { ...jsonSchema.definitions }, }, - // definitions: jsonSchema.definitions, }, apiFolder: "pages/api", tags: ["users", "teams", "memeberships"], diff --git a/pages/api/event-type-custom-inputs/[id].ts b/pages/api/event-type-custom-inputs/[id].ts index 62b61d9c92..d9dd21d112 100644 --- a/pages/api/event-type-custom-inputs/[id].ts +++ b/pages/api/event-type-custom-inputs/[id].ts @@ -25,6 +25,8 @@ import { * type: integer * required: true * description: Numeric ID of the eventTypeCustomInput to get + * security: + * - ApiKeyAuth: [] * tags: * - event-type-custom-inputs * responses: @@ -52,6 +54,8 @@ import { * type: integer * required: true * description: Numeric ID of the eventTypeCustomInput to edit + * security: + * - ApiKeyAuth: [] * tags: * - event-type-custom-inputs * responses: @@ -71,6 +75,8 @@ import { * type: integer * required: true * description: Numeric ID of the eventTypeCustomInput to delete + * security: + * - ApiKeyAuth: [] * tags: * - event-type-custom-inputs * responses: diff --git a/pages/api/event-type-custom-inputs/index.ts b/pages/api/event-type-custom-inputs/index.ts index f988adc281..806d3ca91e 100644 --- a/pages/api/event-type-custom-inputs/index.ts +++ b/pages/api/event-type-custom-inputs/index.ts @@ -14,6 +14,8 @@ import { * /v1/event-type-custom-inputs: * get: * summary: Get all eventTypeCustomInputs + * security: + * - ApiKeyAuth: [] * tags: * - event-type-custom-inputs * responses: @@ -25,6 +27,8 @@ import { * description: No eventTypeCustomInputs were found * post: * summary: Creates a new eventTypeCustomInput + * security: + * - ApiKeyAuth: [] * tags: * - event-type-custom-inputs * responses: diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index e3ffe87f9b..410cbbb5af 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -22,6 +22,8 @@ import { * type: integer * required: true * description: Numeric ID of the eventType to get + * security: + * - ApiKeyAuth: [] * tags: * - event-types * responses: @@ -49,6 +51,8 @@ import { * type: integer * required: true * description: Numeric ID of the eventType to edit + * security: + * - ApiKeyAuth: [] * tags: * - event-types * responses: @@ -68,6 +72,8 @@ import { * type: integer * required: true * description: Numeric ID of the eventType to delete + * security: + * - ApiKeyAuth: [] * tags: * - event-types * responses: diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 724f0e9769..7f04a6a3de 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -11,6 +11,8 @@ import { schemaEventTypeBodyParams, schemaEventTypePublic } from "@lib/validatio * /v1/event-types: * get: * summary: Get all event types + * security: + * - ApiKeyAuth: [] * tags: * - event-types * responses: @@ -22,6 +24,8 @@ import { schemaEventTypeBodyParams, schemaEventTypePublic } from "@lib/validatio * description: No event types were found * post: * summary: Creates a new event type + * security: + * - ApiKeyAuth: [] * tags: * - event-types * responses: diff --git a/pages/api/memberships/[id].ts b/pages/api/memberships/[id].ts index a963c023f5..2fbb14bcdb 100644 --- a/pages/api/memberships/[id].ts +++ b/pages/api/memberships/[id].ts @@ -25,6 +25,8 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * type: integer * required: true * description: Numeric teamId of the membership to get + * security: + * - ApiKeyAuth: [] * tags: * - memberships * responses: @@ -58,6 +60,8 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * type: integer * required: true * description: Numeric teamId of the membership to get + * security: + * - ApiKeyAuth: [] * tags: * - memberships * responses: @@ -83,6 +87,8 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * type: integer * required: true * description: Numeric teamId of the membership to get + * security: + * - ApiKeyAuth: [] * tags: * - memberships * responses: diff --git a/pages/api/memberships/index.ts b/pages/api/memberships/index.ts index 54b6e70c16..85c2ddced1 100644 --- a/pages/api/memberships/index.ts +++ b/pages/api/memberships/index.ts @@ -11,6 +11,8 @@ import { schemaMembershipBodyParams, schemaMembershipPublic } from "@lib/validat * /v1/memberships: * get: * summary: Get all memberships + * security: + * - ApiKeyAuth: [] * tags: * - memberships * responses: @@ -22,6 +24,8 @@ import { schemaMembershipBodyParams, schemaMembershipPublic } from "@lib/validat * description: No memberships were found * post: * summary: Creates a new membership + * security: + * - ApiKeyAuth: [] * tags: * - memberships * responses: diff --git a/pages/api/payments/[id].ts b/pages/api/payments/[id].ts index cdedf473ec..f196b4cac0 100644 --- a/pages/api/payments/[id].ts +++ b/pages/api/payments/[id].ts @@ -23,6 +23,8 @@ import { * type: integer * required: true * description: Numeric ID of the payment to get + * security: + * - ApiKeyAuth: [] * tags: * - payments * responses: diff --git a/pages/api/payments/index.ts b/pages/api/payments/index.ts index 955cff0725..20028df180 100644 --- a/pages/api/payments/index.ts +++ b/pages/api/payments/index.ts @@ -12,6 +12,8 @@ import { schemaPaymentPublic } from "@lib/validations/payment"; * /v1/payments: * get: * summary: Get all payments + * security: + * - ApiKeyAuth: [] * tags: * - payments * responses: diff --git a/pages/api/reminder-mails/[id].ts b/pages/api/reminder-mails/[id].ts index 10c5dd41e6..e6627ef7b9 100644 --- a/pages/api/reminder-mails/[id].ts +++ b/pages/api/reminder-mails/[id].ts @@ -22,6 +22,8 @@ import { * type: integer * required: true * description: Numeric ID of the reminderMail to get + * security: + * - ApiKeyAuth: [] * tags: * - reminder-mails * responses: @@ -49,6 +51,8 @@ import { * type: integer * required: true * description: Numeric ID of the reminderMail to edit + * security: + * - ApiKeyAuth: [] * tags: * - reminder-mails * responses: @@ -68,6 +72,8 @@ import { * type: integer * required: true * description: Numeric ID of the reminderMail to delete + * security: + * - ApiKeyAuth: [] * tags: * - reminder-mails * responses: diff --git a/pages/api/reminder-mails/index.ts b/pages/api/reminder-mails/index.ts index 2c743c0474..22c4f63dab 100644 --- a/pages/api/reminder-mails/index.ts +++ b/pages/api/reminder-mails/index.ts @@ -15,6 +15,8 @@ import { * /v1/reminder-mails: * get: * summary: Get all reminder mails + * security: + * - ApiKeyAuth: [] * tags: * - reminder-mails * responses: @@ -26,6 +28,8 @@ import { * description: No reminder mails were found * post: * summary: Creates a new reminder mail + * security: + * - ApiKeyAuth: [] * tags: * - reminder-mails * responses: diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index c75034e5d1..eb87d13949 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -22,6 +22,8 @@ import { * type: integer * required: true * description: Numeric ID of the schedule to get + * security: + * - ApiKeyAuth: [] * tags: * - schedules * responses: @@ -49,6 +51,8 @@ import { * type: integer * required: true * description: Numeric ID of the schedule to edit + * security: + * - ApiKeyAuth: [] * tags: * - schedules * responses: @@ -68,6 +72,8 @@ import { * type: integer * required: true * description: Numeric ID of the schedule to delete + * security: + * - ApiKeyAuth: [] * tags: * - schedules * responses: diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index f8eedf599f..3f5761e30d 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -11,6 +11,8 @@ import { schemaScheduleBodyParams, schemaSchedulePublic, withValidSchedule } fro * /v1/schedules: * get: * summary: Get all schedules + * security: + * - ApiKeyAuth: [] * tags: * - schedules * responses: @@ -22,6 +24,8 @@ import { schemaScheduleBodyParams, schemaSchedulePublic, withValidSchedule } fro * description: No schedules were found * post: * summary: Creates a new schedule + * security: + * - ApiKeyAuth: [] * tags: * - schedules * responses: diff --git a/pages/api/selected-calendars/[id].ts b/pages/api/selected-calendars/[id].ts index b66fc5a888..219d51dc4c 100644 --- a/pages/api/selected-calendars/[id].ts +++ b/pages/api/selected-calendars/[id].ts @@ -34,6 +34,8 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * type: string * required: true * description: integration of the selected calendar to get + * security: + * - ApiKeyAuth: [] * tags: * - selected-calendars * responses: @@ -73,6 +75,8 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * type: string * required: true * description: integration of the selected calendar to get + * security: + * - ApiKeyAuth: [] * tags: * - selected-calendars * responses: @@ -104,6 +108,8 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * type: string * required: true * description: integration of the selected calendar to get + * security: + * - ApiKeyAuth: [] * tags: * - selected-calendars * responses: diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index a6a8a39c16..15daead8a2 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -15,6 +15,8 @@ import { * /v1/selected-calendars: * get: * summary: Get all selected calendars + * security: + * - ApiKeyAuth: [] * tags: * - selected-calendars * responses: @@ -26,6 +28,8 @@ import { * description: No selected calendars were found * post: * summary: Creates a new selected calendar + * security: + * - ApiKeyAuth: [] * tags: * - selected-calendars * responses: diff --git a/pages/api/teams/[id].ts b/pages/api/teams/[id].ts index 70f88c1b35..07da2e2870 100644 --- a/pages/api/teams/[id].ts +++ b/pages/api/teams/[id].ts @@ -23,6 +23,8 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * type: integer * required: true * description: Numeric ID of the team to get + * security: + * - ApiKeyAuth: [] * tags: * - teams * responses: @@ -50,6 +52,8 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * type: integer * required: true * description: Numeric ID of the team to edit + * security: + * - ApiKeyAuth: [] * tags: * - teams * responses: @@ -69,6 +73,8 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * type: integer * required: true * description: Numeric ID of the team to delete + * security: + * - ApiKeyAuth: [] * tags: * - teams * responses: diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index 8007e2fea0..d1c24bf8b8 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -12,6 +12,8 @@ import { schemaTeamBodyParams, schemaTeamPublic, withValidTeam } from "@lib/vali * /v1/teams: * get: * summary: Get all teams + * security: + * - ApiKeyAuth: [] * tags: * - teams * responses: @@ -23,6 +25,8 @@ import { schemaTeamBodyParams, schemaTeamPublic, withValidTeam } from "@lib/vali * description: No teams were found * post: * summary: Creates a new team + * security: + * - ApiKeyAuth: [] * tags: * - teams * responses: diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index a5c55095e5..5beaf442df 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -23,6 +23,8 @@ import { schemaUserBodyParams, schemaUserPublic } from "@lib/validations/user"; * type: integer * required: true * description: Numeric ID of the user to get + * security: + * - ApiKeyAuth: [] * tags: * - users * responses: @@ -50,6 +52,8 @@ import { schemaUserBodyParams, schemaUserPublic } from "@lib/validations/user"; * type: integer * required: true * description: Numeric ID of the user to edit + * security: + * - ApiKeyAuth: [] * tags: * - users * responses: @@ -69,6 +73,8 @@ import { schemaUserBodyParams, schemaUserPublic } from "@lib/validations/user"; * type: integer * required: true * description: Numeric ID of the user to delete + * security: + * - ApiKeyAuth: [] * tags: * - users * responses: diff --git a/templates/endpoints/[id]/delete.ts b/templates/endpoints/[id]/delete.ts index 2b59baee90..5cf646aee0 100644 --- a/templates/endpoints/[id]/delete.ts +++ b/templates/endpoints/[id]/delete.ts @@ -21,6 +21,8 @@ import { * type: integer * required: true * description: Numeric ID of the resource to delete + * security: + * - ApiKeyAuth: [] * tags: * - resources * responses: diff --git a/templates/endpoints/[id]/edit.ts b/templates/endpoints/[id]/edit.ts index 0e73604fb4..54b8fec540 100644 --- a/templates/endpoints/[id]/edit.ts +++ b/templates/endpoints/[id]/edit.ts @@ -22,6 +22,8 @@ import { * type: integer * required: true * description: Numeric ID of the resource to edit + * security: + * - ApiKeyAuth: [] * tags: * - resources * responses: diff --git a/templates/endpoints/[id]/index.ts b/templates/endpoints/[id]/index.ts index 31393a7a6a..66e7ab105c 100644 --- a/templates/endpoints/[id]/index.ts +++ b/templates/endpoints/[id]/index.ts @@ -22,6 +22,8 @@ import { * type: integer * required: true * description: Numeric ID of the resource to get + * security: + * - ApiKeyAuth: [] * tags: * - resources * responses: diff --git a/templates/endpoints/get_all.ts b/templates/endpoints/get_all.ts index 490381501e..b3b9257e9a 100644 --- a/templates/endpoints/get_all.ts +++ b/templates/endpoints/get_all.ts @@ -11,6 +11,8 @@ import { schemaResourcePublic } from "@lib/validations/resource"; * /v1/resources: * get: * summary: Get all resources + * security: + * - ApiKeyAuth: [] * tags: * - resources * responses: diff --git a/templates/endpoints/get_all_and_post.ts b/templates/endpoints/get_all_and_post.ts index 25115ff859..bf6fee016f 100644 --- a/templates/endpoints/get_all_and_post.ts +++ b/templates/endpoints/get_all_and_post.ts @@ -11,6 +11,8 @@ import { schemaPaymentBodyParams, schemaPaymentPublic } from "@lib/validations/p * /v1/payments: * get: * summary: Get all payments + * security: + * - ApiKeyAuth: [] * tags: * - payments * responses: @@ -22,6 +24,8 @@ import { schemaPaymentBodyParams, schemaPaymentPublic } from "@lib/validations/p * description: No payments were found * post: * summary: Creates a new payment + * security: + * - ApiKeyAuth: [] * tags: * - payments * responses: diff --git a/templates/endpoints/post.ts b/templates/endpoints/post.ts index af0644a7a8..e2b9e17683 100644 --- a/templates/endpoints/post.ts +++ b/templates/endpoints/post.ts @@ -18,6 +18,8 @@ import { schemaResourceBodyParams, schemaResourcePublic, withValidResource } fro * application/json: * schema: * $ref: '#/components/schemas/Resource' + * security: + * - ApiKeyAuth: [] * tags: * - resources * responses: From 8965601e6f1c907fd3206c04f30a3f7cd4639d32 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 18 Apr 2022 23:24:57 +0200 Subject: [PATCH 109/658] fix verifyapikey, add daabase_url to env.example --- .env.example | 3 ++- lib/helpers/verifyApiKey.ts | 38 ++++++++++++++++++------------------- 2 files changed, 21 insertions(+), 20 deletions(-) diff --git a/.env.example b/.env.example index f3271e560c..1c0f6152c1 100644 --- a/.env.example +++ b/.env.example @@ -1 +1,2 @@ -API_KEY_PREFIX=cal_ \ No newline at end of file +API_KEY_PREFIX=cal_ +DATABASE_URL="postgresql://postgres:@localhost:5450/calendso" diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 6fe33c6ad3..008f3dc4f4 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -4,31 +4,31 @@ import { hashAPIKey } from "@calcom/ee/lib/api/apiKeys"; import prisma from "@calcom/prisma"; // Used to check if the API key is not expired, could be extracted if reused. but not for now. -export const dateInPast = function (firstDate: Date, secondDate: Date) { - if (firstDate.setHours(0, 0, 0, 0) <= secondDate.setHours(0, 0, 0, 0)) { +export const dateInPast = function (date: Date) { + const now = new Date(); + if (now.setHours(0, 0, 0, 0) <= date.setHours(0, 0, 0, 0)) { return true; } }; -const today = new Date(); // This verifies the API key and sets the user if it is valid. export const verifyApiKey: NextMiddleware = async (req, res, next) => { - if (!req.query.apiKey) res.status(401).json({ message: "No API key provided" }); - + if (!req.query.apiKey) res.status(401).json({ message: "No api key provided" }); + // We remove the prefix from the user provided api_key. If no env set default to "cal_" const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "cal_", ""); + // Hash the key again before matching against the database records. const hashedKey = hashAPIKey(strippedApiKey); - - await prisma.apiKey - .findUnique({ where: { hashedKey } }) - .then(async (apiKey) => { - if (!apiKey) { - res.status(401).json({ error: "You did not provide an api key" }); - throw new Error("No api key found"); - } - if (apiKey.userId) res.setHeader("X-Calcom-User-ID", apiKey.userId); - if (apiKey.expiresAt && apiKey.userId && dateInPast(today, apiKey.expiresAt)) await next(); - }) - .catch((error) => { - res.status(401).json({ error: "Your api key is not valid" }); - }); + // Check if the hashed api key exists in database. + await prisma.apiKey.findUnique({ where: { hashedKey } }).then(async (apiKey) => { + // If we cannot find any api key. Throw a 401 Unauthorized. + if (!apiKey) res.status(401).json({ error: "Your api key is not valid" }); + if (apiKey && apiKey.expiresAt && dateInPast(apiKey.expiresAt) && apiKey.userId) { + // Right now API Keys are user centric, we only allow resources related to this userId throughout the application. + // if the api key is not expired, and the user id is present in the database. + // Set the user in the request. as x-calcom-user-id. + res.setHeader("X-Calcom-User-ID", apiKey.userId); + // Pass the request to the next middleware. + await next(); + } + }); }; From b4f3b8cc5536786f47263a2afdab27cc68061b9d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 18 Apr 2022 23:40:28 +0200 Subject: [PATCH 110/658] removes credentials endpoint --- pages/api/credentials/[id].ts | 142 --------------------------------- pages/api/credentials/index.ts | 78 ------------------ 2 files changed, 220 deletions(-) delete mode 100644 pages/api/credentials/[id].ts delete mode 100644 pages/api/credentials/index.ts diff --git a/pages/api/credentials/[id].ts b/pages/api/credentials/[id].ts deleted file mode 100644 index 279ad3c2b4..0000000000 --- a/pages/api/credentials/[id].ts +++ /dev/null @@ -1,142 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { CredentialResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; -import { schemaCredentialBodyParams, schemaCredentialPublic } from "@lib/validations/credential"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /v1/credentials/{id}: - * get: - * summary: Get a credential by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the credential to get - * security: - * - ApiKeyAuth: [] - * tags: - * - credentials - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Credential was not found - * patch: - * summary: Edit an existing credential - * consumes: - * - application/json - * parameters: - * - in: body - * name: credential - * description: The credential to edit - * schema: - * type: object - * $ref: '#/components/schemas/Credential' - * required: true - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the credential to edit - * security: - * - ApiKeyAuth: [] - * tags: - * - credentials - * responses: - * 201: - * description: OK, credential edited successfuly - * model: Credential - * 400: - * description: Bad request. Credential body is invalid. - * 401: - * description: Authorization information is missing or invalid. - * delete: - * summary: Remove an existing credential - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the credential to delete - * security: - * - ApiKeyAuth: [] - * tags: - * - credentials - * responses: - * 201: - * description: OK, credential removed successfuly - * model: Credential - * 400: - * description: Bad request. Credential id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function credentialById(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body } = req; - const safeQuery = schemaQueryIdParseInt.safeParse(query); - const safeBody = schemaCredentialBodyParams.safeParse(body); - if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = getCalcomUserId(res); - const data = await prisma.credential.findMany({ where: { userId } }); - const credentialIds = data.map((credential) => credential.id); - // res.status(200).json({ data }); - if (credentialIds.includes(safeQuery.data.id)) { - switch (method) { - case "GET": - await prisma.credential - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaCredentialPublic.parse(data)) - .then((credential) => res.status(200).json({ credential })) - .catch((error: Error) => - res.status(404).json({ message: `Credential with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - case "PATCH": - if (!safeBody.success) throw new Error("Invalid request body"); - await prisma.credential - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((data) => schemaCredentialPublic.parse(data)) - .then((credential) => res.status(200).json({ credential })) - .catch((error: Error) => - res.status(404).json({ message: `Credential with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - case "DELETE": - await prisma.credential - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ message: `Credential with id: ${safeQuery.data.id} deleted successfully` }) - ) - .catch((error: Error) => - res.status(404).json({ message: `Credential with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } - } else res.status(401).json({ message: "Unauthorized" }); -} - -export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(credentialById)); diff --git a/pages/api/credentials/index.ts b/pages/api/credentials/index.ts deleted file mode 100644 index 5e94ee17cd..0000000000 --- a/pages/api/credentials/index.ts +++ /dev/null @@ -1,78 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { CredentialResponse, CredentialsResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; -import { schemaCredentialBodyParams, schemaCredentialPublic } from "@lib/validations/credential"; - -/** - * @swagger - * /api/credentials: - * get: - * summary: Get all credentials - * security: - * - ApiKeyAuth: [] - * tags: - * - credentials - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No credentials were found - * post: - * summary: Creates a new credential - * security: - * - ApiKeyAuth: [] - * tags: - * - credentials - * responses: - * 201: - * description: OK, credential created - * model: Credential - * 400: - * description: Bad request. Credential body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createOrlistAllCredentials( - req: NextApiRequest, - res: NextApiResponse -) { - const { method } = req; - const userId = getCalcomUserId(res); - - if (method === "GET") { - const data = await prisma.credential.findMany({ where: { userId } }); - const credentials = data.map((credential) => schemaCredentialPublic.parse(credential)); - if (credentials) res.status(200).json({ credentials }); - else - (error: Error) => - res.status(404).json({ - message: "No Credentials were found", - error, - }); - } else if (method === "POST") { - const safe = schemaCredentialBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body"); - - const data = await prisma.credential.create({ data: safe.data }); - const credential = schemaCredentialPublic.parse(data); - - if (credential) - res - .status(201) - .json({ credential: { ...credential, userId }, message: "Credential created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new credential", - error, - }); - } else res.status(405).json({ message: `Method ${method} not allowed` }); -} - -export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllCredentials); From 29666493d6f616fea37cf1be30cc9de4d63fc199 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 19 Apr 2022 05:19:59 +0200 Subject: [PATCH 111/658] make event types return only userId data --- lib/validations/event-type.ts | 4 +- pages/api/event-types/[id].ts | 94 +++++++++++++++++++++------------- pages/api/event-types/index.ts | 11 +++- 3 files changed, 70 insertions(+), 39 deletions(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 113620157e..ab24a9b0d1 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -12,8 +12,8 @@ const schemaEventTypeRequiredParams = z.object({ }); export const schemaEventTypeBodyParams = schemaEventTypeBaseBodyParams.merge(schemaEventTypeRequiredParams); - -export const schemaEventTypePublic = EventType.omit({}); +// Omitting those two (locations/ metadata) because the validations where choking at array and JSON object. add them later if needed +export const schemaEventTypePublic = EventType.omit({ locations: true, metadata: true }); export const withValidEventType = withValidation({ schema: schemaEventTypeBodyParams, diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 410cbbb5af..91ba0e380a 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { EventTypeResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaEventTypeBodyParams, schemaEventTypePublic } from "@lib/validations/event-type"; import { schemaQueryIdParseInt, @@ -26,6 +27,8 @@ import { * - ApiKeyAuth: [] * tags: * - event-types + * externalDocs: + * url: https://docs.cal.com/event-types * responses: * 200: * description: OK @@ -55,6 +58,8 @@ import { * - ApiKeyAuth: [] * tags: * - event-types + * externalDocs: + * url: https://docs.cal.com/event-types * responses: * 201: * description: OK, eventType edited successfuly @@ -76,6 +81,8 @@ import { * - ApiKeyAuth: [] * tags: * - event-types + * externalDocs: + * url: https://docs.cal.com/event-types * responses: * 201: * description: OK, eventType removed successfuly @@ -90,44 +97,61 @@ export async function eventTypeById(req: NextApiRequest, res: NextApiResponse eventType.id); + if (userEventTypes.includes(safeQuery.data.id)) { + switch (method) { + case "GET": + await prisma.eventType + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data) => schemaEventTypePublic.parse(data)) + .then((event_type) => res.status(200).json({ event_type })) + .catch((error: Error) => + res.status(404).json({ + message: `EventType with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - switch (method) { - case "GET": - await prisma.eventType - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaEventTypePublic.parse(data)) - .then((event_type) => res.status(200).json({ event_type })) - .catch((error: Error) => - res.status(404).json({ message: `EventType with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "PATCH": + if (!safeBody.success) { + throw new Error("Invalid request body"); + } + await prisma.eventType + .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) + .then((data) => schemaEventTypePublic.parse(data)) + .then((event_type) => res.status(200).json({ event_type })) + .catch((error: Error) => + res.status(404).json({ + message: `EventType with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - case "PATCH": - if (!safeBody.success) throw new Error("Invalid request body"); - await prisma.eventType - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((data) => schemaEventTypePublic.parse(data)) - .then((event_type) => res.status(200).json({ event_type })) - .catch((error: Error) => - res.status(404).json({ message: `EventType with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "DELETE": + await prisma.eventType + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ + message: `EventType with id: ${safeQuery.data.id} deleted`, + }) + ) + .catch((error: Error) => + res.status(404).json({ + message: `EventType with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - case "DELETE": - await prisma.eventType - .delete({ where: { id: safeQuery.data.id } }) - .then(() => res.status(200).json({ message: `EventType with id: ${safeQuery.data.id} deleted` })) - .catch((error: Error) => - res.status(404).json({ message: `EventType with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } } } diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 7f04a6a3de..cd883d719c 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { EventTypeResponse, EventTypesResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaEventTypeBodyParams, schemaEventTypePublic } from "@lib/validations/event-type"; /** @@ -15,6 +16,8 @@ import { schemaEventTypeBodyParams, schemaEventTypePublic } from "@lib/validatio * - ApiKeyAuth: [] * tags: * - event-types + * externalDocs: + * url: https://docs.cal.com/event-types * responses: * 200: * description: OK @@ -28,6 +31,8 @@ import { schemaEventTypeBodyParams, schemaEventTypePublic } from "@lib/validatio * - ApiKeyAuth: [] * tags: * - event-types + * externalDocs: + * url: https://docs.cal.com/event-types * responses: * 201: * description: OK, event type created @@ -42,8 +47,10 @@ async function createOrlistAllEventTypes( res: NextApiResponse ) { const { method } = req; + const userId = await getCalcomUserId(res); + if (method === "GET") { - const data = await prisma.eventType.findMany(); + const data = await prisma.eventType.findMany({ where: { userId } }); const event_types = data.map((eventType) => schemaEventTypePublic.parse(eventType)); if (event_types) res.status(200).json({ event_types }); else @@ -56,7 +63,7 @@ async function createOrlistAllEventTypes( const safe = schemaEventTypeBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body"); - const data = await prisma.eventType.create({ data: safe.data }); + const data = await prisma.eventType.create({ data: { ...safe.data, userId } }); const event_type = schemaEventTypePublic.parse(data); if (data) res.status(201).json({ event_type, message: "EventType created successfully" }); From 7734e86f6b62e6cc511aac5f290407879b91280f Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 19 Apr 2022 13:44:24 +0200 Subject: [PATCH 112/658] improve readme. fix event-types --- README.md | 109 ++++++++++++++++++---- lib/helpers/verifyApiKey.ts | 3 +- pages/api/availabilities/[id].ts | 6 ++ pages/api/availabilities/index.ts | 4 + pages/api/daily-event-references/index.ts | 4 +- 5 files changed, 106 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 81e06fa2ae..a79bb64f37 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,58 @@ # Cal.com Public API (Enterprise Only) -## This will be the new public enterprise-only API +This is the public REST api for cal.com. It exposes CRUD Endpoints of all our most important resources. It makes it easy for anyone to integrate with cal at the programming level. -This is the public REST api for cal.com +> The priority is the booking-related API routes so people can build their own booking flow, then event type management routes, then availability management routes etc -## NextJS + TypeScript +## Stack -It's a barebones **NextJS** + **TypeScript** project leveraging the nextJS API with a pages/api folder. +- NextJS +- TypeScript +- Prisma +- No tRPC (for now) We hook directly into prisma client, but probably should look into adding a new @calcom/trpc package that adds pagination and such stuff and can be shared between webapp and API. -- `api.cal.com/v1` -- `api.cal.com/api/v1` +## API Authentication (API Keys) + +The API requires a valid apiKey query param to be passed: +You can generate them at + +For example: +```sh +GET https://api.cal.com/v1/users?apiKey={INSERT_YOUR_CAL.COM_API_KEY_HERE} +``` + +API Keys optionally may have expiry dates, if they are expired they won't work. If you create an apiKey without a userId relation, it won't work either for now as it relies on it to establish the current authenticated user. + +In the future we might add support for header Beaer Auth if we need to or our customers require it. + +## Redirects + +Since this is an API only project, we don't want to have to type /api/ in all the routes, and so redirect all traffic to api, so a call to `api.cal.com/v1` will resolve to `api.cal.com/api/v1` + +Likewise, v1 is added as param query called version to final /api call so we don't duplicate endpoints in the future for versioning if needed. ## API Endpoint Validation -### Zod +We validate that only the supported methods are accepted at each endpoint, so in -The API uses `zod` library like our main web repo. It validates that either GET query parameters or POST body content's are valid and up to our spec. It gives appropiate errors when parsing result's with schemas. +- **/endpoint**: you can only [GET] (all) and [POST] (create new) +- **/endpoint/id**: you can read create and edit [GET, PATCH, DELETE] + +### Zod Validations + +The API uses `zod` library like our main web repo. It validates that either GET query parameters or POST body content's are valid and up to our spec. It gives errors when parsing result's with schemas and failing validation. + +We use it in several ways, but mainly, we first import the auto-generated schema from @calcom/prisma for each model, which lives in `lib/validations/` + +We have some shared validations which several resources require, like baseApiParams which parses apiKey in all requests, or querIdAsString or TransformParseInt which deal with the id's coming from req.query. + +- **[*]BaseBodyParams** that omits any values from the model that are too sensitive or we don't want to pick when creating a new resource like id, userId, etc.. (those are gotten from context or elswhere) + +- **[*]Public** that also omits any values that we don't want to expose when returning the model as a response, which we parse against before returning all resources. + +- **[*]BodyParams** which merges both `[*]BaseBodyParams.merge([*]RequiredParams);` + +- **withValid[*]** which is currently not being much used because is only useful in only post endpoints (we do post/get all in same file). This would validate the req.body of a POST call to API against our BaseBodyParams validation ### Next Validations @@ -29,14 +66,7 @@ We aim to provide a fully tested API for our peace of mind, this is accomplished ## Next.config.js -### Redirects - -Since this will only support an API, we redirect the requests to root to the /api folder. -We also added a redirect for future-proofing API versioning when we might need it, without having to resort to dirty hacks like a v1/v2 folders with lots of duplicated code, instead we redirect /api/v*/:rest to /api/:rest?version=* - -The priority is the booking-related API routes so people can build their own booking flow, then event type management routes, then availability management routes etc - -How to add a new model or endpoint +### How to add a new model or endpoint Basically there's three places of the codebase you need to think about for each feature. @@ -44,7 +74,7 @@ Basically there's three places of the codebase you need to think about for each - This is the most important one, and where your endpoint will live. You will leverage nextjs dynamic routes and expose one file for each endpoint you want to support ideally. -## How the codebase is organized. +## How the codebase is organized ## The example resource -model- and it's endpoints @@ -77,3 +107,48 @@ tests/endpoint/resource.new.test.ts - Create new resource ## `/lib/validations/yourEndpoint.ts` - This is where our model validations, live, we try to make a 1:1 for db models, and also extract out any re-usable code into the /lib/validations/shared/ sub-folder. + +## Endpoints matrix + +| resource | get [id] | get all | create | edit | delete | +|--------------------------|----------|----------|---------|-------|--------| +| attendees | ✅ | ✅ | ✅ | ✅ | ✅ | +| availabilities | ✅ | ✅ | ✅ | ✅ | ✅ | +| booking-references | ✅ | ✅ | ✅ | ✅ | ✅ | +| daily-event-references | ✅ | ✅ | ✅ | ✅ | ✅ | +| destination-calendars | ✅ | ✅ | ✅ | ✅ | ✅ | +| event-type-custom-inputs | ✅ | ✅ | ✅ | ✅ | ✅ | +| event-types | ✅ | ✅ | ✅ | ✅ | ✅ | +| memberships | ✅ | ✅ | ✅ | ✅ | ✅ | +| payments | ✅ | ✅ | ❌ | ❌ | ❌ | +| reminder-mails | ✅ | ✅ | ✅ | ✅ | ✅ | +| schedules | ✅ | ✅ | ✅ | ✅ | ✅ | +| selected-calendars | ✅ | ✅ | ✅ | ✅ | ✅ | +| teams | ✅ | ✅ | ✅ | ✅ | ✅ | +| users | ✅ | 👤[1] | ✅ | ✅ | ✅ | + +## Models from database that are not exposed + +mostly because they're deemed too sensitive can be revisited if needed. + +- [] Api Keys +- [] Credentials + +## Documentation (OpenAPI) + +You will see that each endpoint has a comment at the top with the annotation `@swagger` with the documentation of the endpoint, **please update it if you change the code!** This is what auto-generates the OpenAPI spec by collecting the YAML in each endpoint and parsing it in /docs alongside the json-schema (auto-generated from prisma package, not added to code but manually for now, need to fix later) + +### @calcom/apps/swagger + +The documentation of the API lives inside the code, and it's auto-generated, the only endpoints that return without a valid apiKey are the homepage, with a JSON message redirecting you to the docs. and the /docs endpoint, which returns the OpenAPI 3.0 JSON Spec. Which SwaggerUi then consumes and generates the docs on. + +## Deployment + +`scripts/vercel-deploy.sh` +The API is deployed to vercel.com, it uses a similar deployment script to website or webapp, and requires transpilation of several shared packages that are part of our turborepo ["app-store", "prisma", "lib", "ee"] +in order to build and deploy properly. + +## Envirorment variables + +DATABASE_URL= +API_KEY_PREFIX=cal_# This can be changed per envirorment so cal_test_ for staging for example. diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 008f3dc4f4..0ee197456c 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -26,7 +26,8 @@ export const verifyApiKey: NextMiddleware = async (req, res, next) => { // Right now API Keys are user centric, we only allow resources related to this userId throughout the application. // if the api key is not expired, and the user id is present in the database. // Set the user in the request. as x-calcom-user-id. - res.setHeader("X-Calcom-User-ID", apiKey.userId); + if (apiKey.userId) res.setHeader("X-Calcom-User-ID", apiKey.userId); + // Pass the request to the next middleware. await next(); } diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index feeef587c0..90d0f72fc1 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -27,6 +27,8 @@ import { * - ApiKeyAuth: [] * tags: * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability * responses: * 200: * description: OK @@ -56,6 +58,8 @@ import { * - ApiKeyAuth: [] * tags: * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability * responses: * 201: * description: OK, availability edited successfuly @@ -77,6 +81,8 @@ import { * - ApiKeyAuth: [] * tags: * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability * responses: * 201: * description: OK, availability removed successfuly diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index 558b948d30..bcd904ce95 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -16,6 +16,8 @@ import { schemaAvailabilityBodyParams, schemaAvailabilityPublic } from "@lib/val * - ApiKeyAuth: [] * tags: * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability * responses: * 200: * description: OK @@ -29,6 +31,8 @@ import { schemaAvailabilityBodyParams, schemaAvailabilityPublic } from "@lib/val * - ApiKeyAuth: [] * tags: * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability * responses: * 201: * description: OK, availability created diff --git a/pages/api/daily-event-references/index.ts b/pages/api/daily-event-references/index.ts index aa60482bb1..e3a90d6f03 100644 --- a/pages/api/daily-event-references/index.ts +++ b/pages/api/daily-event-references/index.ts @@ -17,7 +17,7 @@ import { * security: * - ApiKeyAuth: [] * tags: - * - daily-event-reference + * - daily-event-references * responses: * 200: * description: OK @@ -30,7 +30,7 @@ import { * security: * - ApiKeyAuth: [] * tags: - * - daily-event-reference + * - daily-event-references * responses: * 201: * description: OK, daily event reference created From 12dbb0ad032f2ca4e68b874227d169ae359c00b8 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 20 Apr 2022 16:06:37 +0200 Subject: [PATCH 113/658] feat: final securing of all endpoints, update readme --- README.md | 14 +++ tests/api-keys/[id]/api-key.id.delete.test.ts | 86 --------------- tests/api-keys/[id]/api-key.id.edit.test.ts | 103 ------------------ tests/api-keys/[id]/api-key.id.index.test.ts | 83 -------------- tests/api-keys/api-key.index.test.ts | 39 ------- tests/api-keys/api-key.new.test.ts | 77 ------------- 6 files changed, 14 insertions(+), 388 deletions(-) delete mode 100644 tests/api-keys/[id]/api-key.id.delete.test.ts delete mode 100644 tests/api-keys/[id]/api-key.id.edit.test.ts delete mode 100644 tests/api-keys/[id]/api-key.id.index.test.ts delete mode 100644 tests/api-keys/api-key.index.test.ts delete mode 100644 tests/api-keys/api-key.new.test.ts diff --git a/README.md b/README.md index a79bb64f37..5aed701aff 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,17 @@ This is the public REST api for cal.com. It exposes CRUD Endpoints of all our mo - Prisma - No tRPC (for now) We hook directly into prisma client, but probably should look into adding a new @calcom/trpc package that adds pagination and such stuff and can be shared between webapp and API. + +## How to run it + +First clone the main repo with --recursive-submodules flag. This will clone our monorepo, and all the private git submodules within it. +`` +Be sure to be authenticated in gh-cli or via PAT in your shell, as this will clone private repos that requires this (website, api) +`` + +`cp .env.example .env` + +`yarn workspace @calcom/api dev ## API Authentication (API Keys) The API requires a valid apiKey query param to be passed: @@ -133,6 +144,9 @@ mostly because they're deemed too sensitive can be revisited if needed. - [] Api Keys - [] Credentials +- [] Webhooks +- [] ResetPasswordRequest +- [] VerificationToken ## Documentation (OpenAPI) diff --git a/tests/api-keys/[id]/api-key.id.delete.test.ts b/tests/api-keys/[id]/api-key.id.delete.test.ts deleted file mode 100644 index d2abfecb7a..0000000000 --- a/tests/api-keys/[id]/api-key.id.delete.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -import handleDeleteApiKey from "@api/api-keys/[id]/delete"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -describe("DELETE /api/api-keys/[id]/delete with valid id as string returns an apiKey", () => { - it("returns a message with the specified apiKeys", async () => { - const apiKey = await prisma.apiKey.findFirst(); - const { req, res } = createMocks({ - method: "DELETE", - query: { - id: apiKey?.id, - }, - }); - // const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.id} }); - await handleDeleteApiKey(req, res); - expect(res._getStatusCode()).toBe(204); - expect(JSON.parse(res._getData())).toEqual({ - message: `api-key with id: ${apiKey?.id} deleted successfully`, - }); - }); -}); - -// This can never happen under our normal nextjs setup where query is always a string | string[]. -// But seemed a good example for testing an error validation -describe("DELETE /api/api-keys/[id]/delete errors if query id is number, requires a string", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "DELETE", - query: { - id: 1, // passing query as a number, which should fail as nextjs will try to parse it as a string - }, - }); - await handleDeleteApiKey(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "invalid_type", - expected: "string", - received: "number", - path: ["id"], - message: "Expected string, received number", - }, - ]); - }); -}); - -describe("DELETE /api/api-keys/[id]/delete an id not present in db like 0, throws 404 not found", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "DELETE", - query: { - id: "0", // There's no apiKey with id 0 - }, - }); - await handleDeleteApiKey(req, res); - - expect(res._getStatusCode()).toBe(404); - expect(JSON.parse(res._getData())).toStrictEqual({ - error: { - clientVersion: "3.10.0", - code: "P2025", - meta: { - cause: "Record to delete does not exist.", - }, - }, - message: "Resource with id:0 was not found", - }); - }); -}); - -describe("POST /api/api-keys/[id]/delete fails, only DELETE allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "1", - }, - }); - await handleDeleteApiKey(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only DELETE Method allowed" }); - }); -}); diff --git a/tests/api-keys/[id]/api-key.id.edit.test.ts b/tests/api-keys/[id]/api-key.id.edit.test.ts deleted file mode 100644 index 1007181179..0000000000 --- a/tests/api-keys/[id]/api-key.id.edit.test.ts +++ /dev/null @@ -1,103 +0,0 @@ -import handleapiKeyEdit from "@api/api-keys/[id]/edit"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -import { stringifyISODate } from "@lib/utils/stringifyISODate"; - -describe("PATCH /api/api-keys/[id]/edit with valid id and body with note", () => { - it("returns a 200 and the updated apiKey note", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "cl16zg6860000wwylnsgva00b", - }, - body: { - note: "Updated note", - }, - }); - const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.id } }); - await handleapiKeyEdit(req, res); - - expect(res._getStatusCode()).toBe(200); - expect(JSON.parse(res._getData())).toEqual({ - data: { - ...apiKey, - createdAt: stringifyISODate(apiKey?.createdAt), - expiresAt: stringifyISODate(apiKey?.expiresAt), - }, - }); - }); -}); - -describe("PATCH /api/api-keys/[id]/edit with invalid id returns 404", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "cl16zg6860000wwylnsgva00a", - }, - body: { - note: "Updated note", - }, - }); - const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.id } }); - await handleapiKeyEdit(req, res); - - expect(res._getStatusCode()).toBe(404); - if (apiKey) apiKey.note = "Updated note"; - expect(JSON.parse(res._getData())).toStrictEqual({ - error: { - clientVersion: "3.10.0", - code: "P2025", - meta: { - cause: "Record to update not found.", - }, - }, - message: "apiKey with ID cl16zg6860000wwylnsgva00a not found and wasn't updated", - }); - }); -}); - -describe("PATCH /api/api-keys/[id]/edit with valid id and no body returns 200 with an apiKey with no note and default expireAt", () => { - it("returns a message with the specified apiKeys", async () => { - const apiKey = await prisma.apiKey.create({ data: {} }); - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: apiKey?.id, - }, - }); - await handleapiKeyEdit(req, res); - - expect(apiKey?.note).toBeNull(); - expect(res._getStatusCode()).toBe(200); - expect(JSON.parse(res._getData())).toEqual({ - data: { - ...apiKey, - createdAt: stringifyISODate(apiKey?.createdAt), - expiresAt: stringifyISODate(apiKey?.expiresAt), - }, - }); - }); -}); - -describe("POST /api/api-keys/[id]/edit fails, only PATCH allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "cl16zg6860000wwylnsgva00b", - }, - body: { - note: "Updated note", - }, - }); - await handleapiKeyEdit(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ - message: "Only PATCH Method allowed for updating API keys", - }); - }); -}); diff --git a/tests/api-keys/[id]/api-key.id.index.test.ts b/tests/api-keys/[id]/api-key.id.index.test.ts deleted file mode 100644 index 8d3c2655af..0000000000 --- a/tests/api-keys/[id]/api-key.id.index.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -import handleApiKey from "@api/api-keys/[id]"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -import { stringifyISODate } from "@lib/utils/stringifyISODate"; - -describe("GET /api/api-keys/[id] with valid id as string returns an apiKey", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: "cl16zg6860000wwylnsgva00b", - }, - }); - const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.id } }); - await handleApiKey(req, res); - - expect(res._getStatusCode()).toBe(200); - expect(JSON.parse(res._getData())).toEqual({ - data: { - ...apiKey, - createdAt: stringifyISODate(apiKey?.createdAt), - expiresAt: stringifyISODate(apiKey?.expiresAt), - }, - }); - }); -}); - -// This can never happen under our normal nextjs setup where query is always a string | string[]. -// But seemed a good example for testing an error validation -describe("GET /api/api-keys/[id] errors if query id is number, requires a string", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: 1, // passing query as a number, which should fail as nextjs will try to parse it as a string - }, - }); - await handleApiKey(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "invalid_type", - expected: "string", - received: "number", - path: ["id"], - message: "Expected string, received number", - }, - ]); - }); -}); - -describe("GET /api/api-keys/[id] an id not present in db like 0, throws 404 not found", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: "0", // There's no apiKey with id 0 - }, - }); - await handleApiKey(req, res); - - expect(res._getStatusCode()).toBe(404); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "API key was not found" }); - }); -}); - -describe("POST /api/api-keys/[id] fails, only GET allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "1", - }, - }); - await handleApiKey(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); - }); -}); diff --git a/tests/api-keys/api-key.index.test.ts b/tests/api-keys/api-key.index.test.ts deleted file mode 100644 index 957b749b88..0000000000 --- a/tests/api-keys/api-key.index.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import handleApiKeys from "@api/api-keys"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -import { stringifyISODate } from "@lib/utils/stringifyISODate"; - -describe("GET /api/api-keys without any params", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "GET", - query: {}, - }); - let apiKeys = await prisma.apiKey.findMany(); - await handleApiKeys(req, res); - - expect(res._getStatusCode()).toBe(200); - apiKeys = apiKeys.map( - (apiKey) => - (apiKey = { - ...apiKey, - createdAt: stringifyISODate(apiKey?.createdAt), - expiresAt: stringifyISODate(apiKey?.expiresAt), - }) - ); - expect(JSON.parse(res._getData())).toStrictEqual(JSON.parse(JSON.stringify({ data: { ...apiKeys } }))); - }); -}); - -describe("POST /api/api-keys/ fails, only GET allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - }); - await handleApiKeys(req, res); - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); - }); -}); diff --git a/tests/api-keys/api-key.new.test.ts b/tests/api-keys/api-key.new.test.ts deleted file mode 100644 index 339b4c146b..0000000000 --- a/tests/api-keys/api-key.new.test.ts +++ /dev/null @@ -1,77 +0,0 @@ -import handleNewApiKey from "@api/api-keys/new"; -import { createMocks } from "node-mocks-http"; - -describe("POST /api/api-keys/new with a note", () => { - it("returns a 201, and the created api key", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - body: { - note: "Updated note", - }, - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(201); - expect(JSON.parse(res._getData()).data.note).toStrictEqual("Updated note"); - }); -}); - -describe("POST /api/api-keys/new with a slug param", () => { - it("returns error 400, and the details about invalid slug body param", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - body: { - note: "Updated note", - slug: "slug", - }, - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "unrecognized_keys", - keys: ["slug"], - message: "Unrecognized key(s) in object: 'slug'", - path: [], - }, - ]); - }); -}); - -describe("GET /api/api-keys/new fails, only POST allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "GET", // This POST method is not allowed - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ error: "Only POST Method allowed" }); - }); -}); - -// FIXME: test 405 when prisma fails look for how to test prisma errors -describe("GET /api/api-keys/new fails, only POST allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - body: { - nonExistentParam: true, - // note: '123', - // slug: 12, - }, - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "unrecognized_keys", - keys: ["nonExistentParam"], - message: "Unrecognized key(s) in object: 'nonExistentParam'", - path: [], - }, - ]); - }); -}); From e138df47bad1ad57b12d851c7d1dd22138739195 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 20 Apr 2022 20:25:26 +0200 Subject: [PATCH 114/658] remove duplicated error check in event-types id --- pages/api/event-types/[id].ts | 1 - 1 file changed, 1 deletion(-) diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 91ba0e380a..c19822d65b 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -97,7 +97,6 @@ export async function eventTypeById(req: NextApiRequest, res: NextApiResponse eventType.id); From ec903b21c6b6bd3e3da5a4fe8b4f0de8f3ed8978 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 20 Apr 2022 23:42:49 +0200 Subject: [PATCH 115/658] feat: teams return only userId related data, on POST create ownership membership for userId --- README.md | 13 ++++++ lib/types.ts | 1 + pages/api/teams/[id].ts | 87 +++++++++++++++++++++++----------------- pages/api/teams/index.ts | 20 ++++++--- 4 files changed, 78 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 5aed701aff..aa06e86e58 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,17 @@ tests/endpoint/resource.new.test.ts - Create new resource | teams | ✅ | ✅ | ✅ | ✅ | ✅ | | users | ✅ | 👤[1] | ✅ | ✅ | ✅ | +## Models missing userId relation. + +- daily-event-references +- destination-calendars +- event-types-custom-input +- memberships +- reminder-mails +- schedules +- selected-calendars +- teams + ## Models from database that are not exposed mostly because they're deemed too sensitive can be revisited if needed. @@ -166,3 +177,5 @@ in order to build and deploy properly. DATABASE_URL= API_KEY_PREFIX=cal_# This can be changed per envirorment so cal_test_ for staging for example. + +If you're self-hosting under our commercial license, you can use any prefix you want for api keys. either leave the default cal_ (not providing any envirorment variable) or modify it diff --git a/lib/types.ts b/lib/types.ts index 91af310a62..cc3f95d7e8 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -37,6 +37,7 @@ export type UsersResponse = BaseResponse & { // Team export type TeamResponse = BaseResponse & { team?: Partial; + owner?: Partial; }; export type TeamsResponse = BaseResponse & { teams?: Partial[]; diff --git a/pages/api/teams/[id].ts b/pages/api/teams/[id].ts index 07da2e2870..de14a27c3d 100644 --- a/pages/api/teams/[id].ts +++ b/pages/api/teams/[id].ts @@ -97,46 +97,59 @@ export async function teamById(req: NextApiRequest, res: NextApiResponse schemaTeamPublic.parse(data)) - .then((team) => res.status(200).json({ team })) - .catch((error: Error) => - res.status(404).json({ message: `Team with id: ${safeQuery.data.id} not found`, error }) - ); - break; + const userTeamIds = userWithMemberships.map((membership) => membership.teamId); + if (userTeamIds.includes(safeQuery.data.id)) { + switch (method) { + case "GET": + await prisma.team + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data) => schemaTeamPublic.parse(data)) + .then((team) => res.status(200).json({ team })) + .catch((error: Error) => + res.status(404).json({ + message: `Team with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - case "PATCH": - if (!safeBody.success) throw new Error("Invalid request body"); - await prisma.team - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((team) => schemaTeamPublic.parse(team)) - .then((team) => res.status(200).json({ team })) - .catch((error: Error) => - res.status(404).json({ message: `Team with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "PATCH": + if (!safeBody.success) { + throw new Error("Invalid request body"); + } + await prisma.team + .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) + .then((team) => schemaTeamPublic.parse(team)) + .then((team) => res.status(200).json({ team })) + .catch((error: Error) => + res.status(404).json({ + message: `Team with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - case "DELETE": - await prisma.team - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ message: `Team with id: ${safeQuery.data.id} deleted successfully` }) - ) - .catch((error: Error) => - res.status(404).json({ message: `Team with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "DELETE": + await prisma.team + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ + message: `Team with id: ${safeQuery.data.id} deleted successfully`, + }) + ) + .catch((error: Error) => + res.status(404).json({ + message: `Team with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } + } else res.status(401).json({ message: "Unauthorized" }); } export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(teamById)); diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index d1c24bf8b8..3fcd7d7d05 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -5,6 +5,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { TeamResponse, TeamsResponse } from "@lib/types"; import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; +import { schemaMembershipPublic } from "@lib/validations/membership"; import { schemaTeamBodyParams, schemaTeamPublic, withValidTeam } from "@lib/validations/team"; /** @@ -59,13 +60,20 @@ async function createOrlistAllTeams(req: NextApiRequest, res: NextApiResponse schemaMembershipPublic.parse(membership)); + // We're also creating the relation membership of team ownership in this call. const data = schemaTeamPublic.parse(team); - - if (data) res.status(201).json({ team: data, message: "Team created successfully" }); + // We are also returning the new ownership relation as owner besides team. + if (data) + res.status(201).json({ + team: data, + owner: membership, + message: "Team created successfully, we also made you the owner of this team", + }); else (error: Error) => res.status(400).json({ From 910f222d626bd44f2f009e96144b2d5b038cb80c Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 20 Apr 2022 23:43:40 +0200 Subject: [PATCH 116/658] fix: remove teams from endpoints that need hardening --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index aa06e86e58..42c02cfd23 100644 --- a/README.md +++ b/README.md @@ -147,7 +147,6 @@ tests/endpoint/resource.new.test.ts - Create new resource - reminder-mails - schedules - selected-calendars -- teams ## Models from database that are not exposed From 6749840077542a1e998c56d9ad96a5eca03e06e5 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 21 Apr 2022 00:00:02 +0200 Subject: [PATCH 117/658] fix: improve comments on teams --- pages/api/teams/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index 3fcd7d7d05..a480bff97a 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -56,16 +56,15 @@ async function createOrlistAllTeams(req: NextApiRequest, res: NextApiResponse schemaMembershipPublic.parse(membership)); - // We're also creating the relation membership of team ownership in this call. const data = schemaTeamPublic.parse(team); // We are also returning the new ownership relation as owner besides team. if (data) From 80c2c4bdae4a840fa6e731ce68f88646fdb933f4 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 21 Apr 2022 00:31:42 +0200 Subject: [PATCH 118/658] feat: selected calendars hardened --- README.md | 1 - pages/api/selected-calendars/[id].ts | 134 ++++++++++++++------------ pages/api/selected-calendars/index.ts | 16 +-- 3 files changed, 83 insertions(+), 68 deletions(-) diff --git a/README.md b/README.md index 42c02cfd23..c3faa6a283 100644 --- a/README.md +++ b/README.md @@ -146,7 +146,6 @@ tests/endpoint/resource.new.test.ts - Create new resource - memberships - reminder-mails - schedules -- selected-calendars ## Models from database that are not exposed diff --git a/pages/api/selected-calendars/[id].ts b/pages/api/selected-calendars/[id].ts index 219d51dc4c..69cd9c059e 100644 --- a/pages/api/selected-calendars/[id].ts +++ b/pages/api/selected-calendars/[id].ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { SelectedCalendarResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaSelectedCalendarBodyParams, schemaSelectedCalendarPublic, @@ -130,72 +131,85 @@ export async function selectedCalendarById( const safeBody = schemaSelectedCalendarBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); // This is how we set the userId and externalId in the query for managing compoundId. - const [userId, integration, externalId] = safeQuery.data.id.split("_"); - - switch (method) { - case "GET": - await prisma.selectedCalendar - .findUnique({ - where: { - userId_integration_externalId: { - userId: parseInt(userId), - integration: integration, - externalId: externalId, + const [paramUserId, integration, externalId] = safeQuery.data.id.split("_"); + const userId = getCalcomUserId(res); + if (userId === parseInt(paramUserId)) { + switch (method) { + case "GET": + await prisma.selectedCalendar + .findUnique({ + where: { + userId_integration_externalId: { + userId: userId, + integration: integration, + externalId: externalId, + }, }, - }, - }) - .then((selectedCalendar) => schemaSelectedCalendarPublic.parse(selectedCalendar)) - .then((selected_calendar) => res.status(200).json({ selected_calendar })) - .catch((error: Error) => - res.status(404).json({ message: `SelectedCalendar with id: ${safeQuery.data.id} not found`, error }) - ); - break; + }) + .then((selectedCalendar) => schemaSelectedCalendarPublic.parse(selectedCalendar)) + .then((selected_calendar) => res.status(200).json({ selected_calendar })) + .catch((error: Error) => + res.status(404).json({ + message: `SelectedCalendar with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - case "PATCH": - if (!safeBody.success) throw new Error("Invalid request body"); - await prisma.selectedCalendar - .update({ - where: { - userId_integration_externalId: { - userId: parseInt(userId), - integration: integration, - externalId: externalId, + case "PATCH": + if (!safeBody.success) { + throw new Error("Invalid request body"); + } + await prisma.selectedCalendar + .update({ + where: { + userId_integration_externalId: { + userId: userId, + integration: integration, + externalId: externalId, + }, }, - }, - data: safeBody.data, - }) - .then((selectedCalendar) => schemaSelectedCalendarPublic.parse(selectedCalendar)) - .then((selected_calendar) => res.status(200).json({ selected_calendar })) - .catch((error: Error) => - res.status(404).json({ message: `SelectedCalendar with id: ${safeQuery.data.id} not found`, error }) - ); - break; + data: safeBody.data, + }) + .then((selectedCalendar) => schemaSelectedCalendarPublic.parse(selectedCalendar)) + .then((selected_calendar) => res.status(200).json({ selected_calendar })) + .catch((error: Error) => + res.status(404).json({ + message: `SelectedCalendar with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - case "DELETE": - await prisma.selectedCalendar - .delete({ - where: { - userId_integration_externalId: { - userId: parseInt(userId), - integration: integration, - externalId: externalId, + case "DELETE": + await prisma.selectedCalendar + .delete({ + where: { + userId_integration_externalId: { + userId: userId, + integration: integration, + externalId: externalId, + }, }, - }, - }) - .then(() => - res - .status(200) - .json({ message: `SelectedCalendar with id: ${safeQuery.data.id} deleted successfully` }) - ) - .catch((error: Error) => - res.status(404).json({ message: `SelectedCalendar with id: ${safeQuery.data.id} not found`, error }) - ); - break; + }) + .then(() => + res.status(200).json({ + message: `SelectedCalendar with id: ${safeQuery.data.id} deleted successfully`, + }) + ) + .catch((error: Error) => + res.status(404).json({ + message: `SelectedCalendar with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } + } else res.status(401).json({ message: "Unauthorized" }); } export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdString(selectedCalendarById)); diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index 15daead8a2..cb12a5dac7 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -4,10 +4,10 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { SelectedCalendarResponse, SelectedCalendarsResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaSelectedCalendarBodyParams, schemaSelectedCalendarPublic, - withValidSelectedCalendar, } from "@lib/validations/selected-calendar"; /** @@ -46,8 +46,10 @@ async function createOrlistAllSelectedCalendars( res: NextApiResponse ) { const { method } = req; + const userId = getCalcomUserId(res); + if (method === "GET") { - const data = await prisma.selectedCalendar.findMany(); + const data = await prisma.selectedCalendar.findMany({ where: { userId } }); const selected_calendars = data.map((selected_calendar) => schemaSelectedCalendarPublic.parse(selected_calendar) ); @@ -61,8 +63,10 @@ async function createOrlistAllSelectedCalendars( } else if (method === "POST") { const safe = schemaSelectedCalendarBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body"); - - const data = await prisma.selectedCalendar.create({ data: safe.data }); + // Create new selectedCalendar connecting it to current userId + const data = await prisma.selectedCalendar.create({ + data: { ...safe.data, user: { connect: { id: userId } } }, + }); const selected_calendar = schemaSelectedCalendarPublic.parse(data); if (selected_calendar) @@ -76,6 +80,4 @@ async function createOrlistAllSelectedCalendars( } else res.status(405).json({ message: `Method ${method} not allowed` }); } -export default withMiddleware("HTTP_GET_OR_POST")( - withValidSelectedCalendar(createOrlistAllSelectedCalendars) -); +export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllSelectedCalendars); From cabe4ae9c60f05145d1b24a5fa6a72a26a30163c Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 21 Apr 2022 00:48:54 +0200 Subject: [PATCH 119/658] feat: schedules hardend --- README.md | 19 ++++---- pages/api/schedules/[id].ts | 91 +++++++++++++++++++++--------------- pages/api/schedules/index.ts | 8 ++-- 3 files changed, 68 insertions(+), 50 deletions(-) diff --git a/README.md b/README.md index c3faa6a283..3731387b94 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,9 @@ This is the public REST api for cal.com. It exposes CRUD Endpoints of all our mo - NextJS - TypeScript - Prisma -- No tRPC (for now) We hook directly into prisma client, but probably should look into adding a new @calcom/trpc package that adds pagination and such stuff and can be shared between webapp and API. +- No tRPC ** + +** (for now) We hook directly into prisma client, but probably should look into adding a new @calcom/trpc package that adds pagination and such stuff and can be shared between webapp and API. ## How to run it @@ -138,24 +140,23 @@ tests/endpoint/resource.new.test.ts - Create new resource | teams | ✅ | ✅ | ✅ | ✅ | ✅ | | users | ✅ | 👤[1] | ✅ | ✅ | ✅ | -## Models missing userId relation. +## Models missing userId relation - daily-event-references - destination-calendars - event-types-custom-input - memberships - reminder-mails -- schedules ## Models from database that are not exposed -mostly because they're deemed too sensitive can be revisited if needed. +mostly because they're deemed too sensitive can be revisited if needed. most are expected to be used via cal's webapp. -- [] Api Keys -- [] Credentials -- [] Webhooks -- [] ResetPasswordRequest -- [] VerificationToken +- [ ] Api Keys +- [ ] Credentials +- [ ] Webhooks +- [ ] ResetPasswordRequest +- [ ] VerificationToken ## Documentation (OpenAPI) diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index eb87d13949..1b46e62269 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { ScheduleResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaScheduleBodyParams, schemaSchedulePublic } from "@lib/validations/schedule"; import { schemaQueryIdParseInt, @@ -90,47 +91,61 @@ export async function scheduleById(req: NextApiRequest, res: NextApiResponse schedule.id); + if (userScheduleIds.includes(safeQuery.data.id)) { + switch (method) { + case "GET": + await prisma.schedule + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data) => schemaSchedulePublic.parse(data)) + .then((schedule) => res.status(200).json({ schedule })) + .catch((error: Error) => + res.status(404).json({ + message: `Schedule with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - switch (method) { - case "GET": - await prisma.schedule - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaSchedulePublic.parse(data)) - .then((schedule) => res.status(200).json({ schedule })) - .catch((error: Error) => - res.status(404).json({ message: `Schedule with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "PATCH": + if (!safeBody.success) { + throw new Error("Invalid request body"); + } + await prisma.schedule + .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) + .then((data) => schemaSchedulePublic.parse(data)) + .then((schedule) => res.status(200).json({ schedule })) + .catch((error: Error) => + res.status(404).json({ + message: `Schedule with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - case "PATCH": - if (!safeBody.success) throw new Error("Invalid request body"); - await prisma.schedule - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((data) => schemaSchedulePublic.parse(data)) - .then((schedule) => res.status(200).json({ schedule })) - .catch((error: Error) => - res.status(404).json({ message: `Schedule with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "DELETE": + await prisma.schedule + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ + message: `Schedule with id: ${safeQuery.data.id} deleted successfully`, + }) + ) + .catch((error: Error) => + res.status(404).json({ + message: `Schedule with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - case "DELETE": - await prisma.schedule - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ message: `Schedule with id: ${safeQuery.data.id} deleted successfully` }) - ) - .catch((error: Error) => - res.status(404).json({ message: `Schedule with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } + } else res.status(401).json({ message: "Unauthorized" }); } export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(scheduleById)); diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index 3f5761e30d..cb4eeaeb9d 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { ScheduleResponse, SchedulesResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaScheduleBodyParams, schemaSchedulePublic, withValidSchedule } from "@lib/validations/schedule"; /** @@ -42,8 +43,10 @@ async function createOrlistAllSchedules( res: NextApiResponse ) { const { method } = req; + const userId = getCalcomUserId(res); + if (method === "GET") { - const data = await prisma.schedule.findMany(); + const data = await prisma.schedule.findMany({ where: { userId } }); const schedules = data.map((schedule) => schemaSchedulePublic.parse(schedule)); if (schedules) res.status(200).json({ schedules }); else @@ -55,8 +58,7 @@ async function createOrlistAllSchedules( } else if (method === "POST") { const safe = schemaScheduleBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body"); - - const data = await prisma.schedule.create({ data: safe.data }); + const data = await prisma.schedule.create({ data: { ...safe.data, userId } }); const schedule = schemaSchedulePublic.parse(data); if (schedule) res.status(201).json({ schedule, message: "Schedule created successfully" }); From 9c5624c748f82e5e4a4d67e64a7732ebd647b3bc Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 21 Apr 2022 00:50:34 +0200 Subject: [PATCH 120/658] fix: delete reminder mails endpoints for now as no userId, consult if needed --- pages/api/reminder-mails/[id].ts | 136 ------------------------------ pages/api/reminder-mails/index.ts | 76 ----------------- 2 files changed, 212 deletions(-) delete mode 100644 pages/api/reminder-mails/[id].ts delete mode 100644 pages/api/reminder-mails/index.ts diff --git a/pages/api/reminder-mails/[id].ts b/pages/api/reminder-mails/[id].ts deleted file mode 100644 index e6627ef7b9..0000000000 --- a/pages/api/reminder-mails/[id].ts +++ /dev/null @@ -1,136 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { ReminderMailResponse } from "@lib/types"; -import { schemaReminderMailBodyParams, schemaReminderMailPublic } from "@lib/validations/reminder-mail"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /v1/reminder-mails/{id}: - * get: - * summary: Get a reminderMail by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the reminderMail to get - * security: - * - ApiKeyAuth: [] - * tags: - * - reminder-mails - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: ReminderMail was not found - * patch: - * summary: Edit an existing reminderMail - * consumes: - * - application/json - * parameters: - * - in: body - * name: reminderMail - * description: The reminderMail to edit - * schema: - * type: object - * $ref: '#/components/schemas/ReminderMail' - * required: true - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the reminderMail to edit - * security: - * - ApiKeyAuth: [] - * tags: - * - reminder-mails - * responses: - * 201: - * description: OK, reminderMail edited successfuly - * model: ReminderMail - * 400: - * description: Bad request. ReminderMail body is invalid. - * 401: - * description: Authorization information is missing or invalid. - * delete: - * summary: Remove an existing reminderMail - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the reminderMail to delete - * security: - * - ApiKeyAuth: [] - * tags: - * - reminder-mails - * responses: - * 201: - * description: OK, reminderMail removed successfuly - * model: ReminderMail - * 400: - * description: Bad request. ReminderMail id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function reminderMailById(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body } = req; - const safeQuery = schemaQueryIdParseInt.safeParse(query); - const safeBody = schemaReminderMailBodyParams.safeParse(body); - if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - - switch (method) { - case "GET": - await prisma.reminderMail - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaReminderMailPublic.parse(data)) - .then((reminder_mail) => res.status(200).json({ reminder_mail })) - .catch((error: Error) => - res.status(404).json({ message: `ReminderMail with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - case "PATCH": - if (!safeBody.success) throw new Error("Invalid request body"); - await prisma.reminderMail - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((reminderMail) => schemaReminderMailPublic.parse(reminderMail)) - .then((reminder_mail) => res.status(200).json({ reminder_mail })) - .catch((error: Error) => - res.status(404).json({ message: `ReminderMail with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - case "DELETE": - await prisma.reminderMail - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ message: `ReminderMail with id: ${safeQuery.data.id} deleted successfully` }) - ) - .catch((error: Error) => - res.status(404).json({ message: `ReminderMail with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } -} - -export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(reminderMailById)); diff --git a/pages/api/reminder-mails/index.ts b/pages/api/reminder-mails/index.ts deleted file mode 100644 index 22c4f63dab..0000000000 --- a/pages/api/reminder-mails/index.ts +++ /dev/null @@ -1,76 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { ReminderMailResponse, ReminderMailsResponse } from "@lib/types"; -import { - schemaReminderMailBodyParams, - schemaReminderMailPublic, - withValidReminderMail, -} from "@lib/validations/reminder-mail"; - -/** - * @swagger - * /v1/reminder-mails: - * get: - * summary: Get all reminder mails - * security: - * - ApiKeyAuth: [] - * tags: - * - reminder-mails - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No reminder mails were found - * post: - * summary: Creates a new reminder mail - * security: - * - ApiKeyAuth: [] - * tags: - * - reminder-mails - * responses: - * 201: - * description: OK, reminder mail created - * model: ReminderMail - * 400: - * description: Bad request. ReminderMail body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createOrlistAllReminderMails( - req: NextApiRequest, - res: NextApiResponse -) { - const { method } = req; - if (method === "GET") { - const data = await prisma.reminderMail.findMany(); - const reminder_mails = data.map((reminderMail) => schemaReminderMailPublic.parse(reminderMail)); - if (reminder_mails) res.status(200).json({ reminder_mails }); - else - (error: Error) => - res.status(404).json({ - message: "No ReminderMails were found", - error, - }); - } else if (method === "POST") { - const safe = schemaReminderMailBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body"); - - const data = await prisma.reminderMail.create({ data: safe.data }); - const reminder_mail = schemaReminderMailPublic.parse(data); - - if (reminder_mail) res.status(201).json({ reminder_mail, message: "reminder mail created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "could not create new reminder mail", - error, - }); - } else res.status(405).json({ message: `Method ${method} not allowed` }); -} - -export default withMiddleware("HTTP_GET_OR_POST")(withValidReminderMail(createOrlistAllReminderMails)); From b0c0e9fb4cb74bf37bd5c748a621df2339ab05db Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 21 Apr 2022 00:55:22 +0200 Subject: [PATCH 121/658] feat: memberships hardened mode --- pages/api/memberships/[id].ts | 113 +++++++++++++++++++++------------ pages/api/memberships/index.ts | 6 +- 2 files changed, 78 insertions(+), 41 deletions(-) diff --git a/pages/api/memberships/[id].ts b/pages/api/memberships/[id].ts index 2fbb14bcdb..df62f89107 100644 --- a/pages/api/memberships/[id].ts +++ b/pages/api/memberships/[id].ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { MembershipResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaMembershipBodyParams, schemaMembershipPublic } from "@lib/validations/membership"; import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; @@ -106,48 +107,82 @@ export async function membershipById(req: NextApiRequest, res: NextApiResponse schemaMembershipPublic.parse(data)) + .then((membership) => res.status(200).json({ membership })) + .catch((error: Error) => + res.status(404).json({ + message: `Membership with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - switch (method) { - case "GET": - await prisma.membership - .findUnique({ where: { userId_teamId: { userId: parseInt(userId), teamId: parseInt(teamId) } } }) - .then((data) => schemaMembershipPublic.parse(data)) - .then((membership) => res.status(200).json({ membership })) - .catch((error: Error) => - res.status(404).json({ message: `Membership with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "PATCH": + if (!safeBody.success) { + throw new Error("Invalid request body"); + } + await prisma.membership + .update({ + where: { + userId_teamId: { + userId: userId, + teamId: parseInt(teamId), + }, + }, + data: safeBody.data, + }) + .then((data) => schemaMembershipPublic.parse(data)) + .then((membership) => res.status(200).json({ membership })) + .catch((error: Error) => + res.status(404).json({ + message: `Membership with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - case "PATCH": - if (!safeBody.success) throw new Error("Invalid request body"); - await prisma.membership - .update({ - where: { userId_teamId: { userId: parseInt(userId), teamId: parseInt(teamId) } }, - data: safeBody.data, - }) - .then((data) => schemaMembershipPublic.parse(data)) - .then((membership) => res.status(200).json({ membership })) - .catch((error: Error) => - res.status(404).json({ message: `Membership with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "DELETE": + await prisma.membership + .delete({ + where: { + userId_teamId: { + userId: userId, + teamId: parseInt(teamId), + }, + }, + }) + .then(() => + res.status(200).json({ + message: `Membership with id: ${safeQuery.data.id} deleted successfully`, + }) + ) + .catch((error: Error) => + res.status(404).json({ + message: `Membership with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - case "DELETE": - await prisma.membership - .delete({ where: { userId_teamId: { userId: parseInt(userId), teamId: parseInt(teamId) } } }) - .then(() => - res.status(200).json({ message: `Membership with id: ${safeQuery.data.id} deleted successfully` }) - ) - .catch((error: Error) => - res.status(404).json({ message: `Membership with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } + } else res.status(401).json({ message: "Unauthorized" }); } export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdString(membershipById)); diff --git a/pages/api/memberships/index.ts b/pages/api/memberships/index.ts index 85c2ddced1..a7a109da2d 100644 --- a/pages/api/memberships/index.ts +++ b/pages/api/memberships/index.ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { MembershipResponse, MembershipsResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaMembershipBodyParams, schemaMembershipPublic } from "@lib/validations/membership"; /** @@ -42,8 +43,9 @@ async function createOrlistAllMemberships( res: NextApiResponse ) { const { method } = req; + const userId = getCalcomUserId(res); if (method === "GET") { - const data = await prisma.membership.findMany(); + const data = await prisma.membership.findMany({ where: { userId } }); const memberships = data.map((membership) => schemaMembershipPublic.parse(membership)); if (memberships) res.status(200).json({ memberships }); else @@ -56,7 +58,7 @@ async function createOrlistAllMemberships( const safe = schemaMembershipBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body"); - const data = await prisma.membership.create({ data: safe.data }); + const data = await prisma.membership.create({ data: { ...safe.data, userId } }); const membership = schemaMembershipPublic.parse(data); if (membership) res.status(201).json({ membership, message: "Membership created successfully" }); From 18c1a2f026bc1106e74c0e41ba108c956df9e6c0 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 21 Apr 2022 00:55:41 +0200 Subject: [PATCH 122/658] remove unnecessary await on all getCalcomUserId() calls --- pages/api/attendees/index.ts | 2 +- pages/api/availabilities/[id].ts | 2 +- pages/api/availabilities/index.ts | 2 +- pages/api/booking-references/[id].ts | 2 +- pages/api/booking-references/index.ts | 4 ++-- pages/api/bookings/[id].ts | 2 +- pages/api/bookings/index.ts | 2 +- pages/api/event-types/[id].ts | 2 +- pages/api/event-types/index.ts | 2 +- pages/api/payments/[id].ts | 2 +- pages/api/payments/index.ts | 2 +- 11 files changed, 12 insertions(+), 12 deletions(-) diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index ed0707d636..d96fe3bca4 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -68,7 +68,7 @@ async function createOrlistAllAttendees( throw new Error("Invalid request body", safe.error); } const bookingId = safe.data.bookingId; - const userId = await getCalcomUserId(res); + const userId = getCalcomUserId(res); const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index 90d0f72fc1..bdb1215f74 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -97,7 +97,7 @@ export async function availabilityById(req: NextApiRequest, res: NextApiResponse const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaAvailabilityBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = await getCalcomUserId(res); + const userId = getCalcomUserId(res); const data = await prisma.availability.findMany({ where: { userId } }); const availabiltiesIds = data.map((availability) => availability.id); if (availabiltiesIds.includes(safeQuery.data.id)) { diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index bcd904ce95..63ae75db49 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -47,7 +47,7 @@ async function createOrlistAllAvailabilities( res: NextApiResponse ) { const { method } = req; - const userId = await getCalcomUserId(res); + const userId = getCalcomUserId(res); if (method === "GET") { const data = await prisma.availability.findMany({ where: { userId } }); diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index 3067dc3c15..9a1b40089b 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -98,7 +98,7 @@ export async function bookingReferenceById( const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaBookingReferenceBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = await getCalcomUserId(res); + const userId = getCalcomUserId(res); const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index d256936ce5..9ceedeed30 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -46,7 +46,7 @@ async function createOrlistAllBookingReferences( res: NextApiResponse ) { const { method } = req; - const userId = await getCalcomUserId(res); + const userId = getCalcomUserId(res); const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, @@ -72,7 +72,7 @@ async function createOrlistAllBookingReferences( } // const booking_reference = schemaBookingReferencePublic.parse(data); - const userId = await getCalcomUserId(res); + const userId = getCalcomUserId(res); const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index e3e56b9a36..af6a379158 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -91,7 +91,7 @@ export async function bookingById(req: NextApiRequest, res: NextApiResponse ) { const { method } = req; - const userId = await getCalcomUserId(res); + const userId = getCalcomUserId(res); if (method === "GET") { const data = await prisma.booking.findMany({ where: { userId } }); diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index c19822d65b..dc7535cd5a 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -97,7 +97,7 @@ export async function eventTypeById(req: NextApiRequest, res: NextApiResponse eventType.id); if (userEventTypes.includes(safeQuery.data.id)) { diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index cd883d719c..fc6a2a35f7 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -47,7 +47,7 @@ async function createOrlistAllEventTypes( res: NextApiResponse ) { const { method } = req; - const userId = await getCalcomUserId(res); + const userId = getCalcomUserId(res); if (method === "GET") { const data = await prisma.eventType.findMany({ where: { userId } }); diff --git a/pages/api/payments/[id].ts b/pages/api/payments/[id].ts index f196b4cac0..295803ca76 100644 --- a/pages/api/payments/[id].ts +++ b/pages/api/payments/[id].ts @@ -38,7 +38,7 @@ import { export async function paymentById(req: NextApiRequest, res: NextApiResponse) { const { method, query } = req; const safeQuery = schemaQueryIdParseInt.safeParse(query); - const userId = await getCalcomUserId(res); + const userId = getCalcomUserId(res); if (safeQuery.success && method === "GET") { const userWithBookings = await prisma.user.findUnique({ diff --git a/pages/api/payments/index.ts b/pages/api/payments/index.ts index 20028df180..bb2c132c0c 100644 --- a/pages/api/payments/index.ts +++ b/pages/api/payments/index.ts @@ -25,7 +25,7 @@ import { schemaPaymentPublic } from "@lib/validations/payment"; * description: No payments were found */ async function allPayments(_: NextApiRequest, res: NextApiResponse) { - const userId = await getCalcomUserId(res); + const userId = getCalcomUserId(res); const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, From d8bfff95254494dbe3138c82a8dab2e20b366101 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 21 Apr 2022 01:08:45 +0200 Subject: [PATCH 123/658] feat: event type custom input endpoitns ready --- README.md | 8 +- pages/api/event-type-custom-inputs/[id].ts | 99 +++++++++++++-------- pages/api/event-type-custom-inputs/index.ts | 37 ++++++-- 3 files changed, 93 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index 3731387b94..480973762b 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,6 @@ tests/endpoint/resource.new.test.ts - Create new resource | event-types | ✅ | ✅ | ✅ | ✅ | ✅ | | memberships | ✅ | ✅ | ✅ | ✅ | ✅ | | payments | ✅ | ✅ | ❌ | ❌ | ❌ | -| reminder-mails | ✅ | ✅ | ✅ | ✅ | ✅ | | schedules | ✅ | ✅ | ✅ | ✅ | ✅ | | selected-calendars | ✅ | ✅ | ✅ | ✅ | ✅ | | teams | ✅ | ✅ | ✅ | ✅ | ✅ | @@ -144,9 +143,7 @@ tests/endpoint/resource.new.test.ts - Create new resource - daily-event-references - destination-calendars -- event-types-custom-input -- memberships -- reminder-mails + ## Models from database that are not exposed @@ -157,7 +154,8 @@ mostly because they're deemed too sensitive can be revisited if needed. most are - [ ] Webhooks - [ ] ResetPasswordRequest - [ ] VerificationToken - +- [ ] ReminderMail +- [ ] ## Documentation (OpenAPI) You will see that each endpoint has a comment at the top with the annotation `@swagger` with the documentation of the endpoint, **please update it if you change the code!** This is what auto-generates the OpenAPI spec by collecting the YAML in each endpoint and parsing it in /docs alongside the json-schema (auto-generated from prisma package, not added to code but manually for now, need to fix later) diff --git a/pages/api/event-type-custom-inputs/[id].ts b/pages/api/event-type-custom-inputs/[id].ts index d9dd21d112..5a00436361 100644 --- a/pages/api/event-type-custom-inputs/[id].ts +++ b/pages/api/event-type-custom-inputs/[id].ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { EventTypeCustomInputResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaEventTypeCustomInputBodyParams, schemaEventTypeCustomInputPublic, @@ -93,47 +94,69 @@ async function eventTypeById(req: NextApiRequest, res: NextApiResponse eventType.id); + const userEventTypeCustomInputs = await prisma.eventTypeCustomInput.findMany({ + where: { eventType: userEventTypes }, + }); + const userEventTypeCustomInputIds = userEventTypeCustomInputs.map( + (eventTypeCustomInput) => eventTypeCustomInput.id + ); + if (userEventTypeCustomInputIds.includes(safeQuery.data.id)) { + switch (method) { + case "GET": + await prisma.eventTypeCustomInput + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data) => schemaEventTypeCustomInputPublic.parse(data)) + .then((event_type_custom_input) => res.status(200).json({ event_type_custom_input })) + .catch((error: Error) => + res.status(404).json({ + message: `EventType with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - switch (method) { - case "GET": - await prisma.eventTypeCustomInput - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaEventTypeCustomInputPublic.parse(data)) - .then((event_type_custom_input) => res.status(200).json({ event_type_custom_input })) - .catch((error: Error) => - res.status(404).json({ message: `EventType with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "PATCH": + if (!safeBody.success) { + throw new Error("Invalid request body"); + } + await prisma.eventTypeCustomInput + .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) + .then((data) => schemaEventTypeCustomInputPublic.parse(data)) + .then((event_type_custom_input) => res.status(200).json({ event_type_custom_input })) + .catch((error: Error) => + res.status(404).json({ + message: `EventType with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - case "PATCH": - if (!safeBody.success) throw new Error("Invalid request body"); - await prisma.eventTypeCustomInput - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((data) => schemaEventTypeCustomInputPublic.parse(data)) - .then((event_type_custom_input) => res.status(200).json({ event_type_custom_input })) - .catch((error: Error) => - res.status(404).json({ message: `EventType with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "DELETE": + await prisma.eventTypeCustomInput + .delete({ + where: { id: safeQuery.data.id }, + }) + .then(() => + res.status(200).json({ + message: `CustomInputEventType with id: ${safeQuery.data.id} deleted`, + }) + ) + .catch((error: Error) => + res.status(404).json({ + message: `EventType with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - case "DELETE": - await prisma.eventTypeCustomInput - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ message: `CustomInputEventType with id: ${safeQuery.data.id} deleted` }) - ) - .catch((error: Error) => - res.status(404).json({ message: `EventType with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } + } else res.status(401).json({ message: "Unauthorized" }); } export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(eventTypeById)); diff --git a/pages/api/event-type-custom-inputs/index.ts b/pages/api/event-type-custom-inputs/index.ts index 806d3ca91e..e6c0c852bf 100644 --- a/pages/api/event-type-custom-inputs/index.ts +++ b/pages/api/event-type-custom-inputs/index.ts @@ -45,8 +45,17 @@ async function createOrlistAllEventTypeCustomInputs( res: NextApiResponse ) { const { method } = req; + const userId = getCalcomUserId(res); + const data = await prisma.eventType.findMany({ where: { userId } }); + const userEventTypes = data.map((eventType) => eventType.id); + // const userEventTypeCustomInputs = await prisma.eventTypeCustomInput.findMany({ + // where: { eventType: userEventTypes }, + // }); + // const userEventTypeCustomInputIds = userEventTypeCustomInputs.map( + // (eventTypeCustomInput) => eventTypeCustomInput.id + // ); if (method === "GET") { - const data = await prisma.eventTypeCustomInput.findMany(); + const data = await prisma.eventTypeCustomInput.findMany({ where: { eventType: userEventTypes } }); const event_type_custom_inputs = data.map((eventTypeCustomInput) => schemaEventTypeCustomInputPublic.parse(eventTypeCustomInput) ); @@ -60,13 +69,25 @@ async function createOrlistAllEventTypeCustomInputs( } else if (method === "POST") { const safe = schemaEventTypeCustomInputBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body"); - - const data = await prisma.eventTypeCustomInput.create({ data: safe.data }); - const event_type_custom_input = schemaEventTypeCustomInputPublic.parse(data); - - if (event_type_custom_input) - res.status(201).json({ event_type_custom_input, message: "EventTypeCustomInput created successfully" }); - else + // Since we're supporting a create or connect relation on eventType, we need to treat them differently + // When using connect on event type, check if userId is the owner of the event + if (safe.data.eventType.connect && !userEventTypes.includes(safe.data.eventType.connect.id as number)) { + const data = await prisma.eventTypeCustomInput.create({ data: { ...safe.data } }); + const event_type_custom_input = schemaEventTypeCustomInputPublic.parse(data); + if (event_type_custom_input) + res + .status(201) + .json({ event_type_custom_input, message: "EventTypeCustomInput created successfully" }); + // When creating, no need + // FIXME: we might want to pass userId to the new created/linked eventType, though. + } else if (safe.data.eventType.create) { + const data = await prisma.eventTypeCustomInput.create({ data: { ...safe.data } }); + const event_type_custom_input = schemaEventTypeCustomInputPublic.parse(data); + if (event_type_custom_input) + res + .status(201) + .json({ event_type_custom_input, message: "EventTypeCustomInput created successfully" }); + } else (error: Error) => res.status(400).json({ message: "Could not create new eventTypeCustomInput", From 103228cf8452110f86d59b99e30b3231cb1eaeae Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 21 Apr 2022 01:15:58 +0200 Subject: [PATCH 124/658] feat: destination calendars ready --- README.md | 1 - pages/api/destination-calendars/[id].ts | 101 +++++++++++++---------- pages/api/destination-calendars/index.ts | 7 +- 3 files changed, 62 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 480973762b..844008a152 100644 --- a/README.md +++ b/README.md @@ -142,7 +142,6 @@ tests/endpoint/resource.new.test.ts - Create new resource ## Models missing userId relation - daily-event-references -- destination-calendars ## Models from database that are not exposed diff --git a/pages/api/destination-calendars/[id].ts b/pages/api/destination-calendars/[id].ts index ef7712e525..62eb85810c 100644 --- a/pages/api/destination-calendars/[id].ts +++ b/pages/api/destination-calendars/[id].ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { DestinationCalendarResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaDestinationCalendarBodyParams, schemaDestinationCalendarPublic, @@ -96,53 +97,65 @@ export async function destionationCalendarById( const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaDestinationCalendarBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + const userId = getCalcomUserId(res); + const data = await prisma.destinationCalendar.findMany({ where: { userId } }); + const userDestinationCalendars = data.map((destinationCalendar) => destinationCalendar.id); + // FIXME: Should we also check ownership of bokingId and eventTypeId to avoid users cross-pollinating other users calendars. + // On a related note, moving from sequential integer IDs to UUIDs would be a good idea. and maybe help avoid having this problem. + if (userDestinationCalendars.includes(safeQuery.data.id)) { + switch (method) { + case "GET": + await prisma.destinationCalendar + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data) => schemaDestinationCalendarPublic.parse(data)) + .then((destination_calendar) => res.status(200).json({ destination_calendar })) + .catch((error: Error) => + res.status(404).json({ + message: `DestinationCalendar with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - switch (method) { - case "GET": - await prisma.destinationCalendar - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaDestinationCalendarPublic.parse(data)) - .then((destination_calendar) => res.status(200).json({ destination_calendar })) - .catch((error: Error) => - res - .status(404) - .json({ message: `DestinationCalendar with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "PATCH": + if (!safeBody.success) { + throw new Error("Invalid request body"); + } + await prisma.destinationCalendar + .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) + .then((data) => schemaDestinationCalendarPublic.parse(data)) + .then((destination_calendar) => res.status(200).json({ destination_calendar })) + .catch((error: Error) => + res.status(404).json({ + message: `DestinationCalendar with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - case "PATCH": - if (!safeBody.success) throw new Error("Invalid request body"); - await prisma.destinationCalendar - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((data) => schemaDestinationCalendarPublic.parse(data)) - .then((destination_calendar) => res.status(200).json({ destination_calendar })) - .catch((error: Error) => - res - .status(404) - .json({ message: `DestinationCalendar with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "DELETE": + await prisma.destinationCalendar + .delete({ + where: { id: safeQuery.data.id }, + }) + .then(() => + res.status(200).json({ + message: `DestinationCalendar with id: ${safeQuery.data.id} deleted`, + }) + ) + .catch((error: Error) => + res.status(404).json({ + message: `DestinationCalendar with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - case "DELETE": - await prisma.destinationCalendar - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ message: `DestinationCalendar with id: ${safeQuery.data.id} deleted` }) - ) - .catch((error: Error) => - res - .status(404) - .json({ message: `DestinationCalendar with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } + } else res.status(401).json({ message: "Unauthorized" }); } export default withMiddleware("HTTP_GET_DELETE_PATCH")( diff --git a/pages/api/destination-calendars/index.ts b/pages/api/destination-calendars/index.ts index 3980b3e203..2b904dbc93 100644 --- a/pages/api/destination-calendars/index.ts +++ b/pages/api/destination-calendars/index.ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { DestinationCalendarResponse, DestinationCalendarsResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaDestinationCalendarBodyParams, schemaDestinationCalendarPublic, @@ -45,8 +46,10 @@ async function createOrlistAllDestinationCalendars( res: NextApiResponse ) { const { method } = req; + const userId = getCalcomUserId(res); + if (method === "GET") { - const data = await prisma.destinationCalendar.findMany(); + const data = await prisma.destinationCalendar.findMany({ where: { userId } }); const destination_calendars = data.map((destinationCalendar) => schemaDestinationCalendarPublic.parse(destinationCalendar) ); @@ -61,7 +64,7 @@ async function createOrlistAllDestinationCalendars( const safe = schemaDestinationCalendarBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body"); - const data = await prisma.destinationCalendar.create({ data: safe.data }); + const data = await prisma.destinationCalendar.create({ data: { ...safe.data, userId } }); const destination_calendar = schemaDestinationCalendarPublic.parse(data); if (destination_calendar) From ccd8637ae6601b04af0114db136fa6c63b2587d9 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 21 Apr 2022 01:30:47 +0200 Subject: [PATCH 125/658] feat: all endpoints safe --- README.md | 17 ++-- pages/api/daily-event-references/[id].ts | 105 +++++++++++++--------- pages/api/daily-event-references/index.ts | 9 +- 3 files changed, 77 insertions(+), 54 deletions(-) diff --git a/README.md b/README.md index 844008a152..9bcadef81e 100644 --- a/README.md +++ b/README.md @@ -139,11 +139,6 @@ tests/endpoint/resource.new.test.ts - Create new resource | teams | ✅ | ✅ | ✅ | ✅ | ✅ | | users | ✅ | 👤[1] | ✅ | ✅ | ✅ | -## Models missing userId relation - -- daily-event-references - - ## Models from database that are not exposed mostly because they're deemed too sensitive can be revisited if needed. most are expected to be used via cal's webapp. @@ -154,7 +149,7 @@ mostly because they're deemed too sensitive can be revisited if needed. most are - [ ] ResetPasswordRequest - [ ] VerificationToken - [ ] ReminderMail -- [ ] + ## Documentation (OpenAPI) You will see that each endpoint has a comment at the top with the annotation `@swagger` with the documentation of the endpoint, **please update it if you change the code!** This is what auto-generates the OpenAPI spec by collecting the YAML in each endpoint and parsing it in /docs alongside the json-schema (auto-generated from prisma package, not added to code but manually for now, need to fix later) @@ -171,7 +166,11 @@ in order to build and deploy properly. ## Envirorment variables -DATABASE_URL= -API_KEY_PREFIX=cal_# This can be changed per envirorment so cal_test_ for staging for example. +### Required -If you're self-hosting under our commercial license, you can use any prefix you want for api keys. either leave the default cal_ (not providing any envirorment variable) or modify it +DATABASE_URL=DATABASE_URL="postgresql://postgres:@localhost:5450/calendso" + +## Optional + +API_KEY_PREFIX=cal_# This can be changed per envirorment so cal_test_ for staging for example. +> If you're self-hosting under our commercial license, you can use any prefix you want for api keys. either leave the default cal_ (not providing any envirorment variable) or modify it diff --git a/pages/api/daily-event-references/[id].ts b/pages/api/daily-event-references/[id].ts index 17d6ced278..089e21610b 100644 --- a/pages/api/daily-event-references/[id].ts +++ b/pages/api/daily-event-references/[id].ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { DailyEventReferenceResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaDailyEventReferenceBodyParams, schemaDailyEventReferencePublic, @@ -96,53 +97,69 @@ export async function dailyEventReferenceById( const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaDailyEventReferenceBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + const userId = getCalcomUserId(res); + const userBookings = await prisma.booking.findMany({ where: { userId } }); + const userBookingIds = userBookings.map((booking) => booking.id); + const userBookingDailyEventReferences = await prisma.dailyEventReference.findMany({ + where: { bookingId: { in: userBookingIds } }, + }); + const userBookingDailyEventReferenceIds = userBookingDailyEventReferences.map( + (dailyEventReference) => dailyEventReference.id + ); + if (userBookingDailyEventReferenceIds.includes(safeQuery.data.id)) { + switch (method) { + case "GET": + await prisma.dailyEventReference + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data) => schemaDailyEventReferencePublic.parse(data)) + .then((daily_event_reference) => res.status(200).json({ daily_event_reference })) + .catch((error: Error) => + res.status(404).json({ + message: `DailyEventReference with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - switch (method) { - case "GET": - await prisma.dailyEventReference - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaDailyEventReferencePublic.parse(data)) - .then((daily_event_reference) => res.status(200).json({ daily_event_reference })) - .catch((error: Error) => - res - .status(404) - .json({ message: `DailyEventReference with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "PATCH": + if (!safeBody.success) { + throw new Error("Invalid request body"); + } + await prisma.dailyEventReference + .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) + .then((data) => schemaDailyEventReferencePublic.parse(data)) + .then((daily_event_reference) => res.status(200).json({ daily_event_reference })) + .catch((error: Error) => + res.status(404).json({ + message: `DailyEventReference with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - case "PATCH": - if (!safeBody.success) throw new Error("Invalid request body"); - await prisma.dailyEventReference - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((data) => schemaDailyEventReferencePublic.parse(data)) - .then((daily_event_reference) => res.status(200).json({ daily_event_reference })) - .catch((error: Error) => - res - .status(404) - .json({ message: `DailyEventReference with id: ${safeQuery.data.id} not found`, error }) - ); - break; + case "DELETE": + await prisma.dailyEventReference + .delete({ + where: { id: safeQuery.data.id }, + }) + .then(() => + res.status(200).json({ + message: `DailyEventReference with id: ${safeQuery.data.id} deleted`, + }) + ) + .catch((error: Error) => + res.status(404).json({ + message: `DailyEventReference with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - case "DELETE": - await prisma.dailyEventReference - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ message: `DailyEventReference with id: ${safeQuery.data.id} deleted` }) - ) - .catch((error: Error) => - res - .status(404) - .json({ message: `DailyEventReference with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } + } else res.status(401).json({ message: "Unauthorized" }); } export default withMiddleware("HTTP_GET_DELETE_PATCH")( diff --git a/pages/api/daily-event-references/index.ts b/pages/api/daily-event-references/index.ts index e3a90d6f03..8b00334b1e 100644 --- a/pages/api/daily-event-references/index.ts +++ b/pages/api/daily-event-references/index.ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { DailyEventReferenceResponse, DailyEventReferencesResponse } from "@lib/types"; +import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaDailyEventReferenceBodyParams, schemaDailyEventReferencePublic, @@ -45,8 +46,14 @@ async function createOrlistAllDailyEventReferences( res: NextApiResponse ) { const { method } = req; + const userId = getCalcomUserId(res); + const userBookings = await prisma.booking.findMany({ where: { userId } }); + const userBookingIds = userBookings.map((booking) => booking.id); + if (method === "GET") { - const data = await prisma.dailyEventReference.findMany(); + const data = await prisma.dailyEventReference.findMany({ + where: { bookingId: { in: userBookingIds } }, + }); const daily_event_references = data.map((dailyEventReference) => schemaDailyEventReferencePublic.parse(dailyEventReference) ); From 00bd2ed6e1030479abb55f58b55681c5e0c543f1 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 21 Apr 2022 01:31:36 +0200 Subject: [PATCH 126/658] remove old tests for now, add new tests later --- tests/bookings/[id]/booking.id.edit.test.ts | 116 ------------------ tests/bookings/[id]/booking.id.index.test.ts | 84 ------------- tests/bookings/booking.index.test.ts | 39 ------ tests/bookings/booking.new.test.ts | 77 ------------ .../[id]/event-type.id.edit.test.ts | 116 ------------------ .../[id]/event-type.id.index.test.ts | 75 ----------- tests/event-types/event-type.index.test.ts | 32 ----- tests/event-types/event-type.new.test.ts | 70 ----------- tests/teams/[id]/team.id.edit.test.ts | 107 ---------------- tests/teams/[id]/team.id.index.test.ts | 75 ----------- tests/users/[id]/user.id.edit.test.ts | 116 ------------------ tests/users/[id]/user.id.index.test.ts | 83 ------------- 12 files changed, 990 deletions(-) delete mode 100644 tests/bookings/[id]/booking.id.edit.test.ts delete mode 100644 tests/bookings/[id]/booking.id.index.test.ts delete mode 100644 tests/bookings/booking.index.test.ts delete mode 100644 tests/bookings/booking.new.test.ts delete mode 100644 tests/event-types/[id]/event-type.id.edit.test.ts delete mode 100644 tests/event-types/[id]/event-type.id.index.test.ts delete mode 100644 tests/event-types/event-type.index.test.ts delete mode 100644 tests/event-types/event-type.new.test.ts delete mode 100644 tests/teams/[id]/team.id.edit.test.ts delete mode 100644 tests/teams/[id]/team.id.index.test.ts delete mode 100644 tests/users/[id]/user.id.edit.test.ts delete mode 100644 tests/users/[id]/user.id.index.test.ts diff --git a/tests/bookings/[id]/booking.id.edit.test.ts b/tests/bookings/[id]/booking.id.edit.test.ts deleted file mode 100644 index 8bf32eb0e5..0000000000 --- a/tests/bookings/[id]/booking.id.edit.test.ts +++ /dev/null @@ -1,116 +0,0 @@ -import handleBookingEdit from "@api/bookings/[id]/edit"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -describe("PATCH /api/bookings/[id]/edit with valid id and body updates an booking", () => { - it("returns a message with the specified bookings", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "2", - }, - body: { - title: "Updated title", - slug: "updated-slug", - length: 1, - }, - }); - const booking = await prisma.booking.findUnique({ where: { id: parseInt(req.query.id) } }); - await handleBookingEdit(req, res); - - expect(res._getStatusCode()).toBe(200); - if (booking) booking.title = "Updated title"; - expect(JSON.parse(res._getData())).toStrictEqual({ data: booking }); - }); -}); - -describe("PATCH /api/bookings/[id]/edit with invalid id returns 404", () => { - it("returns a message with the specified bookings", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "0", - }, - body: { - title: "Updated title", - slug: "updated-slug", - length: 1, - }, - }); - const booking = await prisma.booking.findUnique({ where: { id: parseInt(req.query.id) } }); - await handleBookingEdit(req, res); - - expect(res._getStatusCode()).toBe(404); - if (booking) booking.title = "Updated title"; - expect(JSON.parse(res._getData())).toStrictEqual({ - error: { - clientVersion: "3.10.0", - code: "P2025", - meta: { - cause: "Record to update not found.", - }, - }, - message: "Event type with ID 0 not found and wasn't updated", - }); - }); -}); - -describe("PATCH /api/bookings/[id]/edit with valid id and no body returns 400 error and zod validation errors", () => { - it("returns a message with the specified bookings", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "2", - }, - }); - await handleBookingEdit(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "invalid_type", - expected: "string", - message: "Required", - path: ["title"], - received: "undefined", - }, - { - code: "invalid_type", - expected: "string", - message: "Required", - path: ["slug"], - received: "undefined", - }, - { - code: "invalid_type", - expected: "number", - message: "Required", - path: ["length"], - received: "undefined", - }, - ]); - }); -}); - -describe("POST /api/bookings/[id]/edit fails, only PATCH allowed", () => { - it("returns a message with the specified bookings", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "1", - }, - body: { - title: "Updated title", - slug: "updated-slug", - length: 1, - }, - }); - await handleBookingEdit(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ - message: "Only PATCH Method allowed for updating bookings", - }); - }); -}); diff --git a/tests/bookings/[id]/booking.id.index.test.ts b/tests/bookings/[id]/booking.id.index.test.ts deleted file mode 100644 index 4a2ff0ca0c..0000000000 --- a/tests/bookings/[id]/booking.id.index.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -import handleBooking from "@api/bookings/[id]"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -import { stringifyISODate } from "@lib/utils/stringifyISODate"; - -describe("GET /api/bookings/[id] with valid id as string returns an booking", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: "1", - }, - }); - const booking = await prisma.booking.findUnique({ where: { id: 1 } }); - await handleBooking(req, res); - - expect(res._getStatusCode()).toBe(200); - expect(JSON.parse(res._getData())).toEqual({ - data: { - ...booking, - createdAt: stringifyISODate(booking?.createdAt), - startTime: stringifyISODate(booking?.startTime), - endTime: stringifyISODate(booking?.endTime), - }, - }); - }); -}); - -// This can never happen under our normal nextjs setup where query is always a string | string[]. -// But seemed a good example for testing an error validation -describe("GET /api/bookings/[id] errors if query id is number, requires a string", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: 1, // passing query as a number, which should fail as nextjs will try to parse it as a string - }, - }); - await handleBooking(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "invalid_type", - expected: "string", - received: "number", - path: ["id"], - message: "Expected string, received number", - }, - ]); - }); -}); - -describe("GET /api/bookings/[id] an id not present in db like 0, throws 404 not found", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: "0", // There's no booking type with id 0 - }, - }); - await handleBooking(req, res); - - expect(res._getStatusCode()).toBe(404); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Event type not found" }); - }); -}); - -describe("POST /api/bookings/[id] fails, only GET allowed", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "1", - }, - }); - await handleBooking(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); - }); -}); diff --git a/tests/bookings/booking.index.test.ts b/tests/bookings/booking.index.test.ts deleted file mode 100644 index 957b749b88..0000000000 --- a/tests/bookings/booking.index.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import handleApiKeys from "@api/api-keys"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -import { stringifyISODate } from "@lib/utils/stringifyISODate"; - -describe("GET /api/api-keys without any params", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "GET", - query: {}, - }); - let apiKeys = await prisma.apiKey.findMany(); - await handleApiKeys(req, res); - - expect(res._getStatusCode()).toBe(200); - apiKeys = apiKeys.map( - (apiKey) => - (apiKey = { - ...apiKey, - createdAt: stringifyISODate(apiKey?.createdAt), - expiresAt: stringifyISODate(apiKey?.expiresAt), - }) - ); - expect(JSON.parse(res._getData())).toStrictEqual(JSON.parse(JSON.stringify({ data: { ...apiKeys } }))); - }); -}); - -describe("POST /api/api-keys/ fails, only GET allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - }); - await handleApiKeys(req, res); - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); - }); -}); diff --git a/tests/bookings/booking.new.test.ts b/tests/bookings/booking.new.test.ts deleted file mode 100644 index 339b4c146b..0000000000 --- a/tests/bookings/booking.new.test.ts +++ /dev/null @@ -1,77 +0,0 @@ -import handleNewApiKey from "@api/api-keys/new"; -import { createMocks } from "node-mocks-http"; - -describe("POST /api/api-keys/new with a note", () => { - it("returns a 201, and the created api key", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - body: { - note: "Updated note", - }, - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(201); - expect(JSON.parse(res._getData()).data.note).toStrictEqual("Updated note"); - }); -}); - -describe("POST /api/api-keys/new with a slug param", () => { - it("returns error 400, and the details about invalid slug body param", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - body: { - note: "Updated note", - slug: "slug", - }, - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "unrecognized_keys", - keys: ["slug"], - message: "Unrecognized key(s) in object: 'slug'", - path: [], - }, - ]); - }); -}); - -describe("GET /api/api-keys/new fails, only POST allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "GET", // This POST method is not allowed - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ error: "Only POST Method allowed" }); - }); -}); - -// FIXME: test 405 when prisma fails look for how to test prisma errors -describe("GET /api/api-keys/new fails, only POST allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - body: { - nonExistentParam: true, - // note: '123', - // slug: 12, - }, - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "unrecognized_keys", - keys: ["nonExistentParam"], - message: "Unrecognized key(s) in object: 'nonExistentParam'", - path: [], - }, - ]); - }); -}); diff --git a/tests/event-types/[id]/event-type.id.edit.test.ts b/tests/event-types/[id]/event-type.id.edit.test.ts deleted file mode 100644 index e88bcb9b49..0000000000 --- a/tests/event-types/[id]/event-type.id.edit.test.ts +++ /dev/null @@ -1,116 +0,0 @@ -import handleEventTypeEdit from "@api/event-types/[id]/edit"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -describe("PATCH /api/event-types/[id]/edit with valid id and body updates an event-type", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "2", - }, - body: { - title: "Updated title", - slug: "updated-slug", - length: 1, - }, - }); - const event = await prisma.eventType.findUnique({ where: { id: parseInt(req.query.id) } }); - await handleEventTypeEdit(req, res); - - expect(res._getStatusCode()).toBe(200); - if (event) event.title = "Updated title"; - expect(JSON.parse(res._getData())).toStrictEqual({ data: event }); - }); -}); - -describe("PATCH /api/event-types/[id]/edit with invalid id returns 404", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "0", - }, - body: { - title: "Updated title", - slug: "updated-slug", - length: 1, - }, - }); - const event = await prisma.eventType.findUnique({ where: { id: parseInt(req.query.id) } }); - await handleEventTypeEdit(req, res); - - expect(res._getStatusCode()).toBe(404); - if (event) event.title = "Updated title"; - expect(JSON.parse(res._getData())).toStrictEqual({ - error: { - clientVersion: "3.10.0", - code: "P2025", - meta: { - cause: "Record to update not found.", - }, - }, - message: "Event type with ID 0 not found and wasn't updated", - }); - }); -}); - -describe("PATCH /api/event-types/[id]/edit with valid id and no body returns 400 error and zod validation errors", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "2", - }, - }); - await handleEventTypeEdit(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "invalid_type", - expected: "string", - message: "Required", - path: ["title"], - received: "undefined", - }, - { - code: "invalid_type", - expected: "string", - message: "Required", - path: ["slug"], - received: "undefined", - }, - { - code: "invalid_type", - expected: "number", - message: "Required", - path: ["length"], - received: "undefined", - }, - ]); - }); -}); - -describe("POST /api/event-types/[id]/edit fails, only PATCH allowed", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "1", - }, - body: { - title: "Updated title", - slug: "updated-slug", - length: 1, - }, - }); - await handleEventTypeEdit(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ - message: "Only PATCH Method allowed for updating event-types", - }); - }); -}); diff --git a/tests/event-types/[id]/event-type.id.index.test.ts b/tests/event-types/[id]/event-type.id.index.test.ts deleted file mode 100644 index bb54d5963f..0000000000 --- a/tests/event-types/[id]/event-type.id.index.test.ts +++ /dev/null @@ -1,75 +0,0 @@ -import handleEventType from "@api/event-types/[id]"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -describe("GET /api/event-types/[id] with valid id as string returns an event-type", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: "1", - }, - }); - const event = await prisma.eventType.findUnique({ where: { id: 1 } }); - await handleEventType(req, res); - - expect(res._getStatusCode()).toBe(200); - expect(JSON.parse(res._getData())).toStrictEqual({ data: event }); - }); -}); - -// This can never happen under our normal nextjs setup where query is always a string | string[]. -// But seemed a good example for testing an error validation -describe("GET /api/event-types/[id] errors if query id is number, requires a string", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: 1, // passing query as a number, which should fail as nextjs will try to parse it as a string - }, - }); - await handleEventType(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "invalid_type", - expected: "string", - received: "number", - path: ["id"], - message: "Expected string, received number", - }, - ]); - }); -}); - -describe("GET /api/event-types/[id] an id not present in db like 0, throws 404 not found", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: "0", // There's no event type with id 0 - }, - }); - await handleEventType(req, res); - - expect(res._getStatusCode()).toBe(404); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Event type not found" }); - }); -}); - -describe("POST /api/event-types/[id] fails, only GET allowed", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "1", - }, - }); - await handleEventType(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); - }); -}); diff --git a/tests/event-types/event-type.index.test.ts b/tests/event-types/event-type.index.test.ts deleted file mode 100644 index 7a63a59a5d..0000000000 --- a/tests/event-types/event-type.index.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import handleApiKeys from "@api/event-types"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -// import {stringifyISODate} from "@lib/utils/stringifyISODate"; - -describe("GET /api/event-types without any params", () => { - it("returns a message with the specified eventTypes", async () => { - const { req, res } = createMocks({ - method: "GET", - query: {}, - }); - const eventTypes = await prisma.eventType.findMany(); - await handleApiKeys(req, res); - - expect(res._getStatusCode()).toBe(200); - // eventTypes = eventTypes.map(eventType => (eventType = {...eventType, createdAt: stringifyISODate(eventType?.createdAt), expiresAt: stringifyISODate(eventType?.expiresAt)})); - expect(JSON.parse(res._getData())).toStrictEqual(JSON.parse(JSON.stringify({ data: { ...eventTypes } }))); - }); -}); - -describe("POST /api/event-types/ fails, only GET allowed", () => { - it("returns a message with the specified eventTypes", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - }); - await handleApiKeys(req, res); - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); - }); -}); diff --git a/tests/event-types/event-type.new.test.ts b/tests/event-types/event-type.new.test.ts deleted file mode 100644 index a79209ec03..0000000000 --- a/tests/event-types/event-type.new.test.ts +++ /dev/null @@ -1,70 +0,0 @@ -import handleNewApiKey from "@api/api-keys/new"; -import { createMocks } from "node-mocks-http"; - -describe("POST /api/api-keys/new with a note", () => { - it("returns a 201, and the created api key", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - body: { - note: "Updated note", - }, - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(201); - expect(JSON.parse(res._getData()).data.note).toStrictEqual("Updated note"); - }); -}); - -describe("POST /api/api-keys/new with a slug param", () => { - it("returns error 400, and the details about invalid slug body param", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - body: { - note: "Updated note", - slug: "slug", - }, - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "unrecognized_keys", - keys: ["slug"], - message: "Unrecognized key(s) in object: 'slug'", - path: [], - }, - ]); - }); -}); - -describe("GET /api/api-keys/new fails, only POST allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "GET", // This POST method is not allowed - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ error: "Only POST Method allowed" }); - }); -}); - -// FIXME: test 405 when prisma fails look for how to test prisma errors -// describe("GET /api/api-keys/new fails, only POST allowed", () => { -// it("returns a message with the specified apiKeys", async () => { -// const { req, res } = createMocks({ -// method: "POST", // This POST method is not allowed -// body: { -// fail: true -// // note: '123', -// // slug: 12, -// }, -// }); -// await handleNewApiKey(req, res); - -// expect(res._getStatusCode()).toBe(400); -// expect(JSON.parse(res._getData())).toStrictEqual({ error: "Only POST Method allowed" }); -// }); -// }); diff --git a/tests/teams/[id]/team.id.edit.test.ts b/tests/teams/[id]/team.id.edit.test.ts deleted file mode 100644 index 101deaa06e..0000000000 --- a/tests/teams/[id]/team.id.edit.test.ts +++ /dev/null @@ -1,107 +0,0 @@ -import handleTeamEdit from "@api/teams/[id]/edit"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -describe("PATCH /api/teams/[id]/edit with valid id and body updates a team", () => { - it("returns a message with the specified teams", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "1", - }, - body: { - name: "Updated team", - slug: "updated-team", - }, - }); - const team = await prisma.team.findUnique({ where: { id: parseInt(req.query.id) } }); - await handleTeamEdit(req, res); - - expect(res._getStatusCode()).toBe(200); - // if (team) team.name = "Updated name"; - expect(JSON.parse(res._getData())).toStrictEqual({ data: team }); - }); -}); - -describe("PATCH /api/teams/[id]/edit with invalid id returns 404", () => { - it("returns a message with the specified teams", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "0", - }, - body: { - name: "Updated name", - slug: "updated-slug", - }, - }); - const team = await prisma.team.findUnique({ where: { id: parseInt(req.query.id) } }); - await handleTeamEdit(req, res); - - expect(res._getStatusCode()).toBe(404); - expect(JSON.parse(res._getData())).toStrictEqual({ - error: { - clientVersion: "3.10.0", - code: "P2025", - meta: { - cause: "Record to update not found.", - }, - }, - message: "Event type with ID 0 not found and wasn't updated", - }); - }); -}); - -describe("PATCH /api/teams/[id]/edit with valid id and no body returns 400 error and zod validation errors", () => { - it("returns a message with the specified teams", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "2", - }, - }); - await handleTeamEdit(req, res); - - expect(res._getStatusCode()).toBe(400); - - // Ugly parsing of zod validation errors, not for final production but works for testing - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "invalid_type", - expected: "string", - message: "Required", - path: ["slug"], - received: "undefined", - }, - { - code: "invalid_type", - expected: "string", - message: "Required", - path: ["name"], - received: "undefined", - }, - ]); - }); -}); - -describe("POST /api/teams/[id]/edit fails, only PATCH allowed", () => { - it("returns a message with the specified teams", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "1", - }, - body: { - name: "Updated name", - slug: "updated-slug", - }, - }); - await handleTeamEdit(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ - message: "Only PATCH Method allowed for updating teams", - }); - }); -}); diff --git a/tests/teams/[id]/team.id.index.test.ts b/tests/teams/[id]/team.id.index.test.ts deleted file mode 100644 index 016f7ec604..0000000000 --- a/tests/teams/[id]/team.id.index.test.ts +++ /dev/null @@ -1,75 +0,0 @@ -import handleTeam from "@api/teams/[id]"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -describe("GET /api/teams/[id] with valid id as string returns an team-type", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: "1", - }, - }); - const team = await prisma.team.findUnique({ where: { id: 1 } }); - await handleTeam(req, res); - - expect(res._getStatusCode()).toBe(200); - expect(JSON.parse(res._getData())).toStrictEqual({ data: team }); - }); -}); - -// This can never happen under our normal nextjs setup where query is always a string | string[]. -// But seemed a good example for testing an error validation -describe("GET /api/teams/[id] errors if query id is number, requires a string", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: 1, // passing query as a number, which should fail as nextjs will try to parse it as a string - }, - }); - await handleTeam(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "invalid_type", - expected: "string", - received: "number", - path: ["id"], - message: "Expected string, received number", - }, - ]); - }); -}); - -describe("GET /api/teams/[id] an id not present in db like 0, throws 404 not found", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: "0", // There's no team type with id 0 - }, - }); - await handleTeam(req, res); - - expect(res._getStatusCode()).toBe(404); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Event type not found" }); - }); -}); - -describe("POST /api/teams/[id] fails, only GET allowed", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "1", - }, - }); - await handleTeam(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); - }); -}); diff --git a/tests/users/[id]/user.id.edit.test.ts b/tests/users/[id]/user.id.edit.test.ts deleted file mode 100644 index e88bcb9b49..0000000000 --- a/tests/users/[id]/user.id.edit.test.ts +++ /dev/null @@ -1,116 +0,0 @@ -import handleEventTypeEdit from "@api/event-types/[id]/edit"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -describe("PATCH /api/event-types/[id]/edit with valid id and body updates an event-type", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "2", - }, - body: { - title: "Updated title", - slug: "updated-slug", - length: 1, - }, - }); - const event = await prisma.eventType.findUnique({ where: { id: parseInt(req.query.id) } }); - await handleEventTypeEdit(req, res); - - expect(res._getStatusCode()).toBe(200); - if (event) event.title = "Updated title"; - expect(JSON.parse(res._getData())).toStrictEqual({ data: event }); - }); -}); - -describe("PATCH /api/event-types/[id]/edit with invalid id returns 404", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "0", - }, - body: { - title: "Updated title", - slug: "updated-slug", - length: 1, - }, - }); - const event = await prisma.eventType.findUnique({ where: { id: parseInt(req.query.id) } }); - await handleEventTypeEdit(req, res); - - expect(res._getStatusCode()).toBe(404); - if (event) event.title = "Updated title"; - expect(JSON.parse(res._getData())).toStrictEqual({ - error: { - clientVersion: "3.10.0", - code: "P2025", - meta: { - cause: "Record to update not found.", - }, - }, - message: "Event type with ID 0 not found and wasn't updated", - }); - }); -}); - -describe("PATCH /api/event-types/[id]/edit with valid id and no body returns 400 error and zod validation errors", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "2", - }, - }); - await handleEventTypeEdit(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "invalid_type", - expected: "string", - message: "Required", - path: ["title"], - received: "undefined", - }, - { - code: "invalid_type", - expected: "string", - message: "Required", - path: ["slug"], - received: "undefined", - }, - { - code: "invalid_type", - expected: "number", - message: "Required", - path: ["length"], - received: "undefined", - }, - ]); - }); -}); - -describe("POST /api/event-types/[id]/edit fails, only PATCH allowed", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "1", - }, - body: { - title: "Updated title", - slug: "updated-slug", - length: 1, - }, - }); - await handleEventTypeEdit(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ - message: "Only PATCH Method allowed for updating event-types", - }); - }); -}); diff --git a/tests/users/[id]/user.id.index.test.ts b/tests/users/[id]/user.id.index.test.ts deleted file mode 100644 index bf79c38143..0000000000 --- a/tests/users/[id]/user.id.index.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -import handleUser from "@api/users/[id]"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -import { stringifyISODate } from "@lib/utils/stringifyISODate"; - -describe("GET /api/users/[id] with valid id as string returns an user-type", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: "1", - }, - }); - const user = await prisma.user.findUnique({ where: { id: 1 } }); - await handleUser(req, res); - - expect(res._getStatusCode()).toBe(200); - expect(JSON.parse(res._getData())).toEqual({ - data: { - ...user, - createdDate: stringifyISODate(user?.createdDate), - emailVerified: stringifyISODate(user?.emailVerified), - }, - }); - }); -}); - -// This can never happen under our normal nextjs setup where query is always a string | string[]. -// But seemed a good example for testing an error validation -describe("GET /api/users/[id] errors if query id is number, requires a string", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: 1, // passing query as a number, which should fail as nextjs will try to parse it as a string - }, - }); - await handleUser(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "invalid_type", - expected: "string", - received: "number", - path: ["id"], - message: "Expected string, received number", - }, - ]); - }); -}); - -describe("GET /api/users/[id] an id not present in db like 0, throws 404 not found", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: "0", // There's no user type with id 0 - }, - }); - await handleUser(req, res); - - expect(res._getStatusCode()).toBe(404); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Event type not found" }); - }); -}); - -describe("POST /api/users/[id] fails, only GET allowed", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "1", - }, - }); - await handleUser(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); - }); -}); From b8d452bda0a84b76eb71429255617c3bd061481d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 21 Apr 2022 01:46:15 +0200 Subject: [PATCH 127/658] feat: update readme --- README.md | 42 ------------------------------------------ templates/README.md | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 42 deletions(-) create mode 100644 templates/README.md diff --git a/README.md b/README.md index 81e06fa2ae..c642e60422 100644 --- a/README.md +++ b/README.md @@ -34,46 +34,4 @@ We aim to provide a fully tested API for our peace of mind, this is accomplished Since this will only support an API, we redirect the requests to root to the /api folder. We also added a redirect for future-proofing API versioning when we might need it, without having to resort to dirty hacks like a v1/v2 folders with lots of duplicated code, instead we redirect /api/v*/:rest to /api/:rest?version=* -The priority is the booking-related API routes so people can build their own booking flow, then event type management routes, then availability management routes etc -How to add a new model or endpoint - -Basically there's three places of the codebase you need to think about for each feature. - -/pages/api/ - -- This is the most important one, and where your endpoint will live. You will leverage nextjs dynamic routes and expose one file for each endpoint you want to support ideally. - -## How the codebase is organized. - -## The example resource -model- and it's endpoints - -### `pages/api/endpoint/` - -GET pages/api/endpoint/index.ts - Read All of your resource -POST pages/api/endpoint/new.ts - Create new resource - -### `pages/api/endpoint/[id]/` - -GET pages/api/endpoint/[id]/index.ts - Read All of your resource -PATCH pages/api/endpoint/[id]/edit.ts - Create new resource -DELETE pages/api/endpoint/[id]/delete.ts - Create new resource - -## `/tests/` - -This is where all your endpoint's tests live, we mock prisma calls. We aim for at least 50% global coverage. Test each of your endpoints. - -### `/tests/endpoint/` - -/tests/endpoint/resource.index.test.ts - Test for your pages/api/endpoint/index.ts file -tests/endpoint/resource.new.test.ts - Create new resource - -### `/tests/endpoint/[id]/` - -`/tests/endpoint/[id]/resource.index.test.ts` - Read All of your resource -`/tests/endpoint/[id]/resource.edit.test.ts` - Create new resource -`/tests/endpoint/[id]/resource.delete.test.ts` - Create new resource - -## `/lib/validations/yourEndpoint.ts` - -- This is where our model validations, live, we try to make a 1:1 for db models, and also extract out any re-usable code into the /lib/validations/shared/ sub-folder. diff --git a/templates/README.md b/templates/README.md new file mode 100644 index 0000000000..c44fe4ef59 --- /dev/null +++ b/templates/README.md @@ -0,0 +1,41 @@ +# How to add a new model or endpoint + +Basically there's three places of the codebase you need to think about for each feature. + +/pages/api/ + +- This is the most important one, and where your endpoint will live. You will leverage nextjs dynamic routes and expose one file for each endpoint you want to support ideally. + +## How the codebase is organized. + +## The example resource -model- and it's endpoints + +### `pages/api/endpoint/` + +GET pages/api/endpoint/index.ts - Read All of your resource +POST pages/api/endpoint/new.ts - Create new resource + +### `pages/api/endpoint/[id]/` + +GET pages/api/endpoint/[id]/index.ts - Read All of your resource +PATCH pages/api/endpoint/[id]/edit.ts - Create new resource +DELETE pages/api/endpoint/[id]/delete.ts - Create new resource + +## `/tests/` + +This is where all your endpoint's tests live, we mock prisma calls. We aim for at least 50% global coverage. Test each of your endpoints. + +### `/tests/endpoint/` + +/tests/endpoint/resource.index.test.ts - Test for your pages/api/endpoint/index.ts file +tests/endpoint/resource.new.test.ts - Create new resource + +### `/tests/endpoint/[id]/` + +`/tests/endpoint/[id]/resource.index.test.ts` - Read All of your resource +`/tests/endpoint/[id]/resource.edit.test.ts` - Create new resource +`/tests/endpoint/[id]/resource.delete.test.ts` - Create new resource + +## `/lib/validations/yourEndpoint.ts` + +- This is where our model validations, live, we try to make a 1:1 for db models, and also extract out any re-usable code into the /lib/validations/shared/ sub-folder. From c08f5038075a700872e05b2e1a025224bd86504b Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 21 Apr 2022 01:55:44 +0200 Subject: [PATCH 128/658] update readme round 2 --- README.md | 157 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 145 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index c642e60422..40183411f5 100644 --- a/README.md +++ b/README.md @@ -1,21 +1,109 @@ # Cal.com Public API (Enterprise Only) -## This will be the new public enterprise-only API +This is the public REST api for cal.com. It exposes CRUD Endpoints of all our most important resources. It makes it easy for anyone to integrate with cal at the programming level. -This is the public REST api for cal.com +## Stack -## NextJS + TypeScript +- NextJS +- TypeScript +- Prisma +- No tRPC ** -It's a barebones **NextJS** + **TypeScript** project leveraging the nextJS API with a pages/api folder. +** (for now) We hook directly into prisma client, but probably should look into adding a new @calcom/trpc package that adds pagination and such stuff and can be shared between webapp and API. -- `api.cal.com/v1` -- `api.cal.com/api/v1` +## Development + +### Setup + +1. Clone the main repo (NOT THIS ONE) + + ```sh + git clone --recurse-submodules -j8 https://github.com/calcom/cal.com.git + ``` + +1. Go to the project folder + + ```sh + cd cal.com + ``` + +1. Copy `apps/api/.env.example` to `apps/api/.env` + + ```sh + cp apps/api/.env.example apps/api/.env + cp packages/prisma/.env.example packages/prisma/.env + ``` + +1. Install packages with yarn + + ```sh + yarn + ``` + +1. Start developing + + ```sh + yarn workspace @calcom/api dev + ``` + +1. Open [http://localhost:3002](http://localhost:3002) with your browser to see the result. + +## API Authentication (API Keys) + +The API requires a valid apiKey query param to be passed: +You can generate them at + +For example: + +```sh +GET https://api.cal.com/v1/users?apiKey={INSERT_YOUR_CAL.COM_API_KEY_HERE} +``` + +API Keys optionally may have expiry dates, if they are expired they won't work. If you create an apiKey without a userId relation, it won't work either for now as it relies on it to establish the current authenticated user. + +In the future we might add support for header Beaer Auth if we need to or our customers require it. + +## Next.config.js + +### Redirects + +Since this is an API only project, we don't want to have to type /api/ in all the routes, and so redirect all traffic to api, so a call to `api.cal.com/v1` will resolve to `api.cal.com/api/v1` + +Likewise, v1 is added as param query called version to final /api call so we don't duplicate endpoints in the future for versioning if needed. + +### Transpiling locally shared monorepo modules + +We're calling several packages from monorepo, this need to be transpiled before building since are not available as regular npm packages. That's what withTM does. + +```sh + "@calcom/app-store", + "@calcom/prisma", + "@calcom/lib", + "@calcom/ee", +``` ## API Endpoint Validation -### Zod +We validate that only the supported methods are accepted at each endpoint, so in -The API uses `zod` library like our main web repo. It validates that either GET query parameters or POST body content's are valid and up to our spec. It gives appropiate errors when parsing result's with schemas. +- **/endpoint**: you can only [GET] (all) and [POST] (create new) +- **/endpoint/id**: you can read create and edit [GET, PATCH, DELETE] + +### Zod Validations + +The API uses `zod` library like our main web repo. It validates that either GET query parameters or POST body content's are valid and up to our spec. It gives errors when parsing result's with schemas and failing validation. + +We use it in several ways, but mainly, we first import the auto-generated schema from @calcom/prisma for each model, which lives in `lib/validations/` + +We have some shared validations which several resources require, like baseApiParams which parses apiKey in all requests, or querIdAsString or TransformParseInt which deal with the id's coming from req.query. + +- **[*]BaseBodyParams** that omits any values from the model that are too sensitive or we don't want to pick when creating a new resource like id, userId, etc.. (those are gotten from context or elswhere) + +- **[*]Public** that also omits any values that we don't want to expose when returning the model as a response, which we parse against before returning all resources. + +- **[*]BodyParams** which merges both `[*]BaseBodyParams.merge([*]RequiredParams);` + +- **withValid[*]** which is currently not being much used because is only useful in only post endpoints (we do post/get all in same file). This would validate the req.body of a POST call to API against our BaseBodyParams validation ### Next Validations @@ -27,11 +115,56 @@ We also use this useful helper library that let's us wrap our endpoints in a val We aim to provide a fully tested API for our peace of mind, this is accomplished by using jest + node-mocks-http -## Next.config.js +## Endpoints matrix -### Redirects +| resource | get [id] | get all | create | edit | delete | +|--------------------------|----------|----------|---------|-------|--------| +| attendees | ✅ | ✅ | ✅ | ✅ | ✅ | +| availabilities | ✅ | ✅ | ✅ | ✅ | ✅ | +| booking-references | ✅ | ✅ | ✅ | ✅ | ✅ | +| daily-event-references | ✅ | ✅ | ✅ | ✅ | ✅ | +| destination-calendars | ✅ | ✅ | ✅ | ✅ | ✅ | +| event-type-custom-inputs | ✅ | ✅ | ✅ | ✅ | ✅ | +| event-types | ✅ | ✅ | ✅ | ✅ | ✅ | +| memberships | ✅ | ✅ | ✅ | ✅ | ✅ | +| payments | ✅ | ✅ | ❌ | ❌ | ❌ | +| schedules | ✅ | ✅ | ✅ | ✅ | ✅ | +| selected-calendars | ✅ | ✅ | ✅ | ✅ | ✅ | +| teams | ✅ | ✅ | ✅ | ✅ | ✅ | +| users | ✅ | 👤[1] | ✅ | ✅ | ✅ | -Since this will only support an API, we redirect the requests to root to the /api folder. -We also added a redirect for future-proofing API versioning when we might need it, without having to resort to dirty hacks like a v1/v2 folders with lots of duplicated code, instead we redirect /api/v*/:rest to /api/:rest?version=* +## Models from database that are not exposed +mostly because they're deemed too sensitive can be revisited if needed. most are expected to be used via cal's webapp. +- [ ] Api Keys +- [ ] Credentials +- [ ] Webhooks +- [ ] ResetPasswordRequest +- [ ] VerificationToken +- [ ] ReminderMail + +## Documentation (OpenAPI) + +You will see that each endpoint has a comment at the top with the annotation `@swagger` with the documentation of the endpoint, **please update it if you change the code!** This is what auto-generates the OpenAPI spec by collecting the YAML in each endpoint and parsing it in /docs alongside the json-schema (auto-generated from prisma package, not added to code but manually for now, need to fix later) + +### @calcom/apps/swagger + +The documentation of the API lives inside the code, and it's auto-generated, the only endpoints that return without a valid apiKey are the homepage, with a JSON message redirecting you to the docs. and the /docs endpoint, which returns the OpenAPI 3.0 JSON Spec. Which SwaggerUi then consumes and generates the docs on. + +## Deployment + +`scripts/vercel-deploy.sh` +The API is deployed to vercel.com, it uses a similar deployment script to website or webapp, and requires transpilation of several shared packages that are part of our turborepo ["app-store", "prisma", "lib", "ee"] +in order to build and deploy properly. + +## Envirorment variables + +### Required + +DATABASE_URL=DATABASE_URL="postgresql://postgres:@localhost:5450/calendso" + +## Optional + +API_KEY_PREFIX=cal_# This can be changed per envirorment so cal_test_ for staging for example. +> If you're self-hosting under our commercial license, you can use any prefix you want for api keys. either leave the default cal_ (not providing any envirorment variable) or modify it From 8437a284a83cfe9f2e0b8f55354341dd41caccb3 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 21 Apr 2022 01:57:32 +0200 Subject: [PATCH 129/658] update readme round 2b --- README.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/README.md b/README.md index 40183411f5..19ee4a65f5 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,6 @@ This is the public REST api for cal.com. It exposes CRUD Endpoints of all our mo - NextJS - TypeScript - Prisma -- No tRPC ** - -** (for now) We hook directly into prisma client, but probably should look into adding a new @calcom/trpc package that adds pagination and such stuff and can be shared between webapp and API. ## Development @@ -75,7 +72,7 @@ Likewise, v1 is added as param query called version to final /api call so we don We're calling several packages from monorepo, this need to be transpiled before building since are not available as regular npm packages. That's what withTM does. -```sh +```js "@calcom/app-store", "@calcom/prisma", "@calcom/lib", From cac972eb15adf345e39e833039a37f23741cb0c0 Mon Sep 17 00:00:00 2001 From: alannnc Date: Wed, 20 Apr 2022 18:14:23 -0600 Subject: [PATCH 130/658] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 19ee4a65f5..0a7997d6e8 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ GET https://api.cal.com/v1/users?apiKey={INSERT_YOUR_CAL.COM_API_KEY_HERE} API Keys optionally may have expiry dates, if they are expired they won't work. If you create an apiKey without a userId relation, it won't work either for now as it relies on it to establish the current authenticated user. -In the future we might add support for header Beaer Auth if we need to or our customers require it. +In the future we might add support for header Bearer Auth if we need to or our customers require it. ## Next.config.js From cb4f0a9cd0d886c3c3e830fdb1a25464aa9b4fdd Mon Sep 17 00:00:00 2001 From: alannnc Date: Wed, 20 Apr 2022 18:15:20 -0600 Subject: [PATCH 131/658] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0a7997d6e8..f7e74712c8 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ GET https://api.cal.com/v1/users?apiKey={INSERT_YOUR_CAL.COM_API_KEY_HERE} API Keys optionally may have expiry dates, if they are expired they won't work. If you create an apiKey without a userId relation, it won't work either for now as it relies on it to establish the current authenticated user. -In the future we might add support for header Bearer Auth if we need to or our customers require it. +In the future we might add support for header Bearer Auth if we need to or if our customers require it. ## Next.config.js From a2cdb04985bef4c6130c58a57af2a536e0576b93 Mon Sep 17 00:00:00 2001 From: alannnc Date: Wed, 20 Apr 2022 18:19:48 -0600 Subject: [PATCH 132/658] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f7e74712c8..15cc019306 100644 --- a/README.md +++ b/README.md @@ -106,7 +106,7 @@ We have some shared validations which several resources require, like baseApiPar [Next-Validations Docs](https://next-validations.productsway.com/) [Next-Validations Repo](https://github.com/jellydn/next-validations) -We also use this useful helper library that let's us wrap our endpoints in a validate HOC that checks the req against our validation schema built out with zod for either query and / or body's requests. +We also use this useful helper library that let us wrap our endpoints in a validate HOC that checks the req against our validation schema built out with zod for either query and / or body's requests. ## Testing with Jest + node-mocks-http @@ -132,7 +132,7 @@ We aim to provide a fully tested API for our peace of mind, this is accomplished ## Models from database that are not exposed -mostly because they're deemed too sensitive can be revisited if needed. most are expected to be used via cal's webapp. +mostly because they're deemed too sensitive can be revisited if needed. Also they are expected to be used via cal's webapp. - [ ] Api Keys - [ ] Credentials From 3c9f6f2db1bd7b3c6e21b25a06830291d02e50c9 Mon Sep 17 00:00:00 2001 From: alannnc Date: Wed, 20 Apr 2022 18:34:27 -0600 Subject: [PATCH 133/658] Update README.md --- templates/README.md | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/templates/README.md b/templates/README.md index c44fe4ef59..588797c42a 100644 --- a/templates/README.md +++ b/templates/README.md @@ -11,30 +11,37 @@ Basically there's three places of the codebase you need to think about for each ## The example resource -model- and it's endpoints ### `pages/api/endpoint/` - -GET pages/api/endpoint/index.ts - Read All of your resource -POST pages/api/endpoint/new.ts - Create new resource +| Method | route | action | +| ------ | ----- | ----- | +| GET | pages/api/endpoint/index.ts | Read All of your resource | +| POST |pages/api/endpoint/new.ts | Create new resource | ### `pages/api/endpoint/[id]/` -GET pages/api/endpoint/[id]/index.ts - Read All of your resource -PATCH pages/api/endpoint/[id]/edit.ts - Create new resource -DELETE pages/api/endpoint/[id]/delete.ts - Create new resource +| Method | route | action | +| ------ | --------------------------------- | ------------------------- | +| GET | pages/api/endpoint/[id]/index.ts | Read All of your resource | +| PATCH | pages/api/endpoint/[id]/edit.ts | Create new resource | +| DELETE | pages/api/endpoint/[id]/delete.ts | Create new resource | ## `/tests/` -This is where all your endpoint's tests live, we mock prisma calls. We aim for at least 50% global coverage. Test each of your endpoints. +This is where all your endpoint's tests live, we mock prisma calls. We aim for at least 50% global coverage. Please test each of your endpoints. ### `/tests/endpoint/` -/tests/endpoint/resource.index.test.ts - Test for your pages/api/endpoint/index.ts file -tests/endpoint/resource.new.test.ts - Create new resource +| route | action | +| -------------------------------------- | ---------------------------------------------- | +| /tests/endpoint/resource.index.test.ts | Test for your pages/api/endpoint/index.ts file | +| tests/endpoint/resource.new.test.ts | Create new resource | ### `/tests/endpoint/[id]/` -`/tests/endpoint/[id]/resource.index.test.ts` - Read All of your resource -`/tests/endpoint/[id]/resource.edit.test.ts` - Create new resource -`/tests/endpoint/[id]/resource.delete.test.ts` - Create new resource +| route | action | +| ---------------------------------------------- | ------------------------- | +| `/tests/endpoint/[id]/resource.index.test.ts` | Read All of your resource | +| `/tests/endpoint/[id]/resource.edit.test.ts` | Create new resource | +| `/tests/endpoint/[id]/resource.delete.test.ts` | Create new resource | ## `/lib/validations/yourEndpoint.ts` From 14d63fc45cf35aa4df41254c82fde0465e461e75 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 21 Apr 2022 03:31:46 +0200 Subject: [PATCH 134/658] removes tests for now --- tests/api-keys/[id]/api-key.id.delete.test.ts | 86 ------------- tests/api-keys/[id]/api-key.id.edit.test.ts | 103 ---------------- tests/api-keys/[id]/api-key.id.index.test.ts | 83 ------------- tests/api-keys/api-key.index.test.ts | 39 ------ tests/api-keys/api-key.new.test.ts | 77 ------------ tests/bookings/[id]/booking.id.edit.test.ts | 116 ------------------ tests/bookings/[id]/booking.id.index.test.ts | 84 ------------- tests/bookings/booking.index.test.ts | 39 ------ tests/bookings/booking.new.test.ts | 77 ------------ .../[id]/event-type.id.edit.test.ts | 116 ------------------ .../[id]/event-type.id.index.test.ts | 75 ----------- tests/event-types/event-type.index.test.ts | 32 ----- tests/event-types/event-type.new.test.ts | 70 ----------- tests/teams/[id]/team.id.edit.test.ts | 107 ---------------- tests/teams/[id]/team.id.index.test.ts | 75 ----------- tests/users/[id]/user.id.edit.test.ts | 116 ------------------ tests/users/[id]/user.id.index.test.ts | 83 ------------- 17 files changed, 1378 deletions(-) delete mode 100644 tests/api-keys/[id]/api-key.id.delete.test.ts delete mode 100644 tests/api-keys/[id]/api-key.id.edit.test.ts delete mode 100644 tests/api-keys/[id]/api-key.id.index.test.ts delete mode 100644 tests/api-keys/api-key.index.test.ts delete mode 100644 tests/api-keys/api-key.new.test.ts delete mode 100644 tests/bookings/[id]/booking.id.edit.test.ts delete mode 100644 tests/bookings/[id]/booking.id.index.test.ts delete mode 100644 tests/bookings/booking.index.test.ts delete mode 100644 tests/bookings/booking.new.test.ts delete mode 100644 tests/event-types/[id]/event-type.id.edit.test.ts delete mode 100644 tests/event-types/[id]/event-type.id.index.test.ts delete mode 100644 tests/event-types/event-type.index.test.ts delete mode 100644 tests/event-types/event-type.new.test.ts delete mode 100644 tests/teams/[id]/team.id.edit.test.ts delete mode 100644 tests/teams/[id]/team.id.index.test.ts delete mode 100644 tests/users/[id]/user.id.edit.test.ts delete mode 100644 tests/users/[id]/user.id.index.test.ts diff --git a/tests/api-keys/[id]/api-key.id.delete.test.ts b/tests/api-keys/[id]/api-key.id.delete.test.ts deleted file mode 100644 index d2abfecb7a..0000000000 --- a/tests/api-keys/[id]/api-key.id.delete.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -import handleDeleteApiKey from "@api/api-keys/[id]/delete"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -describe("DELETE /api/api-keys/[id]/delete with valid id as string returns an apiKey", () => { - it("returns a message with the specified apiKeys", async () => { - const apiKey = await prisma.apiKey.findFirst(); - const { req, res } = createMocks({ - method: "DELETE", - query: { - id: apiKey?.id, - }, - }); - // const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.id} }); - await handleDeleteApiKey(req, res); - expect(res._getStatusCode()).toBe(204); - expect(JSON.parse(res._getData())).toEqual({ - message: `api-key with id: ${apiKey?.id} deleted successfully`, - }); - }); -}); - -// This can never happen under our normal nextjs setup where query is always a string | string[]. -// But seemed a good example for testing an error validation -describe("DELETE /api/api-keys/[id]/delete errors if query id is number, requires a string", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "DELETE", - query: { - id: 1, // passing query as a number, which should fail as nextjs will try to parse it as a string - }, - }); - await handleDeleteApiKey(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "invalid_type", - expected: "string", - received: "number", - path: ["id"], - message: "Expected string, received number", - }, - ]); - }); -}); - -describe("DELETE /api/api-keys/[id]/delete an id not present in db like 0, throws 404 not found", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "DELETE", - query: { - id: "0", // There's no apiKey with id 0 - }, - }); - await handleDeleteApiKey(req, res); - - expect(res._getStatusCode()).toBe(404); - expect(JSON.parse(res._getData())).toStrictEqual({ - error: { - clientVersion: "3.10.0", - code: "P2025", - meta: { - cause: "Record to delete does not exist.", - }, - }, - message: "Resource with id:0 was not found", - }); - }); -}); - -describe("POST /api/api-keys/[id]/delete fails, only DELETE allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "1", - }, - }); - await handleDeleteApiKey(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only DELETE Method allowed" }); - }); -}); diff --git a/tests/api-keys/[id]/api-key.id.edit.test.ts b/tests/api-keys/[id]/api-key.id.edit.test.ts deleted file mode 100644 index 1007181179..0000000000 --- a/tests/api-keys/[id]/api-key.id.edit.test.ts +++ /dev/null @@ -1,103 +0,0 @@ -import handleapiKeyEdit from "@api/api-keys/[id]/edit"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -import { stringifyISODate } from "@lib/utils/stringifyISODate"; - -describe("PATCH /api/api-keys/[id]/edit with valid id and body with note", () => { - it("returns a 200 and the updated apiKey note", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "cl16zg6860000wwylnsgva00b", - }, - body: { - note: "Updated note", - }, - }); - const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.id } }); - await handleapiKeyEdit(req, res); - - expect(res._getStatusCode()).toBe(200); - expect(JSON.parse(res._getData())).toEqual({ - data: { - ...apiKey, - createdAt: stringifyISODate(apiKey?.createdAt), - expiresAt: stringifyISODate(apiKey?.expiresAt), - }, - }); - }); -}); - -describe("PATCH /api/api-keys/[id]/edit with invalid id returns 404", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "cl16zg6860000wwylnsgva00a", - }, - body: { - note: "Updated note", - }, - }); - const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.id } }); - await handleapiKeyEdit(req, res); - - expect(res._getStatusCode()).toBe(404); - if (apiKey) apiKey.note = "Updated note"; - expect(JSON.parse(res._getData())).toStrictEqual({ - error: { - clientVersion: "3.10.0", - code: "P2025", - meta: { - cause: "Record to update not found.", - }, - }, - message: "apiKey with ID cl16zg6860000wwylnsgva00a not found and wasn't updated", - }); - }); -}); - -describe("PATCH /api/api-keys/[id]/edit with valid id and no body returns 200 with an apiKey with no note and default expireAt", () => { - it("returns a message with the specified apiKeys", async () => { - const apiKey = await prisma.apiKey.create({ data: {} }); - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: apiKey?.id, - }, - }); - await handleapiKeyEdit(req, res); - - expect(apiKey?.note).toBeNull(); - expect(res._getStatusCode()).toBe(200); - expect(JSON.parse(res._getData())).toEqual({ - data: { - ...apiKey, - createdAt: stringifyISODate(apiKey?.createdAt), - expiresAt: stringifyISODate(apiKey?.expiresAt), - }, - }); - }); -}); - -describe("POST /api/api-keys/[id]/edit fails, only PATCH allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "cl16zg6860000wwylnsgva00b", - }, - body: { - note: "Updated note", - }, - }); - await handleapiKeyEdit(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ - message: "Only PATCH Method allowed for updating API keys", - }); - }); -}); diff --git a/tests/api-keys/[id]/api-key.id.index.test.ts b/tests/api-keys/[id]/api-key.id.index.test.ts deleted file mode 100644 index 8d3c2655af..0000000000 --- a/tests/api-keys/[id]/api-key.id.index.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -import handleApiKey from "@api/api-keys/[id]"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -import { stringifyISODate } from "@lib/utils/stringifyISODate"; - -describe("GET /api/api-keys/[id] with valid id as string returns an apiKey", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: "cl16zg6860000wwylnsgva00b", - }, - }); - const apiKey = await prisma.apiKey.findUnique({ where: { id: req.query.id } }); - await handleApiKey(req, res); - - expect(res._getStatusCode()).toBe(200); - expect(JSON.parse(res._getData())).toEqual({ - data: { - ...apiKey, - createdAt: stringifyISODate(apiKey?.createdAt), - expiresAt: stringifyISODate(apiKey?.expiresAt), - }, - }); - }); -}); - -// This can never happen under our normal nextjs setup where query is always a string | string[]. -// But seemed a good example for testing an error validation -describe("GET /api/api-keys/[id] errors if query id is number, requires a string", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: 1, // passing query as a number, which should fail as nextjs will try to parse it as a string - }, - }); - await handleApiKey(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "invalid_type", - expected: "string", - received: "number", - path: ["id"], - message: "Expected string, received number", - }, - ]); - }); -}); - -describe("GET /api/api-keys/[id] an id not present in db like 0, throws 404 not found", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: "0", // There's no apiKey with id 0 - }, - }); - await handleApiKey(req, res); - - expect(res._getStatusCode()).toBe(404); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "API key was not found" }); - }); -}); - -describe("POST /api/api-keys/[id] fails, only GET allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "1", - }, - }); - await handleApiKey(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); - }); -}); diff --git a/tests/api-keys/api-key.index.test.ts b/tests/api-keys/api-key.index.test.ts deleted file mode 100644 index 957b749b88..0000000000 --- a/tests/api-keys/api-key.index.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import handleApiKeys from "@api/api-keys"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -import { stringifyISODate } from "@lib/utils/stringifyISODate"; - -describe("GET /api/api-keys without any params", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "GET", - query: {}, - }); - let apiKeys = await prisma.apiKey.findMany(); - await handleApiKeys(req, res); - - expect(res._getStatusCode()).toBe(200); - apiKeys = apiKeys.map( - (apiKey) => - (apiKey = { - ...apiKey, - createdAt: stringifyISODate(apiKey?.createdAt), - expiresAt: stringifyISODate(apiKey?.expiresAt), - }) - ); - expect(JSON.parse(res._getData())).toStrictEqual(JSON.parse(JSON.stringify({ data: { ...apiKeys } }))); - }); -}); - -describe("POST /api/api-keys/ fails, only GET allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - }); - await handleApiKeys(req, res); - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); - }); -}); diff --git a/tests/api-keys/api-key.new.test.ts b/tests/api-keys/api-key.new.test.ts deleted file mode 100644 index 339b4c146b..0000000000 --- a/tests/api-keys/api-key.new.test.ts +++ /dev/null @@ -1,77 +0,0 @@ -import handleNewApiKey from "@api/api-keys/new"; -import { createMocks } from "node-mocks-http"; - -describe("POST /api/api-keys/new with a note", () => { - it("returns a 201, and the created api key", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - body: { - note: "Updated note", - }, - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(201); - expect(JSON.parse(res._getData()).data.note).toStrictEqual("Updated note"); - }); -}); - -describe("POST /api/api-keys/new with a slug param", () => { - it("returns error 400, and the details about invalid slug body param", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - body: { - note: "Updated note", - slug: "slug", - }, - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "unrecognized_keys", - keys: ["slug"], - message: "Unrecognized key(s) in object: 'slug'", - path: [], - }, - ]); - }); -}); - -describe("GET /api/api-keys/new fails, only POST allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "GET", // This POST method is not allowed - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ error: "Only POST Method allowed" }); - }); -}); - -// FIXME: test 405 when prisma fails look for how to test prisma errors -describe("GET /api/api-keys/new fails, only POST allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - body: { - nonExistentParam: true, - // note: '123', - // slug: 12, - }, - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "unrecognized_keys", - keys: ["nonExistentParam"], - message: "Unrecognized key(s) in object: 'nonExistentParam'", - path: [], - }, - ]); - }); -}); diff --git a/tests/bookings/[id]/booking.id.edit.test.ts b/tests/bookings/[id]/booking.id.edit.test.ts deleted file mode 100644 index 8bf32eb0e5..0000000000 --- a/tests/bookings/[id]/booking.id.edit.test.ts +++ /dev/null @@ -1,116 +0,0 @@ -import handleBookingEdit from "@api/bookings/[id]/edit"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -describe("PATCH /api/bookings/[id]/edit with valid id and body updates an booking", () => { - it("returns a message with the specified bookings", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "2", - }, - body: { - title: "Updated title", - slug: "updated-slug", - length: 1, - }, - }); - const booking = await prisma.booking.findUnique({ where: { id: parseInt(req.query.id) } }); - await handleBookingEdit(req, res); - - expect(res._getStatusCode()).toBe(200); - if (booking) booking.title = "Updated title"; - expect(JSON.parse(res._getData())).toStrictEqual({ data: booking }); - }); -}); - -describe("PATCH /api/bookings/[id]/edit with invalid id returns 404", () => { - it("returns a message with the specified bookings", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "0", - }, - body: { - title: "Updated title", - slug: "updated-slug", - length: 1, - }, - }); - const booking = await prisma.booking.findUnique({ where: { id: parseInt(req.query.id) } }); - await handleBookingEdit(req, res); - - expect(res._getStatusCode()).toBe(404); - if (booking) booking.title = "Updated title"; - expect(JSON.parse(res._getData())).toStrictEqual({ - error: { - clientVersion: "3.10.0", - code: "P2025", - meta: { - cause: "Record to update not found.", - }, - }, - message: "Event type with ID 0 not found and wasn't updated", - }); - }); -}); - -describe("PATCH /api/bookings/[id]/edit with valid id and no body returns 400 error and zod validation errors", () => { - it("returns a message with the specified bookings", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "2", - }, - }); - await handleBookingEdit(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "invalid_type", - expected: "string", - message: "Required", - path: ["title"], - received: "undefined", - }, - { - code: "invalid_type", - expected: "string", - message: "Required", - path: ["slug"], - received: "undefined", - }, - { - code: "invalid_type", - expected: "number", - message: "Required", - path: ["length"], - received: "undefined", - }, - ]); - }); -}); - -describe("POST /api/bookings/[id]/edit fails, only PATCH allowed", () => { - it("returns a message with the specified bookings", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "1", - }, - body: { - title: "Updated title", - slug: "updated-slug", - length: 1, - }, - }); - await handleBookingEdit(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ - message: "Only PATCH Method allowed for updating bookings", - }); - }); -}); diff --git a/tests/bookings/[id]/booking.id.index.test.ts b/tests/bookings/[id]/booking.id.index.test.ts deleted file mode 100644 index 4a2ff0ca0c..0000000000 --- a/tests/bookings/[id]/booking.id.index.test.ts +++ /dev/null @@ -1,84 +0,0 @@ -import handleBooking from "@api/bookings/[id]"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -import { stringifyISODate } from "@lib/utils/stringifyISODate"; - -describe("GET /api/bookings/[id] with valid id as string returns an booking", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: "1", - }, - }); - const booking = await prisma.booking.findUnique({ where: { id: 1 } }); - await handleBooking(req, res); - - expect(res._getStatusCode()).toBe(200); - expect(JSON.parse(res._getData())).toEqual({ - data: { - ...booking, - createdAt: stringifyISODate(booking?.createdAt), - startTime: stringifyISODate(booking?.startTime), - endTime: stringifyISODate(booking?.endTime), - }, - }); - }); -}); - -// This can never happen under our normal nextjs setup where query is always a string | string[]. -// But seemed a good example for testing an error validation -describe("GET /api/bookings/[id] errors if query id is number, requires a string", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: 1, // passing query as a number, which should fail as nextjs will try to parse it as a string - }, - }); - await handleBooking(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "invalid_type", - expected: "string", - received: "number", - path: ["id"], - message: "Expected string, received number", - }, - ]); - }); -}); - -describe("GET /api/bookings/[id] an id not present in db like 0, throws 404 not found", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: "0", // There's no booking type with id 0 - }, - }); - await handleBooking(req, res); - - expect(res._getStatusCode()).toBe(404); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Event type not found" }); - }); -}); - -describe("POST /api/bookings/[id] fails, only GET allowed", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "1", - }, - }); - await handleBooking(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); - }); -}); diff --git a/tests/bookings/booking.index.test.ts b/tests/bookings/booking.index.test.ts deleted file mode 100644 index 957b749b88..0000000000 --- a/tests/bookings/booking.index.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import handleApiKeys from "@api/api-keys"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -import { stringifyISODate } from "@lib/utils/stringifyISODate"; - -describe("GET /api/api-keys without any params", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "GET", - query: {}, - }); - let apiKeys = await prisma.apiKey.findMany(); - await handleApiKeys(req, res); - - expect(res._getStatusCode()).toBe(200); - apiKeys = apiKeys.map( - (apiKey) => - (apiKey = { - ...apiKey, - createdAt: stringifyISODate(apiKey?.createdAt), - expiresAt: stringifyISODate(apiKey?.expiresAt), - }) - ); - expect(JSON.parse(res._getData())).toStrictEqual(JSON.parse(JSON.stringify({ data: { ...apiKeys } }))); - }); -}); - -describe("POST /api/api-keys/ fails, only GET allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - }); - await handleApiKeys(req, res); - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); - }); -}); diff --git a/tests/bookings/booking.new.test.ts b/tests/bookings/booking.new.test.ts deleted file mode 100644 index 339b4c146b..0000000000 --- a/tests/bookings/booking.new.test.ts +++ /dev/null @@ -1,77 +0,0 @@ -import handleNewApiKey from "@api/api-keys/new"; -import { createMocks } from "node-mocks-http"; - -describe("POST /api/api-keys/new with a note", () => { - it("returns a 201, and the created api key", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - body: { - note: "Updated note", - }, - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(201); - expect(JSON.parse(res._getData()).data.note).toStrictEqual("Updated note"); - }); -}); - -describe("POST /api/api-keys/new with a slug param", () => { - it("returns error 400, and the details about invalid slug body param", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - body: { - note: "Updated note", - slug: "slug", - }, - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "unrecognized_keys", - keys: ["slug"], - message: "Unrecognized key(s) in object: 'slug'", - path: [], - }, - ]); - }); -}); - -describe("GET /api/api-keys/new fails, only POST allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "GET", // This POST method is not allowed - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ error: "Only POST Method allowed" }); - }); -}); - -// FIXME: test 405 when prisma fails look for how to test prisma errors -describe("GET /api/api-keys/new fails, only POST allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - body: { - nonExistentParam: true, - // note: '123', - // slug: 12, - }, - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "unrecognized_keys", - keys: ["nonExistentParam"], - message: "Unrecognized key(s) in object: 'nonExistentParam'", - path: [], - }, - ]); - }); -}); diff --git a/tests/event-types/[id]/event-type.id.edit.test.ts b/tests/event-types/[id]/event-type.id.edit.test.ts deleted file mode 100644 index e88bcb9b49..0000000000 --- a/tests/event-types/[id]/event-type.id.edit.test.ts +++ /dev/null @@ -1,116 +0,0 @@ -import handleEventTypeEdit from "@api/event-types/[id]/edit"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -describe("PATCH /api/event-types/[id]/edit with valid id and body updates an event-type", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "2", - }, - body: { - title: "Updated title", - slug: "updated-slug", - length: 1, - }, - }); - const event = await prisma.eventType.findUnique({ where: { id: parseInt(req.query.id) } }); - await handleEventTypeEdit(req, res); - - expect(res._getStatusCode()).toBe(200); - if (event) event.title = "Updated title"; - expect(JSON.parse(res._getData())).toStrictEqual({ data: event }); - }); -}); - -describe("PATCH /api/event-types/[id]/edit with invalid id returns 404", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "0", - }, - body: { - title: "Updated title", - slug: "updated-slug", - length: 1, - }, - }); - const event = await prisma.eventType.findUnique({ where: { id: parseInt(req.query.id) } }); - await handleEventTypeEdit(req, res); - - expect(res._getStatusCode()).toBe(404); - if (event) event.title = "Updated title"; - expect(JSON.parse(res._getData())).toStrictEqual({ - error: { - clientVersion: "3.10.0", - code: "P2025", - meta: { - cause: "Record to update not found.", - }, - }, - message: "Event type with ID 0 not found and wasn't updated", - }); - }); -}); - -describe("PATCH /api/event-types/[id]/edit with valid id and no body returns 400 error and zod validation errors", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "2", - }, - }); - await handleEventTypeEdit(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "invalid_type", - expected: "string", - message: "Required", - path: ["title"], - received: "undefined", - }, - { - code: "invalid_type", - expected: "string", - message: "Required", - path: ["slug"], - received: "undefined", - }, - { - code: "invalid_type", - expected: "number", - message: "Required", - path: ["length"], - received: "undefined", - }, - ]); - }); -}); - -describe("POST /api/event-types/[id]/edit fails, only PATCH allowed", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "1", - }, - body: { - title: "Updated title", - slug: "updated-slug", - length: 1, - }, - }); - await handleEventTypeEdit(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ - message: "Only PATCH Method allowed for updating event-types", - }); - }); -}); diff --git a/tests/event-types/[id]/event-type.id.index.test.ts b/tests/event-types/[id]/event-type.id.index.test.ts deleted file mode 100644 index bb54d5963f..0000000000 --- a/tests/event-types/[id]/event-type.id.index.test.ts +++ /dev/null @@ -1,75 +0,0 @@ -import handleEventType from "@api/event-types/[id]"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -describe("GET /api/event-types/[id] with valid id as string returns an event-type", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: "1", - }, - }); - const event = await prisma.eventType.findUnique({ where: { id: 1 } }); - await handleEventType(req, res); - - expect(res._getStatusCode()).toBe(200); - expect(JSON.parse(res._getData())).toStrictEqual({ data: event }); - }); -}); - -// This can never happen under our normal nextjs setup where query is always a string | string[]. -// But seemed a good example for testing an error validation -describe("GET /api/event-types/[id] errors if query id is number, requires a string", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: 1, // passing query as a number, which should fail as nextjs will try to parse it as a string - }, - }); - await handleEventType(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "invalid_type", - expected: "string", - received: "number", - path: ["id"], - message: "Expected string, received number", - }, - ]); - }); -}); - -describe("GET /api/event-types/[id] an id not present in db like 0, throws 404 not found", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: "0", // There's no event type with id 0 - }, - }); - await handleEventType(req, res); - - expect(res._getStatusCode()).toBe(404); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Event type not found" }); - }); -}); - -describe("POST /api/event-types/[id] fails, only GET allowed", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "1", - }, - }); - await handleEventType(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); - }); -}); diff --git a/tests/event-types/event-type.index.test.ts b/tests/event-types/event-type.index.test.ts deleted file mode 100644 index 7a63a59a5d..0000000000 --- a/tests/event-types/event-type.index.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import handleApiKeys from "@api/event-types"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -// import {stringifyISODate} from "@lib/utils/stringifyISODate"; - -describe("GET /api/event-types without any params", () => { - it("returns a message with the specified eventTypes", async () => { - const { req, res } = createMocks({ - method: "GET", - query: {}, - }); - const eventTypes = await prisma.eventType.findMany(); - await handleApiKeys(req, res); - - expect(res._getStatusCode()).toBe(200); - // eventTypes = eventTypes.map(eventType => (eventType = {...eventType, createdAt: stringifyISODate(eventType?.createdAt), expiresAt: stringifyISODate(eventType?.expiresAt)})); - expect(JSON.parse(res._getData())).toStrictEqual(JSON.parse(JSON.stringify({ data: { ...eventTypes } }))); - }); -}); - -describe("POST /api/event-types/ fails, only GET allowed", () => { - it("returns a message with the specified eventTypes", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - }); - await handleApiKeys(req, res); - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); - }); -}); diff --git a/tests/event-types/event-type.new.test.ts b/tests/event-types/event-type.new.test.ts deleted file mode 100644 index a79209ec03..0000000000 --- a/tests/event-types/event-type.new.test.ts +++ /dev/null @@ -1,70 +0,0 @@ -import handleNewApiKey from "@api/api-keys/new"; -import { createMocks } from "node-mocks-http"; - -describe("POST /api/api-keys/new with a note", () => { - it("returns a 201, and the created api key", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - body: { - note: "Updated note", - }, - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(201); - expect(JSON.parse(res._getData()).data.note).toStrictEqual("Updated note"); - }); -}); - -describe("POST /api/api-keys/new with a slug param", () => { - it("returns error 400, and the details about invalid slug body param", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - body: { - note: "Updated note", - slug: "slug", - }, - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "unrecognized_keys", - keys: ["slug"], - message: "Unrecognized key(s) in object: 'slug'", - path: [], - }, - ]); - }); -}); - -describe("GET /api/api-keys/new fails, only POST allowed", () => { - it("returns a message with the specified apiKeys", async () => { - const { req, res } = createMocks({ - method: "GET", // This POST method is not allowed - }); - await handleNewApiKey(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ error: "Only POST Method allowed" }); - }); -}); - -// FIXME: test 405 when prisma fails look for how to test prisma errors -// describe("GET /api/api-keys/new fails, only POST allowed", () => { -// it("returns a message with the specified apiKeys", async () => { -// const { req, res } = createMocks({ -// method: "POST", // This POST method is not allowed -// body: { -// fail: true -// // note: '123', -// // slug: 12, -// }, -// }); -// await handleNewApiKey(req, res); - -// expect(res._getStatusCode()).toBe(400); -// expect(JSON.parse(res._getData())).toStrictEqual({ error: "Only POST Method allowed" }); -// }); -// }); diff --git a/tests/teams/[id]/team.id.edit.test.ts b/tests/teams/[id]/team.id.edit.test.ts deleted file mode 100644 index 101deaa06e..0000000000 --- a/tests/teams/[id]/team.id.edit.test.ts +++ /dev/null @@ -1,107 +0,0 @@ -import handleTeamEdit from "@api/teams/[id]/edit"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -describe("PATCH /api/teams/[id]/edit with valid id and body updates a team", () => { - it("returns a message with the specified teams", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "1", - }, - body: { - name: "Updated team", - slug: "updated-team", - }, - }); - const team = await prisma.team.findUnique({ where: { id: parseInt(req.query.id) } }); - await handleTeamEdit(req, res); - - expect(res._getStatusCode()).toBe(200); - // if (team) team.name = "Updated name"; - expect(JSON.parse(res._getData())).toStrictEqual({ data: team }); - }); -}); - -describe("PATCH /api/teams/[id]/edit with invalid id returns 404", () => { - it("returns a message with the specified teams", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "0", - }, - body: { - name: "Updated name", - slug: "updated-slug", - }, - }); - const team = await prisma.team.findUnique({ where: { id: parseInt(req.query.id) } }); - await handleTeamEdit(req, res); - - expect(res._getStatusCode()).toBe(404); - expect(JSON.parse(res._getData())).toStrictEqual({ - error: { - clientVersion: "3.10.0", - code: "P2025", - meta: { - cause: "Record to update not found.", - }, - }, - message: "Event type with ID 0 not found and wasn't updated", - }); - }); -}); - -describe("PATCH /api/teams/[id]/edit with valid id and no body returns 400 error and zod validation errors", () => { - it("returns a message with the specified teams", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "2", - }, - }); - await handleTeamEdit(req, res); - - expect(res._getStatusCode()).toBe(400); - - // Ugly parsing of zod validation errors, not for final production but works for testing - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "invalid_type", - expected: "string", - message: "Required", - path: ["slug"], - received: "undefined", - }, - { - code: "invalid_type", - expected: "string", - message: "Required", - path: ["name"], - received: "undefined", - }, - ]); - }); -}); - -describe("POST /api/teams/[id]/edit fails, only PATCH allowed", () => { - it("returns a message with the specified teams", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "1", - }, - body: { - name: "Updated name", - slug: "updated-slug", - }, - }); - await handleTeamEdit(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ - message: "Only PATCH Method allowed for updating teams", - }); - }); -}); diff --git a/tests/teams/[id]/team.id.index.test.ts b/tests/teams/[id]/team.id.index.test.ts deleted file mode 100644 index 016f7ec604..0000000000 --- a/tests/teams/[id]/team.id.index.test.ts +++ /dev/null @@ -1,75 +0,0 @@ -import handleTeam from "@api/teams/[id]"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -describe("GET /api/teams/[id] with valid id as string returns an team-type", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: "1", - }, - }); - const team = await prisma.team.findUnique({ where: { id: 1 } }); - await handleTeam(req, res); - - expect(res._getStatusCode()).toBe(200); - expect(JSON.parse(res._getData())).toStrictEqual({ data: team }); - }); -}); - -// This can never happen under our normal nextjs setup where query is always a string | string[]. -// But seemed a good example for testing an error validation -describe("GET /api/teams/[id] errors if query id is number, requires a string", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: 1, // passing query as a number, which should fail as nextjs will try to parse it as a string - }, - }); - await handleTeam(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "invalid_type", - expected: "string", - received: "number", - path: ["id"], - message: "Expected string, received number", - }, - ]); - }); -}); - -describe("GET /api/teams/[id] an id not present in db like 0, throws 404 not found", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: "0", // There's no team type with id 0 - }, - }); - await handleTeam(req, res); - - expect(res._getStatusCode()).toBe(404); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Event type not found" }); - }); -}); - -describe("POST /api/teams/[id] fails, only GET allowed", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "1", - }, - }); - await handleTeam(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); - }); -}); diff --git a/tests/users/[id]/user.id.edit.test.ts b/tests/users/[id]/user.id.edit.test.ts deleted file mode 100644 index e88bcb9b49..0000000000 --- a/tests/users/[id]/user.id.edit.test.ts +++ /dev/null @@ -1,116 +0,0 @@ -import handleEventTypeEdit from "@api/event-types/[id]/edit"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -describe("PATCH /api/event-types/[id]/edit with valid id and body updates an event-type", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "2", - }, - body: { - title: "Updated title", - slug: "updated-slug", - length: 1, - }, - }); - const event = await prisma.eventType.findUnique({ where: { id: parseInt(req.query.id) } }); - await handleEventTypeEdit(req, res); - - expect(res._getStatusCode()).toBe(200); - if (event) event.title = "Updated title"; - expect(JSON.parse(res._getData())).toStrictEqual({ data: event }); - }); -}); - -describe("PATCH /api/event-types/[id]/edit with invalid id returns 404", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "0", - }, - body: { - title: "Updated title", - slug: "updated-slug", - length: 1, - }, - }); - const event = await prisma.eventType.findUnique({ where: { id: parseInt(req.query.id) } }); - await handleEventTypeEdit(req, res); - - expect(res._getStatusCode()).toBe(404); - if (event) event.title = "Updated title"; - expect(JSON.parse(res._getData())).toStrictEqual({ - error: { - clientVersion: "3.10.0", - code: "P2025", - meta: { - cause: "Record to update not found.", - }, - }, - message: "Event type with ID 0 not found and wasn't updated", - }); - }); -}); - -describe("PATCH /api/event-types/[id]/edit with valid id and no body returns 400 error and zod validation errors", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "PATCH", - query: { - id: "2", - }, - }); - await handleEventTypeEdit(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "invalid_type", - expected: "string", - message: "Required", - path: ["title"], - received: "undefined", - }, - { - code: "invalid_type", - expected: "string", - message: "Required", - path: ["slug"], - received: "undefined", - }, - { - code: "invalid_type", - expected: "number", - message: "Required", - path: ["length"], - received: "undefined", - }, - ]); - }); -}); - -describe("POST /api/event-types/[id]/edit fails, only PATCH allowed", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "1", - }, - body: { - title: "Updated title", - slug: "updated-slug", - length: 1, - }, - }); - await handleEventTypeEdit(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ - message: "Only PATCH Method allowed for updating event-types", - }); - }); -}); diff --git a/tests/users/[id]/user.id.index.test.ts b/tests/users/[id]/user.id.index.test.ts deleted file mode 100644 index bf79c38143..0000000000 --- a/tests/users/[id]/user.id.index.test.ts +++ /dev/null @@ -1,83 +0,0 @@ -import handleUser from "@api/users/[id]"; -import { createMocks } from "node-mocks-http"; - -import prisma from "@calcom/prisma"; - -import { stringifyISODate } from "@lib/utils/stringifyISODate"; - -describe("GET /api/users/[id] with valid id as string returns an user-type", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: "1", - }, - }); - const user = await prisma.user.findUnique({ where: { id: 1 } }); - await handleUser(req, res); - - expect(res._getStatusCode()).toBe(200); - expect(JSON.parse(res._getData())).toEqual({ - data: { - ...user, - createdDate: stringifyISODate(user?.createdDate), - emailVerified: stringifyISODate(user?.emailVerified), - }, - }); - }); -}); - -// This can never happen under our normal nextjs setup where query is always a string | string[]. -// But seemed a good example for testing an error validation -describe("GET /api/users/[id] errors if query id is number, requires a string", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: 1, // passing query as a number, which should fail as nextjs will try to parse it as a string - }, - }); - await handleUser(req, res); - - expect(res._getStatusCode()).toBe(400); - expect(JSON.parse(res._getData())).toStrictEqual([ - { - code: "invalid_type", - expected: "string", - received: "number", - path: ["id"], - message: "Expected string, received number", - }, - ]); - }); -}); - -describe("GET /api/users/[id] an id not present in db like 0, throws 404 not found", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "GET", - query: { - id: "0", // There's no user type with id 0 - }, - }); - await handleUser(req, res); - - expect(res._getStatusCode()).toBe(404); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Event type not found" }); - }); -}); - -describe("POST /api/users/[id] fails, only GET allowed", () => { - it("returns a message with the specified events", async () => { - const { req, res } = createMocks({ - method: "POST", // This POST method is not allowed - query: { - id: "1", - }, - }); - await handleUser(req, res); - - expect(res._getStatusCode()).toBe(405); - expect(JSON.parse(res._getData())).toStrictEqual({ message: "Only GET Method allowed" }); - }); -}); From be3bcf2bf00313efc5761aa962138b5415d13aa0 Mon Sep 17 00:00:00 2001 From: zomars Date: Thu, 21 Apr 2022 19:36:33 -0600 Subject: [PATCH 135/658] Refactoring and fixes --- .husky/pre-commit | 4 --- .prettierrc.js | 1 - babel.config.js | 3 -- lib/helpers/verifyApiKey.ts | 36 ++++++++++++--------- lib/utils/getCalcomUserId.ts | 3 -- package.json | 13 ++------ pages/api/attendees/[id].ts | 3 +- pages/api/attendees/index.ts | 5 ++- pages/api/availabilities/[id].ts | 3 +- pages/api/availabilities/index.ts | 3 +- pages/api/booking-references/[id].ts | 3 +- pages/api/booking-references/index.ts | 5 ++- pages/api/bookings/[id].ts | 3 +- pages/api/bookings/index.ts | 3 +- pages/api/daily-event-references/[id].ts | 3 +- pages/api/daily-event-references/index.ts | 3 +- pages/api/destination-calendars/[id].ts | 3 +- pages/api/destination-calendars/index.ts | 3 +- pages/api/event-type-custom-inputs/[id].ts | 3 +- pages/api/event-type-custom-inputs/index.ts | 2 +- pages/api/event-types/[id].ts | 3 +- pages/api/event-types/index.ts | 3 +- pages/api/memberships/[id].ts | 3 +- pages/api/memberships/index.ts | 3 +- pages/api/payments/[id].ts | 3 +- pages/api/payments/index.ts | 5 ++- pages/api/schedules/[id].ts | 3 +- pages/api/schedules/index.ts | 3 +- pages/api/selected-calendars/[id].ts | 3 +- pages/api/selected-calendars/index.ts | 3 +- pages/api/teams/[id].ts | 3 +- pages/api/teams/index.ts | 3 +- pages/api/users/[id].ts | 3 +- pages/api/users/index.ts | 3 +- tsconfig.json | 22 ++++++------- 35 files changed, 64 insertions(+), 107 deletions(-) delete mode 100755 .husky/pre-commit delete mode 100644 .prettierrc.js delete mode 100644 babel.config.js delete mode 100644 lib/utils/getCalcomUserId.ts diff --git a/.husky/pre-commit b/.husky/pre-commit deleted file mode 100755 index 025779ed2b..0000000000 --- a/.husky/pre-commit +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -. "$(dirname "$0")/_/husky.sh" - -yarn pre-commit diff --git a/.prettierrc.js b/.prettierrc.js deleted file mode 100644 index 246057aa0c..0000000000 --- a/.prettierrc.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require("../../packages/config/prettier-preset"); diff --git a/babel.config.js b/babel.config.js deleted file mode 100644 index 2afcfd2404..0000000000 --- a/babel.config.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - presets: [["@babel/preset-env", { targets: { node: "current" } }], "@babel/preset-typescript"], -}; diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 0ee197456c..0f70c88a8e 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -1,8 +1,17 @@ +import type { IncomingMessage } from "http"; +import type { NextApiRequest, NextApiResponse } from "next"; import { NextMiddleware } from "next-api-middleware"; import { hashAPIKey } from "@calcom/ee/lib/api/apiKeys"; import prisma from "@calcom/prisma"; +/** @todo figure how to use the one from `@calcom/types`fi */ +declare module "next" { + export interface NextApiRequest extends IncomingMessage { + userId: number; + } +} + // Used to check if the API key is not expired, could be extracted if reused. but not for now. export const dateInPast = function (date: Date) { const now = new Date(); @@ -12,24 +21,21 @@ export const dateInPast = function (date: Date) { }; // This verifies the API key and sets the user if it is valid. -export const verifyApiKey: NextMiddleware = async (req, res, next) => { - if (!req.query.apiKey) res.status(401).json({ message: "No api key provided" }); +export const verifyApiKey: NextMiddleware = async (req: NextApiRequest, res: NextApiResponse, next) => { + if (!req.query.apiKey) return res.status(401).json({ message: "No api key provided" }); // We remove the prefix from the user provided api_key. If no env set default to "cal_" const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "cal_", ""); // Hash the key again before matching against the database records. const hashedKey = hashAPIKey(strippedApiKey); // Check if the hashed api key exists in database. - await prisma.apiKey.findUnique({ where: { hashedKey } }).then(async (apiKey) => { - // If we cannot find any api key. Throw a 401 Unauthorized. - if (!apiKey) res.status(401).json({ error: "Your api key is not valid" }); - if (apiKey && apiKey.expiresAt && dateInPast(apiKey.expiresAt) && apiKey.userId) { - // Right now API Keys are user centric, we only allow resources related to this userId throughout the application. - // if the api key is not expired, and the user id is present in the database. - // Set the user in the request. as x-calcom-user-id. - if (apiKey.userId) res.setHeader("X-Calcom-User-ID", apiKey.userId); - - // Pass the request to the next middleware. - await next(); - } - }); + const apiKey = await prisma.apiKey.findUnique({ where: { hashedKey } }); + // If we cannot find any api key. Throw a 401 Unauthorized. + if (!apiKey) return res.status(401).json({ error: "Your api key is not valid" }); + if (apiKey.expiresAt && dateInPast(apiKey.expiresAt)) { + return res.status(401).json({ error: "This api key is expired" }); + } + if (!apiKey.userId) return res.status(404).json({ error: "No user found for this api key" }); + /* We save the user id in the request for later use */ + req.userId = apiKey.userId; + await next(); }; diff --git a/lib/utils/getCalcomUserId.ts b/lib/utils/getCalcomUserId.ts deleted file mode 100644 index 8670bc8759..0000000000 --- a/lib/utils/getCalcomUserId.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { NextApiResponse } from "next"; - -export const getCalcomUserId = (res: NextApiResponse): number => res.getHeader("x-calcom-user-id") as number; diff --git a/package.json b/package.json index 16dc0f9b9f..5739292e02 100644 --- a/package.json +++ b/package.json @@ -14,24 +14,17 @@ "lint-fix": "next lint --fix && prettier --write .", "test": "jest --detectOpenHandles", "type-check": "tsc --pretty --noEmit", - "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist", - "prepare": "husky install", - "pre-commit": "next lint" + "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist" }, "devDependencies": { - "@babel/core": "^7.17.8", - "@babel/preset-env": "^7.16.11", - "@babel/preset-typescript": "^7.16.7", - "@calcom/prisma": "*", "@calcom/tsconfig": "*", "@typescript-eslint/eslint-plugin": "^5.16.0", "babel-jest": "^27.5.1", - "husky": "^7.0.4", "jest": "^27.5.1", - "node-mocks-http": "^1.11.0", - "prettier": "^2.6.1" + "node-mocks-http": "^1.11.0" }, "dependencies": { + "@calcom/prisma": "*", "@sentry/nextjs": "^6.19.3", "next": "^12.1.4", "next-api-middleware": "^1.0.1", diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index a7b573cc87..3eba0891f2 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { AttendeeResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaAttendeeBodyParams, schemaAttendeePublic } from "@lib/validations/attendee"; import { schemaQueryIdParseInt, @@ -93,7 +92,7 @@ export async function attendeeById(req: NextApiRequest, res: NextApiResponse ) { const { method } = req; - const userId = getCalcomUserId(res); + const userId = req.userId; // Here we make sure to only return attendee's of the user's own bookings. const userBookings = await prisma.booking.findMany({ where: { @@ -68,7 +67,7 @@ async function createOrlistAllAttendees( throw new Error("Invalid request body", safe.error); } const bookingId = safe.data.bookingId; - const userId = getCalcomUserId(res); + const userId = req.userId; const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index bdb1215f74..546fbe0ce1 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { AvailabilityResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaAvailabilityBodyParams, schemaAvailabilityPublic } from "@lib/validations/availability"; import { schemaQueryIdParseInt, @@ -97,7 +96,7 @@ export async function availabilityById(req: NextApiRequest, res: NextApiResponse const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaAvailabilityBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = getCalcomUserId(res); + const userId = req.userId; const data = await prisma.availability.findMany({ where: { userId } }); const availabiltiesIds = data.map((availability) => availability.id); if (availabiltiesIds.includes(safeQuery.data.id)) { diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index 63ae75db49..a6310059f7 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { AvailabilityResponse, AvailabilitiesResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaAvailabilityBodyParams, schemaAvailabilityPublic } from "@lib/validations/availability"; /** @@ -47,7 +46,7 @@ async function createOrlistAllAvailabilities( res: NextApiResponse ) { const { method } = req; - const userId = getCalcomUserId(res); + const userId = req.userId; if (method === "GET") { const data = await prisma.availability.findMany({ where: { userId } }); diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index 9a1b40089b..1644041b2f 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -5,7 +5,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { BookingReferenceResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaBookingReferenceBodyParams, schemaBookingReferencePublic, @@ -98,7 +97,7 @@ export async function bookingReferenceById( const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaBookingReferenceBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = getCalcomUserId(res); + const userId = req.userId; const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index 9ceedeed30..03bc700596 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { BookingReferenceResponse, BookingReferencesResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaBookingReferenceBodyParams, schemaBookingReferencePublic, @@ -46,7 +45,7 @@ async function createOrlistAllBookingReferences( res: NextApiResponse ) { const { method } = req; - const userId = getCalcomUserId(res); + const userId = req.userId; const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, @@ -72,7 +71,7 @@ async function createOrlistAllBookingReferences( } // const booking_reference = schemaBookingReferencePublic.parse(data); - const userId = getCalcomUserId(res); + const userId = req.userId; const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index af6a379158..f40ae3ccbd 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { BookingResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaBookingBodyParams, schemaBookingPublic } from "@lib/validations/booking"; import { schemaQueryIdParseInt, @@ -91,7 +90,7 @@ export async function bookingById(req: NextApiRequest, res: NextApiResponse ) { const { method } = req; - const userId = getCalcomUserId(res); + const userId = req.userId; if (method === "GET") { const data = await prisma.booking.findMany({ where: { userId } }); diff --git a/pages/api/daily-event-references/[id].ts b/pages/api/daily-event-references/[id].ts index 089e21610b..993e47ed57 100644 --- a/pages/api/daily-event-references/[id].ts +++ b/pages/api/daily-event-references/[id].ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { DailyEventReferenceResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaDailyEventReferenceBodyParams, schemaDailyEventReferencePublic, @@ -97,7 +96,7 @@ export async function dailyEventReferenceById( const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaDailyEventReferenceBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = getCalcomUserId(res); + const userId = req.userId; const userBookings = await prisma.booking.findMany({ where: { userId } }); const userBookingIds = userBookings.map((booking) => booking.id); const userBookingDailyEventReferences = await prisma.dailyEventReference.findMany({ diff --git a/pages/api/daily-event-references/index.ts b/pages/api/daily-event-references/index.ts index 8b00334b1e..7b216d0040 100644 --- a/pages/api/daily-event-references/index.ts +++ b/pages/api/daily-event-references/index.ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { DailyEventReferenceResponse, DailyEventReferencesResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaDailyEventReferenceBodyParams, schemaDailyEventReferencePublic, @@ -46,7 +45,7 @@ async function createOrlistAllDailyEventReferences( res: NextApiResponse ) { const { method } = req; - const userId = getCalcomUserId(res); + const userId = req.userId; const userBookings = await prisma.booking.findMany({ where: { userId } }); const userBookingIds = userBookings.map((booking) => booking.id); diff --git a/pages/api/destination-calendars/[id].ts b/pages/api/destination-calendars/[id].ts index 62eb85810c..579ba83482 100644 --- a/pages/api/destination-calendars/[id].ts +++ b/pages/api/destination-calendars/[id].ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { DestinationCalendarResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaDestinationCalendarBodyParams, schemaDestinationCalendarPublic, @@ -97,7 +96,7 @@ export async function destionationCalendarById( const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaDestinationCalendarBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = getCalcomUserId(res); + const userId = req.userId; const data = await prisma.destinationCalendar.findMany({ where: { userId } }); const userDestinationCalendars = data.map((destinationCalendar) => destinationCalendar.id); // FIXME: Should we also check ownership of bokingId and eventTypeId to avoid users cross-pollinating other users calendars. diff --git a/pages/api/destination-calendars/index.ts b/pages/api/destination-calendars/index.ts index 2b904dbc93..b3bdcaab57 100644 --- a/pages/api/destination-calendars/index.ts +++ b/pages/api/destination-calendars/index.ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { DestinationCalendarResponse, DestinationCalendarsResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaDestinationCalendarBodyParams, schemaDestinationCalendarPublic, @@ -46,7 +45,7 @@ async function createOrlistAllDestinationCalendars( res: NextApiResponse ) { const { method } = req; - const userId = getCalcomUserId(res); + const userId = req.userId; if (method === "GET") { const data = await prisma.destinationCalendar.findMany({ where: { userId } }); diff --git a/pages/api/event-type-custom-inputs/[id].ts b/pages/api/event-type-custom-inputs/[id].ts index 5a00436361..5ff11ff884 100644 --- a/pages/api/event-type-custom-inputs/[id].ts +++ b/pages/api/event-type-custom-inputs/[id].ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { EventTypeCustomInputResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaEventTypeCustomInputBodyParams, schemaEventTypeCustomInputPublic, @@ -94,7 +93,7 @@ async function eventTypeById(req: NextApiRequest, res: NextApiResponse eventType.id); const userEventTypeCustomInputs = await prisma.eventTypeCustomInput.findMany({ diff --git a/pages/api/event-type-custom-inputs/index.ts b/pages/api/event-type-custom-inputs/index.ts index e6c0c852bf..82c23f8593 100644 --- a/pages/api/event-type-custom-inputs/index.ts +++ b/pages/api/event-type-custom-inputs/index.ts @@ -45,7 +45,7 @@ async function createOrlistAllEventTypeCustomInputs( res: NextApiResponse ) { const { method } = req; - const userId = getCalcomUserId(res); + const userId = req.userId; const data = await prisma.eventType.findMany({ where: { userId } }); const userEventTypes = data.map((eventType) => eventType.id); // const userEventTypeCustomInputs = await prisma.eventTypeCustomInput.findMany({ diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index dc7535cd5a..80d4f95bb6 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { EventTypeResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaEventTypeBodyParams, schemaEventTypePublic } from "@lib/validations/event-type"; import { schemaQueryIdParseInt, @@ -97,7 +96,7 @@ export async function eventTypeById(req: NextApiRequest, res: NextApiResponse eventType.id); if (userEventTypes.includes(safeQuery.data.id)) { diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index fc6a2a35f7..3135d9e866 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { EventTypeResponse, EventTypesResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaEventTypeBodyParams, schemaEventTypePublic } from "@lib/validations/event-type"; /** @@ -47,7 +46,7 @@ async function createOrlistAllEventTypes( res: NextApiResponse ) { const { method } = req; - const userId = getCalcomUserId(res); + const userId = req.userId; if (method === "GET") { const data = await prisma.eventType.findMany({ where: { userId } }); diff --git a/pages/api/memberships/[id].ts b/pages/api/memberships/[id].ts index df62f89107..4c90122f70 100644 --- a/pages/api/memberships/[id].ts +++ b/pages/api/memberships/[id].ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { MembershipResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaMembershipBodyParams, schemaMembershipPublic } from "@lib/validations/membership"; import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; @@ -108,7 +107,7 @@ export async function membershipById(req: NextApiRequest, res: NextApiResponse ) { const { method } = req; - const userId = getCalcomUserId(res); + const userId = req.userId; if (method === "GET") { const data = await prisma.membership.findMany({ where: { userId } }); const memberships = data.map((membership) => schemaMembershipPublic.parse(membership)); diff --git a/pages/api/payments/[id].ts b/pages/api/payments/[id].ts index 295803ca76..9d7d28a184 100644 --- a/pages/api/payments/[id].ts +++ b/pages/api/payments/[id].ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { PaymentResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaPaymentPublic } from "@lib/validations/payment"; import { schemaQueryIdParseInt, @@ -38,7 +37,7 @@ import { export async function paymentById(req: NextApiRequest, res: NextApiResponse) { const { method, query } = req; const safeQuery = schemaQueryIdParseInt.safeParse(query); - const userId = getCalcomUserId(res); + const userId = req.userId; if (safeQuery.success && method === "GET") { const userWithBookings = await prisma.user.findUnique({ diff --git a/pages/api/payments/index.ts b/pages/api/payments/index.ts index bb2c132c0c..827bd68340 100644 --- a/pages/api/payments/index.ts +++ b/pages/api/payments/index.ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { PaymentsResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaPaymentPublic } from "@lib/validations/payment"; /** @@ -24,8 +23,8 @@ import { schemaPaymentPublic } from "@lib/validations/payment"; * 404: * description: No payments were found */ -async function allPayments(_: NextApiRequest, res: NextApiResponse) { - const userId = getCalcomUserId(res); +async function allPayments(req: NextApiRequest, res: NextApiResponse) { + const userId = req.userId; const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index 1b46e62269..e0b83f106b 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { ScheduleResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaScheduleBodyParams, schemaSchedulePublic } from "@lib/validations/schedule"; import { schemaQueryIdParseInt, @@ -91,7 +90,7 @@ export async function scheduleById(req: NextApiRequest, res: NextApiResponse schedule.id); if (userScheduleIds.includes(safeQuery.data.id)) { diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index cb4eeaeb9d..bbdd1c8dbc 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { ScheduleResponse, SchedulesResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaScheduleBodyParams, schemaSchedulePublic, withValidSchedule } from "@lib/validations/schedule"; /** @@ -43,7 +42,7 @@ async function createOrlistAllSchedules( res: NextApiResponse ) { const { method } = req; - const userId = getCalcomUserId(res); + const userId = req.userId; if (method === "GET") { const data = await prisma.schedule.findMany({ where: { userId } }); diff --git a/pages/api/selected-calendars/[id].ts b/pages/api/selected-calendars/[id].ts index 69cd9c059e..c2febd9c47 100644 --- a/pages/api/selected-calendars/[id].ts +++ b/pages/api/selected-calendars/[id].ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { SelectedCalendarResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaSelectedCalendarBodyParams, schemaSelectedCalendarPublic, @@ -132,7 +131,7 @@ export async function selectedCalendarById( if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); // This is how we set the userId and externalId in the query for managing compoundId. const [paramUserId, integration, externalId] = safeQuery.data.id.split("_"); - const userId = getCalcomUserId(res); + const userId = req.userId; if (userId === parseInt(paramUserId)) { switch (method) { case "GET": diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index cb12a5dac7..0ccde36943 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { SelectedCalendarResponse, SelectedCalendarsResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaSelectedCalendarBodyParams, schemaSelectedCalendarPublic, @@ -46,7 +45,7 @@ async function createOrlistAllSelectedCalendars( res: NextApiResponse ) { const { method } = req; - const userId = getCalcomUserId(res); + const userId = req.userId; if (method === "GET") { const data = await prisma.selectedCalendar.findMany({ where: { userId } }); diff --git a/pages/api/teams/[id].ts b/pages/api/teams/[id].ts index de14a27c3d..69a3a7091f 100644 --- a/pages/api/teams/[id].ts +++ b/pages/api/teams/[id].ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { TeamResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, @@ -91,7 +90,7 @@ export async function teamById(req: NextApiRequest, res: NextApiResponse) { const { method } = req; - const userId = getCalcomUserId(res); + const userId = req.userId; if (method === "GET") { const userWithMemberships = await prisma.membership.findMany({ where: { userId: userId }, diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index 5beaf442df..6dd4eb5f63 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { UserResponse } from "@lib/types"; -import { getCalcomUserId } from "@lib/utils/getCalcomUserId"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, @@ -91,7 +90,7 @@ export async function userById(req: NextApiRequest, res: NextApiResponse) { - const userId = getCalcomUserId(res); + const userId = req.userId; const data = await prisma.user.findMany({ where: { id: userId, diff --git a/tsconfig.json b/tsconfig.json index 5acb222ba6..4943d154a6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,23 +1,19 @@ { - "extends": "@calcom/tsconfig/base.json", - "exclude": ["node_modules", "templates"], + "extends": "@calcom/tsconfig/nextjs.json", "compilerOptions": { - "strictNullChecks": true, "baseUrl": ".", - - "target": "es5", - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "noEmit": true, - "incremental": true, - "module": "esnext", - "resolveJsonModule": true, - "jsx": "preserve", "paths": { "@api/*": ["pages/api/*"], "@lib/*": ["lib/*"], "@/*": ["*"] } }, - "include": ["./**/*.ts*"] + "include": [ + "next-env.d.ts", + "../../packages/types/*.d.ts", + "../../packages/types/next-auth.d.ts", + "**/*.ts", + "**/*.tsx" + ], + "exclude": ["node_modules", "templates"] } From 20cef3b4dd0078d85dc6decc563353f50803c732 Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 22 Apr 2022 08:05:31 -0600 Subject: [PATCH 136/658] Uses inferred types --- lib/helpers/verifyApiKey.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 0f70c88a8e..77eaf7e4cb 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -1,5 +1,4 @@ import type { IncomingMessage } from "http"; -import type { NextApiRequest, NextApiResponse } from "next"; import { NextMiddleware } from "next-api-middleware"; import { hashAPIKey } from "@calcom/ee/lib/api/apiKeys"; @@ -21,7 +20,7 @@ export const dateInPast = function (date: Date) { }; // This verifies the API key and sets the user if it is valid. -export const verifyApiKey: NextMiddleware = async (req: NextApiRequest, res: NextApiResponse, next) => { +export const verifyApiKey: NextMiddleware = async (req, res, next) => { if (!req.query.apiKey) return res.status(401).json({ message: "No api key provided" }); // We remove the prefix from the user provided api_key. If no env set default to "cal_" const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "cal_", ""); From 368e6eb0fa83115ffeaf8d2105644ce65363184c Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 23 Apr 2022 02:05:56 +0200 Subject: [PATCH 137/658] fix: rename dateInPast -> dateNotInPast --- lib/helpers/verifyApiKey.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 77eaf7e4cb..6a8c24df4e 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -12,7 +12,7 @@ declare module "next" { } // Used to check if the API key is not expired, could be extracted if reused. but not for now. -export const dateInPast = function (date: Date) { +export const dateNotInPast = function (date: Date) { const now = new Date(); if (now.setHours(0, 0, 0, 0) <= date.setHours(0, 0, 0, 0)) { return true; @@ -30,7 +30,7 @@ export const verifyApiKey: NextMiddleware = async (req, res, next) => { const apiKey = await prisma.apiKey.findUnique({ where: { hashedKey } }); // If we cannot find any api key. Throw a 401 Unauthorized. if (!apiKey) return res.status(401).json({ error: "Your api key is not valid" }); - if (apiKey.expiresAt && dateInPast(apiKey.expiresAt)) { + if (apiKey.expiresAt && dateNotInPast(apiKey.expiresAt)) { return res.status(401).json({ error: "This api key is expired" }); } if (!apiKey.userId) return res.status(404).json({ error: "No user found for this api key" }); From 9cb2f9bc704a0bb2d60fd19f7289265686113870 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 23 Apr 2022 02:06:16 +0200 Subject: [PATCH 138/658] fix: clearer note about dropping metadata and locations in event-type --- lib/validations/event-type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index ab24a9b0d1..119edcb248 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -12,7 +12,7 @@ const schemaEventTypeRequiredParams = z.object({ }); export const schemaEventTypeBodyParams = schemaEventTypeBaseBodyParams.merge(schemaEventTypeRequiredParams); -// Omitting those two (locations/ metadata) because the validations where choking at array and JSON object. add them later if needed +// @NOTE: Removing locations and metadata properties before validation, add them later if required export const schemaEventTypePublic = EventType.omit({ locations: true, metadata: true }); export const withValidEventType = withValidation({ From 307eddcbd528b24c6b6530f12176b1e4ac4db87e Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 23 Apr 2022 02:06:39 +0200 Subject: [PATCH 139/658] fix: invert 401 to throw early in attendees --- pages/api/attendees/[id].ts | 5 +++-- pages/api/attendees/index.ts | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index 3eba0891f2..03133bf526 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -100,7 +100,8 @@ export async function attendeeById(req: NextApiRequest, res: NextApiResponse booking.attendees).flat(); const attendeeIds = attendees.map((attendee) => attendee.id); // Here we make sure to only return attendee's of the user's own bookings. - if (attendeeIds.includes(safeQuery.data.id)) { + if (!attendeeIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); + else { switch (method) { case "GET": await prisma.attendee @@ -151,7 +152,7 @@ export async function attendeeById(req: NextApiRequest, res: NextApiResponse booking.id).flat(); - if (userBookingIds.includes(bookingId)) { + if (!userBookingIds.includes(bookingId)) res.status(401).json({ message: "Unauthorized" }); + else { delete safe.data.bookingId; const noBookingId = safe.data; const data = await prisma.attendee.create({ @@ -99,7 +100,7 @@ async function createOrlistAllAttendees( error, }); } - } else res.status(401).json({ message: "Unauthorized" }); + } } else res.status(405).json({ message: `Method ${method} not allowed` }); } From 8d5605dc7b449018c04b07f4ab45e86a4193da30 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 23 Apr 2022 02:17:06 +0200 Subject: [PATCH 140/658] fix: move 401 to throw early in all endpoints --- pages/api/availabilities/[id].ts | 5 ++--- pages/api/booking-references/index.ts | 5 +++-- pages/api/bookings/[id].ts | 5 +++-- pages/api/daily-event-references/[id].ts | 6 ++++-- pages/api/destination-calendars/[id].ts | 5 +++-- pages/api/event-type-custom-inputs/[id].ts | 6 ++++-- pages/api/event-types/[id].ts | 3 ++- pages/api/memberships/[id].ts | 5 +++-- pages/api/payments/[id].ts | 6 +++--- pages/api/schedules/[id].ts | 5 +++-- pages/api/selected-calendars/[id].ts | 5 +++-- pages/api/teams/[id].ts | 5 +++-- pages/api/users/[id].ts | 5 +++-- 13 files changed, 39 insertions(+), 27 deletions(-) diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index 546fbe0ce1..7d5bfb8b91 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -99,7 +99,8 @@ export async function availabilityById(req: NextApiRequest, res: NextApiResponse const userId = req.userId; const data = await prisma.availability.findMany({ where: { userId } }); const availabiltiesIds = data.map((availability) => availability.id); - if (availabiltiesIds.includes(safeQuery.data.id)) { + if (!availabiltiesIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); + else { switch (method) { case "GET": await prisma.availability @@ -142,8 +143,6 @@ export async function availabilityById(req: NextApiRequest, res: NextApiResponse res.status(405).json({ message: "Method not allowed" }); break; } - } else { - res.status(401).json({ message: "Unauthorized" }); } } diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index 03bc700596..74ae942dd2 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -80,7 +80,8 @@ async function createOrlistAllBookingReferences( throw new Error("User not found"); } const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); - if (userBookingIds.includes(safe.data.bookingId)) { + if (!userBookingIds.includes(safe.data.bookingId)) res.status(401).json({ message: "Unauthorized" }); + else { const booking_reference = await prisma.bookingReference.create({ data: { ...safe.data }, }); @@ -96,7 +97,7 @@ async function createOrlistAllBookingReferences( error, }); } - } else res.status(401).json({ message: "Unauthorized" }); + } } else res.status(405).json({ message: `Method ${method} not allowed` }); } diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index f40ae3ccbd..9172b7dc90 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -97,7 +97,8 @@ export async function bookingById(req: NextApiRequest, res: NextApiResponse booking.id).flat(); - if (userBookingIds.includes(safeQuery.data.id)) { + if (!userBookingIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); + else { switch (method) { case "GET": await prisma.booking @@ -151,7 +152,7 @@ export async function bookingById(req: NextApiRequest, res: NextApiResponse dailyEventReference.id ); - if (userBookingDailyEventReferenceIds.includes(safeQuery.data.id)) { + if (!userBookingDailyEventReferenceIds.includes(safeQuery.data.id)) + res.status(401).json({ message: "Unauthorized" }); + else { switch (method) { case "GET": await prisma.dailyEventReference @@ -158,7 +160,7 @@ export async function dailyEventReferenceById( res.status(405).json({ message: "Method not allowed" }); break; } - } else res.status(401).json({ message: "Unauthorized" }); + } } export default withMiddleware("HTTP_GET_DELETE_PATCH")( diff --git a/pages/api/destination-calendars/[id].ts b/pages/api/destination-calendars/[id].ts index 579ba83482..2f643d4120 100644 --- a/pages/api/destination-calendars/[id].ts +++ b/pages/api/destination-calendars/[id].ts @@ -101,7 +101,8 @@ export async function destionationCalendarById( const userDestinationCalendars = data.map((destinationCalendar) => destinationCalendar.id); // FIXME: Should we also check ownership of bokingId and eventTypeId to avoid users cross-pollinating other users calendars. // On a related note, moving from sequential integer IDs to UUIDs would be a good idea. and maybe help avoid having this problem. - if (userDestinationCalendars.includes(safeQuery.data.id)) { + if (userDestinationCalendars.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); + else { switch (method) { case "GET": await prisma.destinationCalendar @@ -154,7 +155,7 @@ export async function destionationCalendarById( res.status(405).json({ message: "Method not allowed" }); break; } - } else res.status(401).json({ message: "Unauthorized" }); + } } export default withMiddleware("HTTP_GET_DELETE_PATCH")( diff --git a/pages/api/event-type-custom-inputs/[id].ts b/pages/api/event-type-custom-inputs/[id].ts index 5ff11ff884..4df7114cef 100644 --- a/pages/api/event-type-custom-inputs/[id].ts +++ b/pages/api/event-type-custom-inputs/[id].ts @@ -102,7 +102,9 @@ async function eventTypeById(req: NextApiRequest, res: NextApiResponse eventTypeCustomInput.id ); - if (userEventTypeCustomInputIds.includes(safeQuery.data.id)) { + if (!userEventTypeCustomInputIds.includes(safeQuery.data.id)) + res.status(401).json({ message: "Unauthorized" }); + else { switch (method) { case "GET": await prisma.eventTypeCustomInput @@ -155,7 +157,7 @@ async function eventTypeById(req: NextApiRequest, res: NextApiResponse eventType.id); - if (userEventTypes.includes(safeQuery.data.id)) { + if (!userEventTypes.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); + else { switch (method) { case "GET": await prisma.eventType diff --git a/pages/api/memberships/[id].ts b/pages/api/memberships/[id].ts index 4c90122f70..acb8f03c0c 100644 --- a/pages/api/memberships/[id].ts +++ b/pages/api/memberships/[id].ts @@ -108,7 +108,8 @@ export async function membershipById(req: NextApiRequest, res: NextApiResponse schemaPaymentPublic.parse(data)) .then((payment) => { - if (userWithBookings?.bookings.map((b) => b.id).includes(payment.bookingId)) { - res.status(200).json({ payment }); - } else { + if (!userWithBookings?.bookings.map((b) => b.id).includes(payment.bookingId)) { res.status(401).json({ message: "Unauthorized" }); + } else { + res.status(200).json({ payment }); } }) .catch((error: Error) => diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index e0b83f106b..a8fa501412 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -93,7 +93,8 @@ export async function scheduleById(req: NextApiRequest, res: NextApiResponse schedule.id); - if (userScheduleIds.includes(safeQuery.data.id)) { + if (!userScheduleIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); + else { switch (method) { case "GET": await prisma.schedule @@ -144,7 +145,7 @@ export async function scheduleById(req: NextApiRequest, res: NextApiResponse membership.teamId); - if (userTeamIds.includes(safeQuery.data.id)) { + if (!userTeamIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); + else { switch (method) { case "GET": await prisma.team @@ -148,7 +149,7 @@ export async function teamById(req: NextApiRequest, res: NextApiResponse Date: Sat, 23 Apr 2022 02:22:43 +0200 Subject: [PATCH 141/658] fix: remove comments --- pages/api/event-type-custom-inputs/index.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/pages/api/event-type-custom-inputs/index.ts b/pages/api/event-type-custom-inputs/index.ts index 82c23f8593..5b3b249ab4 100644 --- a/pages/api/event-type-custom-inputs/index.ts +++ b/pages/api/event-type-custom-inputs/index.ts @@ -48,12 +48,7 @@ async function createOrlistAllEventTypeCustomInputs( const userId = req.userId; const data = await prisma.eventType.findMany({ where: { userId } }); const userEventTypes = data.map((eventType) => eventType.id); - // const userEventTypeCustomInputs = await prisma.eventTypeCustomInput.findMany({ - // where: { eventType: userEventTypes }, - // }); - // const userEventTypeCustomInputIds = userEventTypeCustomInputs.map( - // (eventTypeCustomInput) => eventTypeCustomInput.id - // ); + if (method === "GET") { const data = await prisma.eventTypeCustomInput.findMany({ where: { eventType: userEventTypes } }); const event_type_custom_inputs = data.map((eventTypeCustomInput) => From 4e8fae7391a25fe188a5ba8e9fcbee0dfdfb4ad1 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 23 Apr 2022 02:26:35 +0200 Subject: [PATCH 142/658] rename apiKey --- lib/helpers/verifyApiKey.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 6a8c24df4e..ab8115faab 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -11,7 +11,7 @@ declare module "next" { } } -// Used to check if the API key is not expired, could be extracted if reused. but not for now. +// Used to check if the apiKey is not expired, could be extracted if reused. but not for now. export const dateNotInPast = function (date: Date) { const now = new Date(); if (now.setHours(0, 0, 0, 0) <= date.setHours(0, 0, 0, 0)) { @@ -19,9 +19,9 @@ export const dateNotInPast = function (date: Date) { } }; -// This verifies the API key and sets the user if it is valid. +// This verifies the apiKey and sets the user if it is valid. export const verifyApiKey: NextMiddleware = async (req, res, next) => { - if (!req.query.apiKey) return res.status(401).json({ message: "No api key provided" }); + if (!req.query.apiKey) return res.status(401).json({ message: "No apiKey provided" }); // We remove the prefix from the user provided api_key. If no env set default to "cal_" const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "cal_", ""); // Hash the key again before matching against the database records. @@ -29,11 +29,11 @@ export const verifyApiKey: NextMiddleware = async (req, res, next) => { // Check if the hashed api key exists in database. const apiKey = await prisma.apiKey.findUnique({ where: { hashedKey } }); // If we cannot find any api key. Throw a 401 Unauthorized. - if (!apiKey) return res.status(401).json({ error: "Your api key is not valid" }); + if (!apiKey) return res.status(401).json({ error: "Your apiKey is not valid" }); if (apiKey.expiresAt && dateNotInPast(apiKey.expiresAt)) { - return res.status(401).json({ error: "This api key is expired" }); + return res.status(401).json({ error: "This apiKey is expired" }); } - if (!apiKey.userId) return res.status(404).json({ error: "No user found for this api key" }); + if (!apiKey.userId) return res.status(404).json({ error: "No user found for this apiKey" }); /* We save the user id in the request for later use */ req.userId = apiKey.userId; await next(); From 9078ee2f3f4de8c2bbbbd1d80d7eab0693b63136 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 23 Apr 2022 02:40:39 +0200 Subject: [PATCH 143/658] fix: build removing extra spaces --- pages/api/attendees/[id].ts | 2 +- pages/api/schedules/[id].ts | 14 ++++++++++++++ pages/api/users/[id].ts | 2 +- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index 03133bf526..6931c5d6df 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -100,7 +100,7 @@ export async function attendeeById(req: NextApiRequest, res: NextApiResponse booking.attendees).flat(); const attendeeIds = attendees.map((attendee) => attendee.id); // Here we make sure to only return attendee's of the user's own bookings. - if (!attendeeIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); + if (!attendeeIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { case "GET": diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index a8fa501412..9a6f67d826 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -126,6 +126,20 @@ export async function scheduleById(req: NextApiRequest, res: NextApiResponse diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index e1a11b3004..58fb826521 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -91,7 +91,7 @@ export async function userById(req: NextApiRequest, res: NextApiResponse Date: Sat, 23 Apr 2022 03:34:34 +0200 Subject: [PATCH 144/658] Update README.md --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 15cc019306..19baacdf58 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # Cal.com Public API (Enterprise Only) -This is the public REST api for cal.com. It exposes CRUD Endpoints of all our most important resources. It makes it easy for anyone to integrate with cal at the programming level. +This is the public REST api for cal.com. +It exposes CRUD Endpoints of all our most important resources. +And it makes it easy for anyone to integrate with Cal.com at the application programming level. ## Stack @@ -60,6 +62,11 @@ API Keys optionally may have expiry dates, if they are expired they won't work. In the future we might add support for header Bearer Auth if we need to or if our customers require it. +## Middlewares +We don't use the new NextJS 12 Beta Middlewares, mainly because they run on the edge, and are not able to call prisma from api endpoints. We use instead a very nifty library called next-api-middleware that let's us use a similar approach building our own middlewares and applying them as we see fit. + +* withMiddleware() requires some default middlewares (verifyApiKey, etc...) + ## Next.config.js ### Redirects From 11bf548241d9042adb3fb6703fbc5152be472c86 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 23 Apr 2022 03:46:53 +0200 Subject: [PATCH 145/658] fix: apiKeyExpire --- lib/helpers/verifyApiKey.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index ab8115faab..2c16a9baf6 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -14,7 +14,7 @@ declare module "next" { // Used to check if the apiKey is not expired, could be extracted if reused. but not for now. export const dateNotInPast = function (date: Date) { const now = new Date(); - if (now.setHours(0, 0, 0, 0) <= date.setHours(0, 0, 0, 0)) { + if (now.setHours(0, 0, 0, 0) >= date.setHours(0, 0, 0, 0)) { return true; } }; From 8c19303bafe15b672933503eab157b81138ffcb0 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 23 Apr 2022 05:37:36 +0200 Subject: [PATCH 146/658] fix: verify expire --- lib/helpers/verifyApiKey.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 2c16a9baf6..cf5c4a8472 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -14,7 +14,7 @@ declare module "next" { // Used to check if the apiKey is not expired, could be extracted if reused. but not for now. export const dateNotInPast = function (date: Date) { const now = new Date(); - if (now.setHours(0, 0, 0, 0) >= date.setHours(0, 0, 0, 0)) { + if (now.setHours(0, 0, 0, 0) > date.setHours(0, 0, 0, 0)) { return true; } }; From 096fd40044d31695e2250039fc6ea6ed7babfe63 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 23 Apr 2022 05:51:26 +0200 Subject: [PATCH 147/658] fix: fixess attends:id endpoit --- pages/api/attendees/index.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index 92335c3570..9fa493aa60 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -41,8 +41,7 @@ async function createOrlistAllAttendees( req: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; + const { method, userId } = req; // Here we make sure to only return attendee's of the user's own bookings. const userBookings = await prisma.booking.findMany({ where: { @@ -76,14 +75,16 @@ async function createOrlistAllAttendees( throw new Error("User not found"); } const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); - if (!userBookingIds.includes(bookingId)) res.status(401).json({ message: "Unauthorized" }); + // Here we make sure to only return attendee's of the user's own bookings. + if (!userBookingIds.includes(parseInt(safe.data.bookingId))) + res.status(401).json({ message: "Unauthorized" }); else { delete safe.data.bookingId; const noBookingId = safe.data; const data = await prisma.attendee.create({ data: { ...noBookingId, - booking: { connect: { id: bookingId } }, + booking: { connect: { id: parseInt(bookingId) } }, }, }); const attendee = schemaAttendeePublic.parse(data); From dad70d5a12ee83d673fa1c0d20994ef1a881b8f0 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 24 Apr 2022 02:10:32 +0200 Subject: [PATCH 148/658] fix users, availabilites, attendees --- lib/validations/availability.ts | 7 +-- lib/validations/user.ts | 84 ++++++++++++++++++++++--------- pages/api/attendees/[id].ts | 5 +- pages/api/availabilities/[id].ts | 12 +++-- pages/api/availabilities/index.ts | 2 + pages/api/users/[id].ts | 22 ++++---- pages/api/users/index.ts | 4 +- 7 files changed, 93 insertions(+), 43 deletions(-) diff --git a/lib/validations/availability.ts b/lib/validations/availability.ts index d55cfb74fa..ff7727a611 100644 --- a/lib/validations/availability.ts +++ b/lib/validations/availability.ts @@ -3,13 +3,14 @@ import { z } from "zod"; import { _AvailabilityModel as Availability } from "@calcom/prisma/zod"; -export const schemaAvailabilityBaseBodyParams = Availability.omit({ id: true }).partial(); +export const schemaAvailabilityBaseBodyParams = Availability.pick({ userId: true, eventTypeId: true, days: true }).partial(); export const schemaAvailabilityPublic = Availability.omit({}); const schemaAvailabilityRequiredParams = z.object({ - startTime: z.string(), - endTime: z.string(), + startTime: z.date().or(z.string()).optional(), + endTime: z.date().or(z.string()).optional(), + days: z.any().optional(), }); export const schemaAvailabilityBodyParams = schemaAvailabilityBaseBodyParams.merge( diff --git a/lib/validations/user.ts b/lib/validations/user.ts index ec3f7a2247..9c5d2777c2 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -3,34 +3,72 @@ import { z } from "zod"; import { _UserModel as User } from "@calcom/prisma/zod"; -export const schemaUserBaseBodyParams = User.omit({ - id: true, - createdAt: true, - password: true, - twoFactorEnabled: true, - twoFactorSecret: true, +// @note: These are the ONLY values allowed as weekStart. So user don't introduce bad data. +enum weekdays { + MONDAY = "Monday", + TUESDAY = "Tuesday", + WEDNESDAY = "Wednesday", + THURSDAY = "Thursday", + FRIDAY = "Friday", + SATURDAY = "Saturday", + SUNDAY = "Sunday", +} + +// @note: These are the values that are editable via PATCH method on the user Model +export const schemaUserBaseBodyParams = User.pick({ + name: true, + bio: true, + avatar: true, + timeZone: true, + weekStart: true, + endTime: true, + bufferTime: true, + theme: true, + defaultScheduleId: true, + locale: true, + timeFormat: true, + brandColor: true, + darkBrandColor: true, + allowDynamicBooking: true, + away: true, }).partial(); +// @note: partial() is used to allow for the user to edit only the fields they want to edit making all optional, +// if want to make any required do it in the schemaRequiredParams +// Here we can both require or not (adding optional or nullish) and also rewrite validations for any value +// for example making weekStart only accept weekdays as input const schemaUserRequiredParams = z.object({ - email: z.string().email(), + weekStart: z.nativeEnum(weekdays).optional(), }); -export const schemaUserBodyParams = schemaUserBaseBodyParams.merge(schemaUserRequiredParams); +// @note: These are the values that are editable via PATCH method on the user Model +export const schemaUserEditBodyParams = schemaUserBaseBodyParams.merge(schemaUserRequiredParams).omit({}); -export const schemaUserPublic = User.omit({ - identityProvider: true, - identityProviderId: true, - plan: true, - metadata: true, - password: true, - twoFactorEnabled: true, - twoFactorSecret: true, - trialEndsAt: true, - completedOnboarding: true, +// @note: These are the values that are always returned when reading a user +export const schemaUserReadPublic = User.pick({ + id: true, + username: true, + name: true, + email: true, + emailVerified: true, + bio: true, + avatar: true, + timeZone: true, + weekStart: true, + endTime: true, + bufferTime: true, + theme: true, + defaultScheduleId: true, + locale: true, + timeFormat: true, + brandColor: true, + darkBrandColor: true, + allowDynamicBooking: true, + away: true, + createdDate: true, + verified: true, + invitedTo: true, }); -export const withValidUser = withValidation({ - schema: schemaUserBodyParams, - type: "Zod", - mode: "body", -}); +// @note: This is the validation for the PATCH method on the user Model. Not used for now. +export const withValidUser = withValidation({ schema: schemaUserEditBodyParams, type: "Zod", mode: "body" }); diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index 6931c5d6df..0c456ea6e4 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -86,13 +86,13 @@ import { * description: Authorization information is missing or invalid. */ export async function attendeeById(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body } = req; + const { method, query, body, userId } = req; const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaAttendeeBodyParams.safeParse(body); if (!safeQuery.success) { + res.status(400).json({ error: safeQuery.error }); throw new Error("Invalid request query", safeQuery.error); } - const userId = req.userId; const userBookings = await prisma.booking.findMany({ where: { userId }, include: { attendees: true }, @@ -118,6 +118,7 @@ export async function attendeeById(req: NextApiRequest, res: NextApiResponse schemaAvailabilityPublic.parse(data)) .then((availability) => res.status(200).json({ availability })) - .catch((error: Error) => - res.status(404).json({ message: `Availability with id: ${safeQuery.data.id} not found`, error }) - ); + .catch((error: Error) => { + console.log(error); + res.status(404).json({ + message: `Availability with id: ${safeQuery.data.id} not found`, + error, + }); + }); break; case "DELETE": diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index a6310059f7..40923606e6 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -59,10 +59,12 @@ async function createOrlistAllAvailabilities( error, }); } else if (method === "POST") { + console.log(req.body); const safe = schemaAvailabilityBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.availability.create({ data: { ...safe.data, userId } }); + console.log(data); const availability = schemaAvailabilityPublic.parse(data); if (availability) res.status(201).json({ availability, message: "Availability created successfully" }); diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index 58fb826521..031ea71e0e 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -8,7 +8,7 @@ import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -import { schemaUserBodyParams, schemaUserPublic } from "@lib/validations/user"; +import { schemaUserEditBodyParams, schemaUserReadPublic, withValidUser } from "@lib/validations/user"; /** * @swagger @@ -85,19 +85,18 @@ import { schemaUserBodyParams, schemaUserPublic } from "@lib/validations/user"; * 401: * description: Authorization information is missing or invalid. */ -export async function userById(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body } = req; +export async function userById(req: NextApiRequest, res: NextApiResponse) { + const { method, query, body, userId } = req; const safeQuery = schemaQueryIdParseInt.safeParse(query); - const safeBody = schemaUserBodyParams.safeParse(body); + console.log(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = req.userId; if (safeQuery.data.id !== userId) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { case "GET": await prisma.user .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaUserPublic.parse(data)) + .then((data) => schemaUserReadPublic.parse(data)) .then((user) => res.status(200).json({ user })) .catch((error: Error) => res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) @@ -105,13 +104,18 @@ export async function userById(req: NextApiRequest, res: NextApiResponse schemaUserPublic.parse(data)) + .then((data) => schemaUserReadPublic.parse(data)) .then((user) => res.status(200).json({ user })) .catch((error: Error) => res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 73f2a46eb6..dfea9f1ff6 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -4,7 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { UsersResponse } from "@lib/types"; -import { schemaUserPublic } from "@lib/validations/user"; +import { schemaUserReadPublic } from "@lib/validations/user"; /** * @swagger @@ -30,7 +30,7 @@ async function allUsers(req: NextApiRequest, res: NextApiResponse id: userId, }, }); - const users = data.map((user) => schemaUserPublic.parse(user)); + const users = data.map((user) => schemaUserReadPublic.parse(user)); if (users) res.status(200).json({ users }); else (error: Error) => From 4c022d5d07c59f0da5436230aa63934663a7316e Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 24 Apr 2022 23:56:25 +0200 Subject: [PATCH 149/658] feat: adds full validations for users endpoint --- lib/validations/user.ts | 58 +++++++++++++++++++++++++++++++++++++++-- pages/api/users/[id].ts | 13 ++++++++- 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/lib/validations/user.ts b/lib/validations/user.ts index 9c5d2777c2..7452c6ad44 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -1,4 +1,5 @@ import { withValidation } from "next-validations"; +import * as tzdb from "tzdata"; import { z } from "zod"; import { _UserModel as User } from "@calcom/prisma/zod"; @@ -14,11 +15,45 @@ enum weekdays { SUNDAY = "Sunday", } +// @note: extracted from apps/web/next-i18next.config.js, update if new locales. +enum locales { + EN = "en", + FR = "fr", + IT = "it", + RU = "ru", + ES = "es", + DE = "de", + PT = "pt", + RO = "ro", + NL = "nl", + PT_BR = "pt-BR", + ES_419 = "es-419", + KO = "ko", + JA = "ja", + PL = "pl", + AR = "ar", + IW = "iw", + ZH_CN = "zh-CN", + ZH_TW = "zh-TW", + CS = "cs", + SR = "sr", + SV = "sv", + VI = "vi", +} +enum theme { + DARK = "dark", + LIGHT = "light", +} + +enum timeFormat { + TWELVE = 12, + TWENTY_FOUR = 24, +} + // @note: These are the values that are editable via PATCH method on the user Model export const schemaUserBaseBodyParams = User.pick({ name: true, bio: true, - avatar: true, timeZone: true, weekStart: true, endTime: true, @@ -31,6 +66,8 @@ export const schemaUserBaseBodyParams = User.pick({ darkBrandColor: true, allowDynamicBooking: true, away: true, + // @note: disallowing avatar changes via API for now. We can add it later if needed. User should upload image via UI. + // avatar: true, }).partial(); // @note: partial() is used to allow for the user to edit only the fields they want to edit making all optional, // if want to make any required do it in the schemaRequiredParams @@ -39,9 +76,26 @@ export const schemaUserBaseBodyParams = User.pick({ // for example making weekStart only accept weekdays as input const schemaUserRequiredParams = z.object({ weekStart: z.nativeEnum(weekdays).optional(), + brandColor: z.string().min(4).max(9).regex(/^#/).optional(), + timeZone: z + .string() + // @note: This is a custom validation that checks if the timezone is valid and exists in the tzdb library + .refine((tz: string) => Object.keys(tzdb.zones).includes(tz)) + .optional(), + bufferTime: z.number().min(0).max(86400).optional(), + startTime: z.number().min(0).max(86400).optional(), + endTime: z.number().min(0).max(86400).optional(), + theme: z.nativeEnum(theme).optional(), + timeFormat: z.nativeEnum(timeFormat).optional(), + defaultScheduleId: z + .number() + .refine((id: number) => id > 0) + .optional(), + locale: z.nativeEnum(locales), }); -// @note: These are the values that are editable via PATCH method on the user Model +// @note: These are the values that are editable via PATCH method on the user Model, +// merging both BaseBodyParams with RequiredParams, and omiting whatever we want at the end. export const schemaUserEditBodyParams = schemaUserBaseBodyParams.merge(schemaUserRequiredParams).omit({}); // @note: These are the values that are always returned when reading a user diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index 031ea71e0e..66386d38d8 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -104,12 +104,23 @@ export async function userById(req: NextApiRequest, res: NextApiResponse) { break; case "PATCH": - // FIXME: Validate body against different Edit validation, skip username. const safeBody = schemaUserEditBodyParams.safeParse(body); if (!safeBody.success) { res.status(400).json({ message: "Bad request", error: safeBody.error }); throw new Error("Invalid request body"); } + const userSchedules = await prisma.schedule.findMany({ + where: { userId }, + }); + const userSchedulesIds = userSchedules.map((schedule) => schedule.id); + // @note: here we make sure user can only make as default his own scheudles + if (!userSchedulesIds.includes(Number(safeBody?.data?.defaultScheduleId))) { + res.status(400).json({ + message: "Bad request", + error: "Invalid default schedule id", + }); + throw new Error("Invalid request body value: defaultScheduleId"); + } await prisma.user .update({ where: { id: userId }, From df43d50a55398bef75e3f7f3af2277a65a7318d9 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 24 Apr 2022 23:56:53 +0200 Subject: [PATCH 150/658] adds tzdata for timeZone validations --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 5739292e02..0c1cb9556e 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "next-swagger-doc": "^0.2.1", "next-transpile-modules": "^9.0.0", "next-validations": "^0.1.11", - "typescript": "^4.6.3" + "typescript": "^4.6.3", + "tzdata": "^1.0.30" } } From b38f78bbad73e793a7070eaa030b6d969a91434b Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 24 Apr 2022 23:57:17 +0200 Subject: [PATCH 151/658] fix: remove withValidSchedule from get/patch/delete shared endpoint --- pages/api/schedules/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index bbdd1c8dbc..bd9a38a9ef 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -70,4 +70,4 @@ async function createOrlistAllSchedules( } else res.status(405).json({ message: `Method ${method} not allowed` }); } -export default withMiddleware("HTTP_GET_OR_POST")(withValidSchedule(createOrlistAllSchedules)); +export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllSchedules); From 804fe27458ea53004b036a6fe7880f4aed757f41 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 25 Apr 2022 03:12:33 +0200 Subject: [PATCH 152/658] fix availabilites validations --- lib/validations/availability.ts | 15 +++++++++++---- pages/api/availabilities/[id].ts | 11 +++++++++-- pages/api/users/[id].ts | 8 +++----- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/lib/validations/availability.ts b/lib/validations/availability.ts index ff7727a611..49f9f2a04e 100644 --- a/lib/validations/availability.ts +++ b/lib/validations/availability.ts @@ -3,14 +3,21 @@ import { z } from "zod"; import { _AvailabilityModel as Availability } from "@calcom/prisma/zod"; -export const schemaAvailabilityBaseBodyParams = Availability.pick({ userId: true, eventTypeId: true, days: true }).partial(); +export const schemaAvailabilityBaseBodyParams = Availability.pick({ + startTime: true, + endTime: true, + date: true, + scheduleId: true, + days: true, +}).partial(); export const schemaAvailabilityPublic = Availability.omit({}); const schemaAvailabilityRequiredParams = z.object({ - startTime: z.date().or(z.string()).optional(), - endTime: z.date().or(z.string()).optional(), - days: z.any().optional(), + startTime: z.date().or(z.number()), + endTime: z.date().or(z.number()), + days: z.array(z.number()).optional(), + eventTypeId: z.number().optional(), }); export const schemaAvailabilityBodyParams = schemaAvailabilityBaseBodyParams.merge( diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index 97a2df6c63..8e2fcd724a 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -94,7 +94,6 @@ import { export async function availabilityById(req: NextApiRequest, res: NextApiResponse) { const { method, query, body } = req; const safeQuery = schemaQueryIdParseInt.safeParse(query); - const safeBody = schemaAvailabilityBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); const userId = req.userId; const data = await prisma.availability.findMany({ where: { userId } }); @@ -113,8 +112,16 @@ export async function availabilityById(req: NextApiRequest, res: NextApiResponse break; case "PATCH": + const safeBody = schemaAvailabilityBodyParams.safeParse(body); + if (!safeBody.success) throw new Error("Invalid request body"); - const edited = await prisma.availability + const userEventTypes = await prisma.eventType.findMany({ where: { userId } }); + const userEventTypesIds = userEventTypes.map((event) => event.id); + if (safeBody.data.eventTypeId && !userEventTypesIds.includes(safeBody.data.eventTypeId)) { + res.status(401).json({ message: "Bad request. You're not the owner of eventTypeId" }); + // throw new Error("Bad request. You're not the owner of eventTypeId"); + } + await prisma.availability .update({ where: { id: safeQuery.data.id }, data: safeBody.data, diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index 66386d38d8..e7e35d5e6e 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -39,12 +39,10 @@ import { schemaUserEditBodyParams, schemaUserReadPublic, withValidUser } from "@ * - application/json * parameters: * - in: body - * name: user - * description: The user to edit + * name: name + * description: The users full name * schema: - * type: object - * $ref: '#/components/schemas/User' - * required: true + * type: string * - in: path * name: id * schema: From b6bce18b2996772b5671e9c7290e95fa5eb5ae44 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 25 Apr 2022 06:04:42 +0200 Subject: [PATCH 153/658] fix: build availabilities validation start/endTime accept only dates no numbers or strings too --- lib/validations/availability.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/validations/availability.ts b/lib/validations/availability.ts index 49f9f2a04e..4400ff2bad 100644 --- a/lib/validations/availability.ts +++ b/lib/validations/availability.ts @@ -14,8 +14,8 @@ export const schemaAvailabilityBaseBodyParams = Availability.pick({ export const schemaAvailabilityPublic = Availability.omit({}); const schemaAvailabilityRequiredParams = z.object({ - startTime: z.date().or(z.number()), - endTime: z.date().or(z.number()), + startTime: z.date(), + endTime: z.date(), days: z.array(z.number()).optional(), eventTypeId: z.number().optional(), }); From ad04be939403f29d657716fe77a87b098d74732a Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 25 Apr 2022 06:13:27 +0200 Subject: [PATCH 154/658] fix: availability patch --- lib/validations/availability.ts | 4 ++-- pages/api/availabilities/[id].ts | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/validations/availability.ts b/lib/validations/availability.ts index 4400ff2bad..20e3c61c94 100644 --- a/lib/validations/availability.ts +++ b/lib/validations/availability.ts @@ -14,8 +14,8 @@ export const schemaAvailabilityBaseBodyParams = Availability.pick({ export const schemaAvailabilityPublic = Availability.omit({}); const schemaAvailabilityRequiredParams = z.object({ - startTime: z.date(), - endTime: z.date(), + startTime: z.date().or(z.string()).optional(), + endTime: z.date().or(z.string()).optional(), days: z.array(z.number()).optional(), eventTypeId: z.number().optional(), }); diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index 8e2fcd724a..5c154cf0f8 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -93,6 +93,7 @@ import { */ export async function availabilityById(req: NextApiRequest, res: NextApiResponse) { const { method, query, body } = req; + const safeBody = schemaAvailabilityBodyParams.safeParse(body); const safeQuery = schemaQueryIdParseInt.safeParse(query); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); const userId = req.userId; @@ -112,14 +113,14 @@ export async function availabilityById(req: NextApiRequest, res: NextApiResponse break; case "PATCH": - const safeBody = schemaAvailabilityBodyParams.safeParse(body); if (!safeBody.success) throw new Error("Invalid request body"); const userEventTypes = await prisma.eventType.findMany({ where: { userId } }); const userEventTypesIds = userEventTypes.map((event) => event.id); if (safeBody.data.eventTypeId && !userEventTypesIds.includes(safeBody.data.eventTypeId)) { - res.status(401).json({ message: "Bad request. You're not the owner of eventTypeId" }); - // throw new Error("Bad request. You're not the owner of eventTypeId"); + res.status(401).json({ + message: `Bad request. You're not the owner of eventTypeId: ${safeBody.data.eventTypeId}`, + }); } await prisma.availability .update({ From fa30b529887a25bf419da3d9a228b0f191126f87 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 26 Apr 2022 21:56:59 +0200 Subject: [PATCH 155/658] remove v1 from specs --- pages/api/attendees/[id].ts | 2 +- pages/api/attendees/index.ts | 2 +- pages/api/availabilities/[id].ts | 2 +- pages/api/availabilities/index.ts | 2 +- pages/api/booking-references/[id].ts | 2 +- pages/api/booking-references/index.ts | 2 +- pages/api/bookings/[id].ts | 2 +- pages/api/bookings/index.ts | 2 +- pages/api/daily-event-references/[id].ts | 2 +- pages/api/daily-event-references/index.ts | 2 +- pages/api/destination-calendars/[id].ts | 2 +- pages/api/destination-calendars/index.ts | 2 +- pages/api/docs.ts | 25 ++++++++++++++++++++- pages/api/event-type-custom-inputs/[id].ts | 2 +- pages/api/event-type-custom-inputs/index.ts | 2 +- pages/api/event-types/[id].ts | 2 +- pages/api/event-types/index.ts | 2 +- pages/api/memberships/[id].ts | 2 +- pages/api/memberships/index.ts | 2 +- pages/api/payments/[id].ts | 2 +- pages/api/payments/index.ts | 2 +- pages/api/schedules/[id].ts | 2 +- pages/api/schedules/index.ts | 2 +- pages/api/selected-calendars/[id].ts | 2 +- pages/api/selected-calendars/index.ts | 2 +- pages/api/teams/[id].ts | 2 +- pages/api/teams/index.ts | 2 +- pages/api/users/[id].ts | 2 +- pages/api/users/index.ts | 2 +- 29 files changed, 52 insertions(+), 29 deletions(-) diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index 0c456ea6e4..e6780c6929 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -12,7 +12,7 @@ import { /** * @swagger - * /v1/attendees/{id}: + * /attendees/{id}: * get: * summary: Get an attendee by ID * parameters: diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index 9fa493aa60..8705fea6a8 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -8,7 +8,7 @@ import { schemaAttendeeBodyParams, schemaAttendeePublic, withValidAttendee } fro /** * @swagger - * /v1/attendees: + * /attendees: * get: * summary: Get all attendees * security: diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index 5c154cf0f8..cd277b058e 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -12,7 +12,7 @@ import { /** * @swagger - * /v1/availabilities/{id}: + * /availabilities/{id}: * get: * summary: Get an availability by ID * parameters: diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index 40923606e6..ab7aa3b388 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -8,7 +8,7 @@ import { schemaAvailabilityBodyParams, schemaAvailabilityPublic } from "@lib/val /** * @swagger - * /v1/availabilities: + * /availabilities: * get: * summary: Get all availabilities * security: diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index 1644041b2f..5f08ab4c0d 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -16,7 +16,7 @@ import { /** * @swagger - * /v1/booking-references/{id}: + * /booking-references/{id}: * get: * summary: Get a daily event reference by ID * parameters: diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index 74ae942dd2..f77b0c586d 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -11,7 +11,7 @@ import { /** * @swagger - * /v1/booking-references: + * /booking-references: * get: * summary: Get all booking references * security: diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index 9172b7dc90..c0b74d09f8 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -12,7 +12,7 @@ import { /** * @swagger - * /v1/bookings/{id}: + * /bookings/{id}: * get: * summary: Get a booking by ID * parameters: diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 9512847ea1..cb0f2089ed 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -8,7 +8,7 @@ import { schemaBookingBodyParams, schemaBookingPublic, withValidBooking } from " /** * @swagger - * /v1/bookings: + * /bookings: * get: * summary: Get all bookings * security: diff --git a/pages/api/daily-event-references/[id].ts b/pages/api/daily-event-references/[id].ts index b8bb8dc88c..280ad0c623 100644 --- a/pages/api/daily-event-references/[id].ts +++ b/pages/api/daily-event-references/[id].ts @@ -15,7 +15,7 @@ import { /** * @swagger - * /v1/daily-event-references/{id}: + * /daily-event-references/{id}: * get: * summary: Get a daily event reference by ID * parameters: diff --git a/pages/api/daily-event-references/index.ts b/pages/api/daily-event-references/index.ts index 7b216d0040..670b18421c 100644 --- a/pages/api/daily-event-references/index.ts +++ b/pages/api/daily-event-references/index.ts @@ -11,7 +11,7 @@ import { /** * @swagger - * /v1/daily-event-references: + * /daily-event-references: * get: * summary: Get all daily event reference * security: diff --git a/pages/api/destination-calendars/[id].ts b/pages/api/destination-calendars/[id].ts index 2f643d4120..f5ba4d90ee 100644 --- a/pages/api/destination-calendars/[id].ts +++ b/pages/api/destination-calendars/[id].ts @@ -15,7 +15,7 @@ import { /** * @swagger - * /v1/destination-calendars/{id}: + * /destination-calendars/{id}: * get: * summary: Get a destination calendar by ID * parameters: diff --git a/pages/api/destination-calendars/index.ts b/pages/api/destination-calendars/index.ts index b3bdcaab57..782612518c 100644 --- a/pages/api/destination-calendars/index.ts +++ b/pages/api/destination-calendars/index.ts @@ -11,7 +11,7 @@ import { /** * @swagger - * /v1/destination-calendars: + * /destination-calendars: * get: * summary: Get all destination calendars * security: diff --git a/pages/api/docs.ts b/pages/api/docs.ts index 3c9f50cfed..25d9c7ce1b 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -5,6 +5,15 @@ import { withSwagger } from "next-swagger-doc"; const swaggerHandler = withSwagger({ definition: { openapi: "3.0.0", + servers: [ + { url: "https://api.cal.com/v1" }, + { url: "https://api.cal.dev/v1" }, + { url: "http://localhost:3002/v1" }, + ], + externalDocs: { + url: "https://docs.cal.com", + description: "Find more info at our main docs: https://docs.cal.com/", + }, info: { title: `${pjson.name}: ${pjson.description}`, version: pjson.version, @@ -15,7 +24,21 @@ const swaggerHandler = withSwagger({ }, }, apiFolder: "pages/api", - tags: ["users", "teams", "memeberships"], + tags: [ + "users", + "teams", + "memeberships", + "selected-calendars", + "schedules", + "payments", + "event-types", + "event-type-custom-inputs", + "destination-calendars", + "daily-event-references", + "booking-references", + "availabilities", + "attendees", + ], sort: true, }); export default swaggerHandler(); diff --git a/pages/api/event-type-custom-inputs/[id].ts b/pages/api/event-type-custom-inputs/[id].ts index 4df7114cef..23e4c73a9a 100644 --- a/pages/api/event-type-custom-inputs/[id].ts +++ b/pages/api/event-type-custom-inputs/[id].ts @@ -15,7 +15,7 @@ import { /** * @swagger - * /v1/event-type-custom-inputs/{id}: + * /event-type-custom-inputs/{id}: * get: * summary: Get a eventTypeCustomInput by ID * parameters: diff --git a/pages/api/event-type-custom-inputs/index.ts b/pages/api/event-type-custom-inputs/index.ts index 5b3b249ab4..f1931b8b12 100644 --- a/pages/api/event-type-custom-inputs/index.ts +++ b/pages/api/event-type-custom-inputs/index.ts @@ -11,7 +11,7 @@ import { /** * @swagger - * /v1/event-type-custom-inputs: + * /event-type-custom-inputs: * get: * summary: Get all eventTypeCustomInputs * security: diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 94dd09dee2..465e85b428 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -12,7 +12,7 @@ import { /** * @swagger - * /v1/event-types/{id}: + * /event-types/{id}: * get: * summary: Get a eventType by ID * parameters: diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 3135d9e866..9d73be9458 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -8,7 +8,7 @@ import { schemaEventTypeBodyParams, schemaEventTypePublic } from "@lib/validatio /** * @swagger - * /v1/event-types: + * /event-types: * get: * summary: Get all event types * security: diff --git a/pages/api/memberships/[id].ts b/pages/api/memberships/[id].ts index acb8f03c0c..c4a1d362f7 100644 --- a/pages/api/memberships/[id].ts +++ b/pages/api/memberships/[id].ts @@ -9,7 +9,7 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ /** * @swagger - * /v1/memberships/{userId}_{teamId}: + * /memberships/{userId}_{teamId}: * get: * summary: Get a membership by userID and teamID * parameters: diff --git a/pages/api/memberships/index.ts b/pages/api/memberships/index.ts index 6402ac8ca4..702effdfd6 100644 --- a/pages/api/memberships/index.ts +++ b/pages/api/memberships/index.ts @@ -8,7 +8,7 @@ import { schemaMembershipBodyParams, schemaMembershipPublic } from "@lib/validat /** * @swagger - * /v1/memberships: + * /memberships: * get: * summary: Get all memberships * security: diff --git a/pages/api/payments/[id].ts b/pages/api/payments/[id].ts index 3f23750b2a..6ccf227641 100644 --- a/pages/api/payments/[id].ts +++ b/pages/api/payments/[id].ts @@ -12,7 +12,7 @@ import { /** * @swagger - * /v1/payments/{id}: + * /payments/{id}: * get: * summary: Get one of your own payments by ID * parameters: diff --git a/pages/api/payments/index.ts b/pages/api/payments/index.ts index 827bd68340..2b00d85ebb 100644 --- a/pages/api/payments/index.ts +++ b/pages/api/payments/index.ts @@ -8,7 +8,7 @@ import { schemaPaymentPublic } from "@lib/validations/payment"; /** * @swagger - * /v1/payments: + * /payments: * get: * summary: Get all payments * security: diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index 9a6f67d826..154dfa41f1 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -12,7 +12,7 @@ import { /** * @swagger - * /v1/schedules/{id}: + * /schedules/{id}: * get: * summary: Get a schedule by ID * parameters: diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index bd9a38a9ef..d04d35cccb 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -8,7 +8,7 @@ import { schemaScheduleBodyParams, schemaSchedulePublic, withValidSchedule } fro /** * @swagger - * /v1/schedules: + * /schedules: * get: * summary: Get all schedules * security: diff --git a/pages/api/selected-calendars/[id].ts b/pages/api/selected-calendars/[id].ts index 5c00b3895f..1b3e5e9cd5 100644 --- a/pages/api/selected-calendars/[id].ts +++ b/pages/api/selected-calendars/[id].ts @@ -12,7 +12,7 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ /** * @swagger - * /v1/selected-calendars/{userId}_{integration}_{externalId}: + * /selected-calendars/{userId}_{integration}_{externalId}: * get: * summary: Get a selected-calendar by userID and teamID * parameters: diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index 0ccde36943..d9b80a8541 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -11,7 +11,7 @@ import { /** * @swagger - * /v1/selected-calendars: + * /selected-calendars: * get: * summary: Get all selected calendars * security: diff --git a/pages/api/teams/[id].ts b/pages/api/teams/[id].ts index f74937ecc5..2990d3642b 100644 --- a/pages/api/teams/[id].ts +++ b/pages/api/teams/[id].ts @@ -12,7 +12,7 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; /** * @swagger - * /v1/teams/{id}: + * /teams/{id}: * get: * summary: Get a team by ID * parameters: diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index 045fc25461..d6392e0c1b 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -9,7 +9,7 @@ import { schemaTeamBodyParams, schemaTeamPublic, withValidTeam } from "@lib/vali /** * @swagger - * /v1/teams: + * /teams: * get: * summary: Get all teams * security: diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index e7e35d5e6e..24bf1075ed 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -12,7 +12,7 @@ import { schemaUserEditBodyParams, schemaUserReadPublic, withValidUser } from "@ /** * @swagger - * /v1/users/{id}: + * /users/{id}: * get: * summary: Get a user by ID, returns your user if regular user. * parameters: diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index dfea9f1ff6..aa35dca042 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -8,7 +8,7 @@ import { schemaUserReadPublic } from "@lib/validations/user"; /** * @swagger - * /v1/users: + * /users: * get: * summary: Get all users (admin only), returns your user if regular user. * security: From 3759eccfca19433b9215d2f360c4287ee58135ea Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 26 Apr 2022 22:12:28 +0200 Subject: [PATCH 156/658] fix: attendees move to use pick, separate patch/post --- lib/validations/attendee.ts | 27 +++++++++++++++++++-------- lib/validations/user.ts | 7 ++----- pages/api/attendees/[id].ts | 4 ++-- pages/api/attendees/index.ts | 4 ++-- 4 files changed, 25 insertions(+), 17 deletions(-) diff --git a/lib/validations/attendee.ts b/lib/validations/attendee.ts index 290ea16adf..5b7fee4e7f 100644 --- a/lib/validations/attendee.ts +++ b/lib/validations/attendee.ts @@ -3,21 +3,32 @@ import { z } from "zod"; import { _AttendeeModel as Attendee } from "@calcom/prisma/zod"; -export const schemaAttendeeBaseBodyParams = Attendee.omit({ id: true }).partial(); +export const schemaAttendeeBaseBodyParams = Attendee.pick({ + bookingId: true, + email: true, + name: true, + timeZone: true, +}).partial(); export const schemaAttendeePublic = Attendee.omit({}); -const schemaAttendeeRequiredParams = z.object({ +const schemaAttendeeCreateRequiredParams = z.object({ bookingId: z.any(), email: z.string().email(), name: z.string(), timeZone: z.string(), }); -export const schemaAttendeeBodyParams = schemaAttendeeBaseBodyParams.merge(schemaAttendeeRequiredParams); - -export const withValidAttendee = withValidation({ - schema: schemaAttendeeBodyParams, - type: "Zod", - mode: "body", +const schemaAttendeeEditeRequiredParams = z.object({ + // bookingId: z.any(), + // @note: disallowing email changes in attendee via API for now. + // email: z.string().email(), + name: z.string(), + timeZone: z.string(), }); +export const schemaAttendeeEditBodyParams = schemaAttendeeBaseBodyParams.merge( + schemaAttendeeEditeRequiredParams +); +export const schemaAttendeeCreateBodyParams = schemaAttendeeBaseBodyParams.merge( + schemaAttendeeCreateRequiredParams +); diff --git a/lib/validations/user.ts b/lib/validations/user.ts index 7452c6ad44..c3e26e9cb0 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -74,7 +74,7 @@ export const schemaUserBaseBodyParams = User.pick({ // Here we can both require or not (adding optional or nullish) and also rewrite validations for any value // for example making weekStart only accept weekdays as input -const schemaUserRequiredParams = z.object({ +const schemaUserEditParams = z.object({ weekStart: z.nativeEnum(weekdays).optional(), brandColor: z.string().min(4).max(9).regex(/^#/).optional(), timeZone: z @@ -96,7 +96,7 @@ const schemaUserRequiredParams = z.object({ // @note: These are the values that are editable via PATCH method on the user Model, // merging both BaseBodyParams with RequiredParams, and omiting whatever we want at the end. -export const schemaUserEditBodyParams = schemaUserBaseBodyParams.merge(schemaUserRequiredParams).omit({}); +export const schemaUserEditBodyParams = schemaUserBaseBodyParams.merge(schemaUserEditParams).omit({}); // @note: These are the values that are always returned when reading a user export const schemaUserReadPublic = User.pick({ @@ -123,6 +123,3 @@ export const schemaUserReadPublic = User.pick({ verified: true, invitedTo: true, }); - -// @note: This is the validation for the PATCH method on the user Model. Not used for now. -export const withValidUser = withValidation({ schema: schemaUserEditBodyParams, type: "Zod", mode: "body" }); diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index e6780c6929..23712e58b6 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -4,7 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { AttendeeResponse } from "@lib/types"; -import { schemaAttendeeBodyParams, schemaAttendeePublic } from "@lib/validations/attendee"; +import { schemaAttendeeEditBodyParams, schemaAttendeePublic } from "@lib/validations/attendee"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, @@ -88,7 +88,6 @@ import { export async function attendeeById(req: NextApiRequest, res: NextApiResponse) { const { method, query, body, userId } = req; const safeQuery = schemaQueryIdParseInt.safeParse(query); - const safeBody = schemaAttendeeBodyParams.safeParse(body); if (!safeQuery.success) { res.status(400).json({ error: safeQuery.error }); throw new Error("Invalid request query", safeQuery.error); @@ -117,6 +116,7 @@ export async function attendeeById(req: NextApiRequest, res: NextApiResponse Date: Tue, 26 Apr 2022 22:23:33 +0200 Subject: [PATCH 157/658] fix: moves to pick and separates availabilities --- lib/validations/attendee.ts | 21 +++++++++++--------- lib/validations/availability.ts | 33 ++++++++++++++++++++----------- pages/api/attendees/[id].ts | 6 +++--- pages/api/attendees/index.ts | 4 ++-- pages/api/availabilities/[id].ts | 9 ++++----- pages/api/availabilities/index.ts | 9 ++++----- pages/api/users/[id].ts | 2 +- 7 files changed, 48 insertions(+), 36 deletions(-) diff --git a/lib/validations/attendee.ts b/lib/validations/attendee.ts index 5b7fee4e7f..e0b91fb309 100644 --- a/lib/validations/attendee.ts +++ b/lib/validations/attendee.ts @@ -10,25 +10,28 @@ export const schemaAttendeeBaseBodyParams = Attendee.pick({ timeZone: true, }).partial(); -export const schemaAttendeePublic = Attendee.omit({}); - -const schemaAttendeeCreateRequiredParams = z.object({ +const schemaAttendeeCreateParams = z.object({ bookingId: z.any(), email: z.string().email(), name: z.string(), timeZone: z.string(), }); -const schemaAttendeeEditeRequiredParams = z.object({ - // bookingId: z.any(), - // @note: disallowing email changes in attendee via API for now. - // email: z.string().email(), +const schemaAttendeeEditParams = z.object({ + // @note: disallowing email/bookingId changes in attendee via API for now as it would introduce side effects name: z.string(), timeZone: z.string(), }); export const schemaAttendeeEditBodyParams = schemaAttendeeBaseBodyParams.merge( - schemaAttendeeEditeRequiredParams + schemaAttendeeEditParams ); export const schemaAttendeeCreateBodyParams = schemaAttendeeBaseBodyParams.merge( - schemaAttendeeCreateRequiredParams + schemaAttendeeCreateParams ); + +export const schemaAttendeeReadPublic = Attendee.pick({ + bookingId: true, + name: true, + email: true, + timeZone: true, +}); diff --git a/lib/validations/availability.ts b/lib/validations/availability.ts index 20e3c61c94..be4691cf0e 100644 --- a/lib/validations/availability.ts +++ b/lib/validations/availability.ts @@ -11,21 +11,32 @@ export const schemaAvailabilityBaseBodyParams = Availability.pick({ days: true, }).partial(); -export const schemaAvailabilityPublic = Availability.omit({}); +export const schemaAvailabilityPublic = Availability.pick({ + startTime: true, + endTime: true, + date: true, + scheduleId: true, + days: true, + userId: true, + eventTypeId: true, +}); -const schemaAvailabilityRequiredParams = z.object({ +const schemaAvailabilityCreateParams = z.object({ + startTime: z.date().or(z.string()), + endTime: z.date().or(z.string()), + days: z.array(z.number()).optional(), + eventTypeId: z.number().optional(), +}); + +const schemaAvailabilityEditParams = z.object({ startTime: z.date().or(z.string()).optional(), endTime: z.date().or(z.string()).optional(), days: z.array(z.number()).optional(), eventTypeId: z.number().optional(), }); - -export const schemaAvailabilityBodyParams = schemaAvailabilityBaseBodyParams.merge( - schemaAvailabilityRequiredParams +export const schemaAvailabilityEditBodyParams = schemaAvailabilityBaseBodyParams.merge( + schemaAvailabilityEditParams +); +export const schemaAvailabilityCreateBodyParams = schemaAvailabilityBaseBodyParams.merge( + schemaAvailabilityCreateParams ); - -export const withValidAvailability = withValidation({ - schema: schemaAvailabilityBodyParams, - type: "Zod", - mode: "body", -}); diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index 23712e58b6..4d6aecd7f1 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -4,7 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { AttendeeResponse } from "@lib/types"; -import { schemaAttendeeEditBodyParams, schemaAttendeePublic } from "@lib/validations/attendee"; +import { schemaAttendeeEditBodyParams, schemaAttendeeReadPublic } from "@lib/validations/attendee"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, @@ -105,7 +105,7 @@ export async function attendeeById(req: NextApiRequest, res: NextApiResponse schemaAttendeePublic.parse(data)) + .then((data) => schemaAttendeeReadPublic.parse(data)) .then((attendee) => res.status(200).json({ attendee })) .catch((error: Error) => res.status(404).json({ @@ -123,7 +123,7 @@ export async function attendeeById(req: NextApiRequest, res: NextApiResponse schemaAttendeePublic.parse(data)) + .then((data) => schemaAttendeeReadPublic.parse(data)) .then((attendee) => res.status(200).json({ attendee })) .catch((error: Error) => res.status(404).json({ diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index ffab82e919..80afde914a 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -4,7 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { AttendeeResponse, AttendeesResponse } from "@lib/types"; -import { schemaAttendeeCreateBodyParams, schemaAttendeePublic } from "@lib/validations/attendee"; +import { schemaAttendeeCreateBodyParams, schemaAttendeeReadPublic } from "@lib/validations/attendee"; /** * @swagger @@ -87,7 +87,7 @@ async function createOrlistAllAttendees( booking: { connect: { id: parseInt(bookingId) } }, }, }); - const attendee = schemaAttendeePublic.parse(data); + const attendee = schemaAttendeeReadPublic.parse(data); if (attendee) { res.status(201).json({ diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index cd277b058e..c77574692a 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -4,7 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { AvailabilityResponse } from "@lib/types"; -import { schemaAvailabilityBodyParams, schemaAvailabilityPublic } from "@lib/validations/availability"; +import { schemaAvailabilityEditBodyParams, schemaAvailabilityReadPublic } from "@lib/validations/availability"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, @@ -93,7 +93,6 @@ import { */ export async function availabilityById(req: NextApiRequest, res: NextApiResponse) { const { method, query, body } = req; - const safeBody = schemaAvailabilityBodyParams.safeParse(body); const safeQuery = schemaQueryIdParseInt.safeParse(query); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); const userId = req.userId; @@ -105,7 +104,7 @@ export async function availabilityById(req: NextApiRequest, res: NextApiResponse case "GET": await prisma.availability .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaAvailabilityPublic.parse(data)) + .then((data) => schemaAvailabilityReadPublic.parse(data)) .then((availability) => res.status(200).json({ availability })) .catch((error: Error) => res.status(404).json({ message: `Availability with id: ${safeQuery.data.id} not found`, error }) @@ -113,7 +112,7 @@ export async function availabilityById(req: NextApiRequest, res: NextApiResponse break; case "PATCH": - + const safeBody = schemaAvailabilityEditBodyParams.safeParse(body); if (!safeBody.success) throw new Error("Invalid request body"); const userEventTypes = await prisma.eventType.findMany({ where: { userId } }); const userEventTypesIds = userEventTypes.map((event) => event.id); @@ -127,7 +126,7 @@ export async function availabilityById(req: NextApiRequest, res: NextApiResponse where: { id: safeQuery.data.id }, data: safeBody.data, }) - .then((data) => schemaAvailabilityPublic.parse(data)) + .then((data) => schemaAvailabilityReadPublic.parse(data)) .then((availability) => res.status(200).json({ availability })) .catch((error: Error) => { console.log(error); diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index ab7aa3b388..999639dc37 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -4,7 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { AvailabilityResponse, AvailabilitiesResponse } from "@lib/types"; -import { schemaAvailabilityBodyParams, schemaAvailabilityPublic } from "@lib/validations/availability"; +import { schemaAvailabilityCreateBodyParams, schemaAvailabilityReadPublic } from "@lib/validations/availability"; /** * @swagger @@ -50,7 +50,7 @@ async function createOrlistAllAvailabilities( if (method === "GET") { const data = await prisma.availability.findMany({ where: { userId } }); - const availabilities = data.map((availability) => schemaAvailabilityPublic.parse(availability)); + const availabilities = data.map((availability) => schemaAvailabilityReadPublic.parse(availability)); if (availabilities) res.status(200).json({ availabilities }); else (error: Error) => @@ -59,13 +59,12 @@ async function createOrlistAllAvailabilities( error, }); } else if (method === "POST") { - console.log(req.body); - const safe = schemaAvailabilityBodyParams.safeParse(req.body); + const safe = schemaAvailabilityCreateBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.availability.create({ data: { ...safe.data, userId } }); console.log(data); - const availability = schemaAvailabilityPublic.parse(data); + const availability = schemaAvailabilityReadPublic.parse(data); if (availability) res.status(201).json({ availability, message: "Availability created successfully" }); else diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index 24bf1075ed..ee9279da0a 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -8,7 +8,7 @@ import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -import { schemaUserEditBodyParams, schemaUserReadPublic, withValidUser } from "@lib/validations/user"; +import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations/user"; /** * @swagger From 14e2964a6dc17e715d85a684560a485af928745d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 26 Apr 2022 22:48:15 +0200 Subject: [PATCH 158/658] fix: booking reference moved to pick-first create/edit separate validations --- README.md | 42 ++++++++++++----------- lib/validations/attendee.ts | 8 ++--- lib/validations/availability.ts | 2 +- lib/validations/booking-reference.ts | 48 ++++++++++++++++++++------- pages/api/availabilities/[id].ts | 5 ++- pages/api/availabilities/index.ts | 5 ++- pages/api/booking-references/[id].ts | 23 +++++++------ pages/api/booking-references/index.ts | 8 ++--- 8 files changed, 85 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 19baacdf58..17082202cd 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Cal.com Public API (Enterprise Only) -This is the public REST api for cal.com. -It exposes CRUD Endpoints of all our most important resources. +This is the public REST api for cal.com. +It exposes CRUD Endpoints of all our most important resources. And it makes it easy for anyone to integrate with Cal.com at the application programming level. ## Stack @@ -63,9 +63,10 @@ API Keys optionally may have expiry dates, if they are expired they won't work. In the future we might add support for header Bearer Auth if we need to or if our customers require it. ## Middlewares + We don't use the new NextJS 12 Beta Middlewares, mainly because they run on the edge, and are not able to call prisma from api endpoints. We use instead a very nifty library called next-api-middleware that let's us use a similar approach building our own middlewares and applying them as we see fit. -* withMiddleware() requires some default middlewares (verifyApiKey, etc...) +- withMiddleware() requires some default middlewares (verifyApiKey, etc...) ## Next.config.js @@ -121,21 +122,21 @@ We aim to provide a fully tested API for our peace of mind, this is accomplished ## Endpoints matrix -| resource | get [id] | get all | create | edit | delete | -|--------------------------|----------|----------|---------|-------|--------| -| attendees | ✅ | ✅ | ✅ | ✅ | ✅ | -| availabilities | ✅ | ✅ | ✅ | ✅ | ✅ | -| booking-references | ✅ | ✅ | ✅ | ✅ | ✅ | -| daily-event-references | ✅ | ✅ | ✅ | ✅ | ✅ | -| destination-calendars | ✅ | ✅ | ✅ | ✅ | ✅ | -| event-type-custom-inputs | ✅ | ✅ | ✅ | ✅ | ✅ | -| event-types | ✅ | ✅ | ✅ | ✅ | ✅ | -| memberships | ✅ | ✅ | ✅ | ✅ | ✅ | -| payments | ✅ | ✅ | ❌ | ❌ | ❌ | -| schedules | ✅ | ✅ | ✅ | ✅ | ✅ | -| selected-calendars | ✅ | ✅ | ✅ | ✅ | ✅ | -| teams | ✅ | ✅ | ✅ | ✅ | ✅ | -| users | ✅ | 👤[1] | ✅ | ✅ | ✅ | +| resource | get [id] | get all | create | edit | delete | +| ------------------------ | -------- | ------- | ------ | ---- | ------ | +| attendees | ✅ | ✅ | ✅ | ✅ | ✅ | +| availabilities | ✅ | ✅ | ✅ | ✅ | ✅ | +| booking-references | ✅ | ✅ | ✅ | ✅ | ✅ | +| daily-event-references | ✅ | ✅ | ✅ | ✅ | ✅ | +| destination-calendars | ✅ | ✅ | ✅ | ✅ | ✅ | +| event-type-custom-inputs | ✅ | ✅ | ✅ | ✅ | ✅ | +| event-types | ✅ | ✅ | ✅ | ✅ | ✅ | +| memberships | ✅ | ✅ | ✅ | ✅ | ✅ | +| payments | ✅ | ✅ | ❌ | ❌ | ❌ | +| schedules | ✅ | ✅ | ✅ | ✅ | ✅ | +| selected-calendars | ✅ | ✅ | ✅ | ✅ | ✅ | +| teams | ✅ | ✅ | ✅ | ✅ | ✅ | +| users | ✅ | 👤[1] | ✅ | ✅ | ✅ | ## Models from database that are not exposed @@ -170,5 +171,6 @@ DATABASE_URL=DATABASE_URL="postgresql://postgres:@localhost:5450/calendso" ## Optional -API_KEY_PREFIX=cal_# This can be changed per envirorment so cal_test_ for staging for example. -> If you're self-hosting under our commercial license, you can use any prefix you want for api keys. either leave the default cal_ (not providing any envirorment variable) or modify it +API*KEY_PREFIX=cal*# This can be changed per envirorment so cal*test* for staging for example. + +> If you're self-hosting under our commercial license, you can use any prefix you want for api keys. either leave the default cal\_ (not providing any envirorment variable) or modify it diff --git a/lib/validations/attendee.ts b/lib/validations/attendee.ts index e0b91fb309..eb956f5206 100644 --- a/lib/validations/attendee.ts +++ b/lib/validations/attendee.ts @@ -22,12 +22,8 @@ const schemaAttendeeEditParams = z.object({ name: z.string(), timeZone: z.string(), }); -export const schemaAttendeeEditBodyParams = schemaAttendeeBaseBodyParams.merge( - schemaAttendeeEditParams -); -export const schemaAttendeeCreateBodyParams = schemaAttendeeBaseBodyParams.merge( - schemaAttendeeCreateParams -); +export const schemaAttendeeEditBodyParams = schemaAttendeeBaseBodyParams.merge(schemaAttendeeEditParams); +export const schemaAttendeeCreateBodyParams = schemaAttendeeBaseBodyParams.merge(schemaAttendeeCreateParams); export const schemaAttendeeReadPublic = Attendee.pick({ bookingId: true, diff --git a/lib/validations/availability.ts b/lib/validations/availability.ts index be4691cf0e..85392c7b1a 100644 --- a/lib/validations/availability.ts +++ b/lib/validations/availability.ts @@ -11,7 +11,7 @@ export const schemaAvailabilityBaseBodyParams = Availability.pick({ days: true, }).partial(); -export const schemaAvailabilityPublic = Availability.pick({ +export const schemaAvailabilityReadPublic = Availability.pick({ startTime: true, endTime: true, date: true, diff --git a/lib/validations/booking-reference.ts b/lib/validations/booking-reference.ts index 75a7d95f0c..75aedfe6d4 100644 --- a/lib/validations/booking-reference.ts +++ b/lib/validations/booking-reference.ts @@ -3,21 +3,45 @@ import { z } from "zod"; import { _BookingReferenceModel as BookingReference } from "@calcom/prisma/zod"; -export const schemaBookingReferenceBaseBodyParams = BookingReference.omit({ id: true }).partial(); +export const schemaBookingReferenceBaseBodyParams = BookingReference.pick({ + type: true, + bookingId: true, + uid: true, + meetingId: true, + meetingPassword: true, + meetingUrl: true, + deleted: true, +}).partial(); -export const schemaBookingReferencePublic = BookingReference.omit({}); +export const schemaBookingReferenceReadPublic = BookingReference.pick({ + type: true, + bookingId: true, + uid: true, + meetingId: true, + meetingPassword: true, + meetingUrl: true, + deleted: true, +}); -const schemaBookingReferenceRequiredParams = z.object({ +const schemaBookingReferenceEditParams = z.object({ type: z.string(), uid: z.string(), + meetingId: z.string(), + meetingPassword: z.string(), + meetingUrl: z.string(), + deleted: z.boolean(), }); - -export const schemaBookingReferenceBodyParams = schemaBookingReferenceBaseBodyParams.merge( - schemaBookingReferenceRequiredParams +const schemaBookingReferenceCreateParams = z.object({ + type: z.string(), + uid: z.string(), + meetingId: z.string(), + meetingPassword: z.string(), + meetingUrl: z.string(), + deleted: z.boolean(), +}); +export const schemaBookingCreateBodyParams = schemaBookingReferenceBaseBodyParams.merge( + schemaBookingReferenceCreateParams +); +export const schemaBookingEditBodyParams = schemaBookingReferenceBaseBodyParams.merge( + schemaBookingReferenceEditParams ); - -export const withValidBookingReference = withValidation({ - schema: schemaBookingReferenceBodyParams, - type: "Zod", - mode: "body", -}); diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index c77574692a..0bef2ab1a9 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -4,7 +4,10 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { AvailabilityResponse } from "@lib/types"; -import { schemaAvailabilityEditBodyParams, schemaAvailabilityReadPublic } from "@lib/validations/availability"; +import { + schemaAvailabilityEditBodyParams, + schemaAvailabilityReadPublic, +} from "@lib/validations/availability"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index 999639dc37..869530566e 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -4,7 +4,10 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { AvailabilityResponse, AvailabilitiesResponse } from "@lib/types"; -import { schemaAvailabilityCreateBodyParams, schemaAvailabilityReadPublic } from "@lib/validations/availability"; +import { + schemaAvailabilityCreateBodyParams, + schemaAvailabilityReadPublic, +} from "@lib/validations/availability"; /** * @swagger diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index 5f08ab4c0d..1789c940b8 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -6,8 +6,8 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { BookingReferenceResponse } from "@lib/types"; import { - schemaBookingReferenceBodyParams, - schemaBookingReferencePublic, + schemaBookingEditBodyParams, + schemaBookingReferenceReadPublic, } from "@lib/validations/booking-reference"; import { schemaQueryIdParseInt, @@ -18,14 +18,14 @@ import { * @swagger * /booking-references/{id}: * get: - * summary: Get a daily event reference by ID + * summary: Get a booking reference by ID * parameters: * - in: path * name: id * schema: * type: integer * required: true - * description: Numeric ID of the daily event reference to get + * description: Numeric ID of the booking reference to get * security: * - ApiKeyAuth: [] * tags: @@ -38,7 +38,7 @@ import { * 404: * description: BookingReference was not found * patch: - * summary: Edit an existing daily event reference + * summary: Edit an existing booking reference * consumes: * - application/json * parameters: @@ -54,7 +54,7 @@ import { * schema: * type: integer * required: true - * description: Numeric ID of the daily event reference to edit + * description: Numeric ID of the booking reference to edit * security: * - ApiKeyAuth: [] * tags: @@ -68,14 +68,14 @@ import { * 401: * description: Authorization information is missing or invalid. * delete: - * summary: Remove an existing daily event reference + * summary: Remove an existing booking reference * parameters: * - in: path * name: id * schema: * type: integer * required: true - * description: Numeric ID of the daily event reference to delete + * description: Numeric ID of the booking reference to delete * security: * - ApiKeyAuth: [] * tags: @@ -95,7 +95,6 @@ export async function bookingReferenceById( ) { const { method, query, body } = req; const safeQuery = schemaQueryIdParseInt.safeParse(query); - const safeBody = schemaBookingReferenceBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); const userId = req.userId; const userWithBookings = await prisma.user.findUnique({ @@ -111,7 +110,7 @@ export async function bookingReferenceById( case "GET": await prisma.bookingReference .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaBookingReferencePublic.parse(data)) + .then((data) => schemaBookingReferenceReadPublic.parse(data)) .then((booking_reference) => res.status(200).json({ booking_reference })) .catch((error: Error) => res.status(404).json({ @@ -122,12 +121,14 @@ export async function bookingReferenceById( break; case "PATCH": + const safeBody = schemaBookingEditBodyParams.safeParse(body); + if (!safeBody.success) { throw new Error("Invalid request body"); } await prisma.bookingReference .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) - .then((data) => schemaBookingReferencePublic.parse(data)) + .then((data) => schemaBookingReferenceReadPublic.parse(data)) .then((booking_reference) => res.status(200).json({ booking_reference })) .catch((error: Error) => res.status(404).json({ diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index f77b0c586d..b715317c20 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -5,8 +5,8 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { BookingReferenceResponse, BookingReferencesResponse } from "@lib/types"; import { - schemaBookingReferenceBodyParams, - schemaBookingReferencePublic, + schemaBookingCreateBodyParams, + schemaBookingReferenceReadPublic, } from "@lib/validations/booking-reference"; /** @@ -55,7 +55,7 @@ async function createOrlistAllBookingReferences( if (method === "GET") { const data = await prisma.bookingReference.findMany({ where: { id: { in: userBookingIds } } }); const booking_references = data.map((bookingReference) => - schemaBookingReferencePublic.parse(bookingReference) + schemaBookingReferenceReadPublic.parse(bookingReference) ); if (booking_references) res.status(200).json({ booking_references }); else @@ -65,7 +65,7 @@ async function createOrlistAllBookingReferences( error, }); } else if (method === "POST") { - const safe = schemaBookingReferenceBodyParams.safeParse(req.body); + const safe = schemaBookingCreateBodyParams.safeParse(req.body); if (!safe.success) { throw new Error("Invalid request body"); } From e52af0bbef6a3c106d8155b55c55e68d0922a092 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 27 Apr 2022 19:25:36 +0200 Subject: [PATCH 159/658] fix: post / patch attendees docs w examples --- lib/validations/attendee.ts | 31 ++++++++----- lib/validations/availability.ts | 2 +- lib/validations/booking-reference.ts | 2 +- lib/validations/booking.ts | 40 ++++++++++++----- lib/validations/credential.ts | 25 ----------- lib/validations/daily-event-reference.ts | 37 +++++++++++----- lib/validations/destination-calendar.ts | 42 +++++++++++++----- lib/validations/event-type-custom-input.ts | 9 ---- lib/validations/event-type.ts | 7 --- lib/validations/membership.ts | 7 --- lib/validations/payment.ts | 8 ---- lib/validations/reminder-mail.ts | 7 --- lib/validations/schedule.ts | 7 --- lib/validations/selected-calendar.ts | 7 --- lib/validations/shared/timeZone.ts | 5 +++ lib/validations/team.ts | 7 --- lib/validations/user.ts | 10 ++--- lib/validations/webhook.ts | 8 ---- pages/api/attendees/[id].ts | 33 ++++++++++---- pages/api/attendees/index.ts | 49 ++++++++++++++++----- pages/api/availabilities/[id].ts | 2 +- pages/api/availabilities/index.ts | 2 +- pages/api/booking-references/[id].ts | 2 +- pages/api/booking-references/index.ts | 2 +- pages/api/bookings/[id].ts | 11 ++--- pages/api/bookings/index.ts | 10 ++--- pages/api/daily-event-references/[id].ts | 12 ++--- pages/api/daily-event-references/index.ts | 12 ++--- pages/api/destination-calendars/[id].ts | 12 ++--- pages/api/destination-calendars/index.ts | 12 ++--- pages/api/docs.ts | 1 + pages/api/event-type-custom-inputs/[id].ts | 2 +- pages/api/event-type-custom-inputs/index.ts | 2 +- pages/api/event-types/[id].ts | 2 +- pages/api/event-types/index.ts | 2 +- pages/api/index.ts | 5 +++ pages/api/memberships/[id].ts | 2 +- pages/api/memberships/index.ts | 2 +- pages/api/payments/[id].ts | 2 +- pages/api/payments/index.ts | 2 +- pages/api/schedules/[id].ts | 2 +- pages/api/schedules/index.ts | 4 +- pages/api/selected-calendars/[id].ts | 2 +- pages/api/selected-calendars/index.ts | 2 +- pages/api/teams/[id].ts | 2 +- pages/api/teams/index.ts | 4 +- pages/api/users/[id].ts | 2 +- pages/api/users/index.ts | 2 +- templates/endpoints/[id]/delete.ts | 2 +- templates/endpoints/[id]/edit.ts | 2 +- templates/endpoints/[id]/index.ts | 2 +- templates/endpoints/get_all.ts | 2 +- templates/endpoints/get_all_and_post.ts | 2 +- templates/endpoints/post.ts | 2 +- templates/zod-validation.ts | 7 --- 55 files changed, 247 insertions(+), 234 deletions(-) delete mode 100644 lib/validations/credential.ts create mode 100644 lib/validations/shared/timeZone.ts diff --git a/lib/validations/attendee.ts b/lib/validations/attendee.ts index eb956f5206..d603eaaf63 100644 --- a/lib/validations/attendee.ts +++ b/lib/validations/attendee.ts @@ -1,8 +1,9 @@ -import { withValidation } from "next-validations"; import { z } from "zod"; import { _AttendeeModel as Attendee } from "@calcom/prisma/zod"; +import { timeZone } from "@lib/validations/shared/timeZone"; + export const schemaAttendeeBaseBodyParams = Attendee.pick({ bookingId: true, email: true, @@ -10,22 +11,28 @@ export const schemaAttendeeBaseBodyParams = Attendee.pick({ timeZone: true, }).partial(); -const schemaAttendeeCreateParams = z.object({ - bookingId: z.any(), - email: z.string().email(), - name: z.string(), - timeZone: z.string(), -}); +const schemaAttendeeCreateParams = z + .object({ + bookingId: z.number().int(), + email: z.string().email(), + name: z.string(), + timeZone: timeZone, + }) + .strict(); -const schemaAttendeeEditParams = z.object({ - // @note: disallowing email/bookingId changes in attendee via API for now as it would introduce side effects - name: z.string(), - timeZone: z.string(), -}); +const schemaAttendeeEditParams = z + .object({ + // @note: disallowing bookingId changes in attendee via API for now as it would introduce side effects + name: z.string().optional(), + email: z.string().email().optional(), + timeZone: timeZone.optional(), + }) + .strict(); export const schemaAttendeeEditBodyParams = schemaAttendeeBaseBodyParams.merge(schemaAttendeeEditParams); export const schemaAttendeeCreateBodyParams = schemaAttendeeBaseBodyParams.merge(schemaAttendeeCreateParams); export const schemaAttendeeReadPublic = Attendee.pick({ + id: true, bookingId: true, name: true, email: true, diff --git a/lib/validations/availability.ts b/lib/validations/availability.ts index 85392c7b1a..6039dfb80f 100644 --- a/lib/validations/availability.ts +++ b/lib/validations/availability.ts @@ -1,4 +1,3 @@ -import { withValidation } from "next-validations"; import { z } from "zod"; import { _AvailabilityModel as Availability } from "@calcom/prisma/zod"; @@ -12,6 +11,7 @@ export const schemaAvailabilityBaseBodyParams = Availability.pick({ }).partial(); export const schemaAvailabilityReadPublic = Availability.pick({ + id: true, startTime: true, endTime: true, date: true, diff --git a/lib/validations/booking-reference.ts b/lib/validations/booking-reference.ts index 75aedfe6d4..f207b09208 100644 --- a/lib/validations/booking-reference.ts +++ b/lib/validations/booking-reference.ts @@ -1,4 +1,3 @@ -import { withValidation } from "next-validations"; import { z } from "zod"; import { _BookingReferenceModel as BookingReference } from "@calcom/prisma/zod"; @@ -14,6 +13,7 @@ export const schemaBookingReferenceBaseBodyParams = BookingReference.pick({ }).partial(); export const schemaBookingReferenceReadPublic = BookingReference.pick({ + id: true, type: true, bookingId: true, uid: true, diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index 77eca1d156..5bf187f523 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -1,23 +1,43 @@ -import { withValidation } from "next-validations"; import { z } from "zod"; import { _BookingModel as Booking } from "@calcom/prisma/zod"; -const schemaBookingBaseBodyParams = Booking.omit({ id: true }).partial(); +const schemaBookingBaseBodyParams = Booking.pick({ + uid: true, + userId: true, + eventTypeId: true, + title: true, + startTime: true, + endTime: true, +}).partial(); -const schemaBookingRequiredParams = z.object({ +const schemaBookingCreateParams = z.object({ + uid: z.string(), + userId: z.number(), + eventTypeId: z.number(), + title: z.string(), + startTime: z.date(), + endTime: z.date(), +}); + +export const schemaBookingCreateBodyParams = schemaBookingBaseBodyParams.merge(schemaBookingCreateParams); + +// @note: disallowing userId/eventTypeId changes in booking endpoint via PATCH for now as it would introduce side effects +const schemaBookingEditParams = z.object({ uid: z.string(), title: z.string(), startTime: z.date(), endTime: z.date(), }); -export const schemaBookingBodyParams = schemaBookingBaseBodyParams.merge(schemaBookingRequiredParams); +export const schemaBookingEditBodyParams = schemaBookingBaseBodyParams.merge(schemaBookingEditParams); -export const schemaBookingPublic = Booking.omit({}); - -export const withValidBooking = withValidation({ - schema: schemaBookingBodyParams, - type: "Zod", - mode: "body", +export const schemaBookingReadPublic = Booking.pick({ + id: true, + userId: true, + eventTypeId: true, + uid: true, + title: true, + startTime: true, + endTime: true, }); diff --git a/lib/validations/credential.ts b/lib/validations/credential.ts deleted file mode 100644 index 9397ef2577..0000000000 --- a/lib/validations/credential.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { withValidation } from "next-validations"; -import { z } from "zod"; - -import { _CredentialModel as Credential } from "@calcom/prisma/zod"; - -import { jsonSchema } from "./shared/jsonSchema"; - -const schemaCredentialBaseBodyParams = Credential.omit({ id: true, userId: true }).partial(); - -const schemaCredentialRequiredParams = z.object({ - type: z.string(), - key: jsonSchema, -}); - -export const schemaCredentialBodyParams = schemaCredentialBaseBodyParams.merge( - schemaCredentialRequiredParams -); - -export const schemaCredentialPublic = Credential.omit({}); - -export const withValidCredential = withValidation({ - schema: schemaCredentialBodyParams, - type: "Zod", - mode: "body", -}); diff --git a/lib/validations/daily-event-reference.ts b/lib/validations/daily-event-reference.ts index f477f6bec6..ca74d5a95f 100644 --- a/lib/validations/daily-event-reference.ts +++ b/lib/validations/daily-event-reference.ts @@ -1,22 +1,35 @@ -import { withValidation } from "next-validations"; import { z } from "zod"; import { _DailyEventReferenceModel as DailyEventReference } from "@calcom/prisma/zod"; -export const schemaDailyEventReferenceBaseBodyParams = DailyEventReference.omit({ id: true }); +export const schemaDailyEventReferenceBaseBodyParams = DailyEventReference.pick({ + dailytoken: true, + dailyurl: true, + bookingId: true, +}).partial(); -const schemaDailyEventReferenceRequiredParams = z.object({ - email: z.string().email(), +const schemaDailyEventReferenceCreateParams = z.object({ + dailytoken: z.string(), + dailyurl: z.string(), + bookingId: z.number(), }); -export const schemaDailyEventReferenceBodyParams = schemaDailyEventReferenceBaseBodyParams.merge( - schemaDailyEventReferenceRequiredParams +export const schemaDailyEventReferenceCreateBodyParams = schemaDailyEventReferenceBaseBodyParams.merge( + schemaDailyEventReferenceCreateParams ); -export const schemaDailyEventReferencePublic = DailyEventReference.omit({}); - -export const withValidDailyEventReference = withValidation({ - schema: schemaDailyEventReferenceBodyParams, - type: "Zod", - mode: "body", +const schemaDailyEventReferenceEditParams = z.object({ + dailytoken: z.string(), + dailyurl: z.string(), + // @note: disallowing bookingId changes in daily-event-reference via API endpoint for now as it would introduce side effects +}); + +export const schemaDailyEventReferenceEditBodyParams = schemaDailyEventReferenceBaseBodyParams.merge( + schemaDailyEventReferenceEditParams +); +export const schemaDailyEventReferenceReadPublic = DailyEventReference.pick({ + id: true, + dailytoken: true, + dailyurl: true, + bookingId: true, }); diff --git a/lib/validations/destination-calendar.ts b/lib/validations/destination-calendar.ts index 87e367ee19..541260d4dc 100644 --- a/lib/validations/destination-calendar.ts +++ b/lib/validations/destination-calendar.ts @@ -1,23 +1,43 @@ -import { withValidation } from "next-validations"; import { z } from "zod"; import { _DestinationCalendarModel as DestinationCalendar } from "@calcom/prisma/zod"; -export const schemaDestinationCalendarBaseBodyParams = DestinationCalendar.omit({ id: true }).partial(); +export const schemaDestinationCalendarBaseBodyParams = DestinationCalendar.pick({ + integration: true, + externalId: true, + eventTypeId: true, + bookingId: true, + userId: true, +}).partial(); -const schemaDestinationCalendarRequiredParams = z.object({ +const schemaDestinationCalendarEditParams = z.object({ integration: z.string(), externalId: z.string(), + eventTypeId: z.number(), + bookingId: z.number(), + userId: z.number(), }); -export const schemaDestinationCalendarBodyParams = schemaDestinationCalendarBaseBodyParams.merge( - schemaDestinationCalendarRequiredParams +export const schemaDestinationCalendarEditBodyParams = schemaDestinationCalendarBaseBodyParams.merge( + schemaDestinationCalendarEditParams +); +const schemaDestinationCalendarCreateParams = z.object({ + integration: z.string(), + externalId: z.string(), + eventTypeId: z.number(), + bookingId: z.number(), + userId: z.number(), +}); + +export const schemaDestinationCalendarCreateBodyParams = schemaDestinationCalendarBaseBodyParams.merge( + schemaDestinationCalendarCreateParams ); -export const schemaDestinationCalendarPublic = DestinationCalendar.omit({}); - -export const withValidDestinationCalendar = withValidation({ - schema: schemaDestinationCalendarBodyParams, - type: "Zod", - mode: "body", +export const schemaDestinationCalendarReadPublic = DestinationCalendar.pick({ + id: true, + integration: true, + externalId: true, + eventTypeId: true, + bookingId: true, + userId: true, }); diff --git a/lib/validations/event-type-custom-input.ts b/lib/validations/event-type-custom-input.ts index 73555285e4..560d3d7684 100644 --- a/lib/validations/event-type-custom-input.ts +++ b/lib/validations/event-type-custom-input.ts @@ -1,4 +1,3 @@ -import { withValidation } from "next-validations"; import { z } from "zod"; import { _EventTypeCustomInputModel as EventTypeCustomInput } from "@calcom/prisma/zod"; @@ -17,8 +16,6 @@ const schemaEventTypeCustomInputRequiredParams = z.object({ eventType: z.object({ connect: z.object({ id: z.number().optional(), - // username: z.string().optional(), - // email: z.string().optional(), }), // FIXME: Provide valid EventTypeModel schema here, but not sure how yet. create: z.any(), @@ -28,9 +25,3 @@ const schemaEventTypeCustomInputRequiredParams = z.object({ export const schemaEventTypeCustomInputBodyParams = schemaEventTypeCustomInputBaseBodyParams.merge( schemaEventTypeCustomInputRequiredParams ); - -export const withValidEventTypeCustomInput = withValidation({ - schema: schemaEventTypeCustomInputBodyParams, - type: "Zod", - mode: "body", -}); diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 119edcb248..e8665a9e3b 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -1,4 +1,3 @@ -import { withValidation } from "next-validations"; import { z } from "zod"; import { _EventTypeModel as EventType } from "@calcom/prisma/zod"; @@ -14,9 +13,3 @@ const schemaEventTypeRequiredParams = z.object({ export const schemaEventTypeBodyParams = schemaEventTypeBaseBodyParams.merge(schemaEventTypeRequiredParams); // @NOTE: Removing locations and metadata properties before validation, add them later if required export const schemaEventTypePublic = EventType.omit({ locations: true, metadata: true }); - -export const withValidEventType = withValidation({ - schema: schemaEventTypeBodyParams, - type: "Zod", - mode: "body", -}); diff --git a/lib/validations/membership.ts b/lib/validations/membership.ts index bb5d7cb7fc..d58eea2c33 100644 --- a/lib/validations/membership.ts +++ b/lib/validations/membership.ts @@ -1,4 +1,3 @@ -import { withValidation } from "next-validations"; import { z } from "zod"; import { _MembershipModel as Membership } from "@calcom/prisma/zod"; @@ -13,9 +12,3 @@ export const schemaMembershipBodyParams = schemaMembershipBaseBodyParams.merge( ); export const schemaMembershipPublic = Membership.omit({}); - -export const withValidMembership = withValidation({ - schema: schemaMembershipBodyParams, - type: "Zod", - mode: "body", -}); diff --git a/lib/validations/payment.ts b/lib/validations/payment.ts index 5789d4a092..32c5d8d641 100644 --- a/lib/validations/payment.ts +++ b/lib/validations/payment.ts @@ -1,13 +1,5 @@ -import { withValidation } from "next-validations"; - import { _PaymentModel as Payment } from "@calcom/prisma/zod"; // FIXME: Payment seems a delicate endpoint, do we need to remove anything here? export const schemaPaymentBodyParams = Payment.omit({ id: true }); export const schemaPaymentPublic = Payment.omit({ externalId: true }); - -export const withValidPayment = withValidation({ - schema: schemaPaymentBodyParams, - type: "Zod", - mode: "body", -}); diff --git a/lib/validations/reminder-mail.ts b/lib/validations/reminder-mail.ts index d97c65c2b1..635dc84dac 100644 --- a/lib/validations/reminder-mail.ts +++ b/lib/validations/reminder-mail.ts @@ -1,4 +1,3 @@ -import { withValidation } from "next-validations"; import { z } from "zod"; import { _ReminderMailModel as ReminderMail } from "@calcom/prisma/zod"; @@ -16,9 +15,3 @@ const schemaReminderMailRequiredParams = z.object({ export const schemaReminderMailBodyParams = schemaReminderMailBaseBodyParams.merge( schemaReminderMailRequiredParams ); - -export const withValidReminderMail = withValidation({ - schema: schemaReminderMailBodyParams, - type: "Zod", - mode: "body", -}); diff --git a/lib/validations/schedule.ts b/lib/validations/schedule.ts index e5782a08d7..176d972da1 100644 --- a/lib/validations/schedule.ts +++ b/lib/validations/schedule.ts @@ -1,4 +1,3 @@ -import { withValidation } from "next-validations"; import { z } from "zod"; import { _ScheduleModel as Schedule } from "@calcom/prisma/zod"; @@ -13,9 +12,3 @@ const schemaScheduleRequiredParams = z.object({ export const schemaScheduleBodyParams = schemaScheduleBaseBodyParams.merge(schemaScheduleRequiredParams); export const schemaSchedulePublic = Schedule.omit({}); - -export const withValidSchedule = withValidation({ - schema: schemaScheduleBodyParams, - type: "Zod", - mode: "body", -}); diff --git a/lib/validations/selected-calendar.ts b/lib/validations/selected-calendar.ts index 4eab89d937..ffdc54b96a 100644 --- a/lib/validations/selected-calendar.ts +++ b/lib/validations/selected-calendar.ts @@ -1,4 +1,3 @@ -import { withValidation } from "next-validations"; import { z } from "zod"; import { _SelectedCalendarModel as SelectedCalendar } from "@calcom/prisma/zod"; @@ -24,9 +23,3 @@ const schemaSelectedCalendarRequiredParams = z.object({ export const schemaSelectedCalendarBodyParams = schemaSelectedCalendarBaseBodyParams.merge( schemaSelectedCalendarRequiredParams ); - -export const withValidSelectedCalendar = withValidation({ - schema: schemaSelectedCalendarBodyParams, - type: "Zod", - mode: "body", -}); diff --git a/lib/validations/shared/timeZone.ts b/lib/validations/shared/timeZone.ts new file mode 100644 index 0000000000..9dfa98003d --- /dev/null +++ b/lib/validations/shared/timeZone.ts @@ -0,0 +1,5 @@ +import * as tzdb from "tzdata"; +import * as z from "zod"; + +// @note: This is a custom validation that checks if the timezone is valid and exists in the tzdb library +export const timeZone = z.string().refine((tz: string) => Object.keys(tzdb.zones).includes(tz)); diff --git a/lib/validations/team.ts b/lib/validations/team.ts index ec6cbf35ec..d980607f87 100644 --- a/lib/validations/team.ts +++ b/lib/validations/team.ts @@ -1,4 +1,3 @@ -import { withValidation } from "next-validations"; import { z } from "zod"; import { _TeamModel as Team } from "@calcom/prisma/zod"; @@ -10,9 +9,3 @@ const schemaTeamRequiredParams = z.object({}); export const schemaTeamBodyParams = schemaTeamBaseBodyParams.merge(schemaTeamRequiredParams); export const schemaTeamPublic = Team.omit({}); - -export const withValidTeam = withValidation({ - schema: schemaTeamBodyParams, - type: "Zod", - mode: "body", -}); diff --git a/lib/validations/user.ts b/lib/validations/user.ts index c3e26e9cb0..9eb7b05094 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -1,9 +1,9 @@ -import { withValidation } from "next-validations"; -import * as tzdb from "tzdata"; import { z } from "zod"; import { _UserModel as User } from "@calcom/prisma/zod"; +import { timeZone } from "@lib/validations/shared/timeZone"; + // @note: These are the ONLY values allowed as weekStart. So user don't introduce bad data. enum weekdays { MONDAY = "Monday", @@ -77,11 +77,7 @@ export const schemaUserBaseBodyParams = User.pick({ const schemaUserEditParams = z.object({ weekStart: z.nativeEnum(weekdays).optional(), brandColor: z.string().min(4).max(9).regex(/^#/).optional(), - timeZone: z - .string() - // @note: This is a custom validation that checks if the timezone is valid and exists in the tzdb library - .refine((tz: string) => Object.keys(tzdb.zones).includes(tz)) - .optional(), + timeZone: timeZone.optional(), bufferTime: z.number().min(0).max(86400).optional(), startTime: z.number().min(0).max(86400).optional(), endTime: z.number().min(0).max(86400).optional(), diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 746443213d..40b0731507 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -1,13 +1,5 @@ -import { withValidation } from "next-validations"; - import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; export const schemaWebhookBodyParams = Webhook.omit({ id: true }).partial(); export const schemaWebhookPublic = Webhook.omit({}); - -export const withValidWebhook = withValidation({ - schema: schemaWebhookBodyParams, - type: "Zod", - mode: "body", -}); diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index 4d6aecd7f1..ce41228cd0 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -14,7 +14,7 @@ import { * @swagger * /attendees/{id}: * get: - * summary: Get an attendee by ID + * summary: Find an attendee by ID * parameters: * - in: path * name: id @@ -22,6 +22,7 @@ import { * type: integer * required: true * description: Numeric ID of the attendee to get + * example: 3 * security: * - ApiKeyAuth: [] * tags: @@ -37,18 +38,34 @@ import { * summary: Edit an existing attendee * consumes: * - application/json + * requestBody: + * description: Edit an existing attendee related to one of your bookings + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - bookingId + * - name + * - email + * - timeZone + * properties: + * email: + * type: string + * example: email@example.com + * name: + * type: string + * example: John Doe + * timeZone: + * type: string + * example: Europe/London * parameters: - * - in: body - * name: attendee - * description: The attendee to edit - * schema: - * type: object - * $ref: '#/components/schemas/Attendee' - * required: true * - in: path * name: id * schema: * type: integer + * example: 3 * required: true * description: Numeric ID of the attendee to edit * security: diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index 80afde914a..3adbc8a78c 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -10,7 +10,7 @@ import { schemaAttendeeCreateBodyParams, schemaAttendeeReadPublic } from "@lib/v * @swagger * /attendees: * get: - * summary: Get all attendees + * summary: Find all attendees * security: * - ApiKeyAuth: [] * tags: @@ -26,6 +26,33 @@ import { schemaAttendeeCreateBodyParams, schemaAttendeeReadPublic } from "@lib/v * summary: Creates a new attendee * security: * - ApiKeyAuth: [] + * consumes: + * - application/json + * requestBody: + * description: Create a new attendee related to one of your bookings + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - bookingId + * - name + * - email + * - timeZone + * properties: + * bookingId: + * type: number + * example: 1 + * email: + * type: string + * example: email@example.com + * name: + * type: string + * example: John Doe + * timeZone: + * type: string + * example: Europe/London * tags: * - attendees * responses: @@ -61,11 +88,12 @@ async function createOrlistAllAttendees( error, }); } else if (method === "POST") { - const safe = schemaAttendeeCreateBodyParams.safeParse(req.body); - if (!safe.success) { - throw new Error("Invalid request body", safe.error); + const safePost = schemaAttendeeCreateBodyParams.safeParse(req.body); + if (!safePost.success) { + console.log(safePost.error); + res.status(400).json({ error: safePost.error }); + throw new Error("Invalid request body", safePost.error); } - const bookingId = safe.data.bookingId; const userId = req.userId; const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, @@ -76,15 +104,14 @@ async function createOrlistAllAttendees( } const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); // Here we make sure to only return attendee's of the user's own bookings. - if (!userBookingIds.includes(parseInt(safe.data.bookingId))) - res.status(401).json({ message: "Unauthorized" }); + if (!userBookingIds.includes(safePost.data.bookingId)) res.status(401).json({ message: "Unauthorized" }); else { - delete safe.data.bookingId; - const noBookingId = safe.data; const data = await prisma.attendee.create({ data: { - ...noBookingId, - booking: { connect: { id: parseInt(bookingId) } }, + email: safePost.data.email, + name: safePost.data.name, + timeZone: safePost.data.timeZone, + booking: { connect: { id: safePost.data.bookingId } }, }, }); const attendee = schemaAttendeeReadPublic.parse(data); diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index 0bef2ab1a9..65f750dba7 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -17,7 +17,7 @@ import { * @swagger * /availabilities/{id}: * get: - * summary: Get an availability by ID + * summary: Find an availability by ID * parameters: * - in: path * name: id diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index 869530566e..3e519bc6ad 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -13,7 +13,7 @@ import { * @swagger * /availabilities: * get: - * summary: Get all availabilities + * summary: Find all availabilities * security: * - ApiKeyAuth: [] * tags: diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index 1789c940b8..21b314f728 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -18,7 +18,7 @@ import { * @swagger * /booking-references/{id}: * get: - * summary: Get a booking reference by ID + * summary: Find a booking reference by ID * parameters: * - in: path * name: id diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index b715317c20..bc82f23701 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -13,7 +13,7 @@ import { * @swagger * /booking-references: * get: - * summary: Get all booking references + * summary: Find all booking references * security: * - ApiKeyAuth: [] * tags: diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index c0b74d09f8..21be432cd1 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -4,7 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { BookingResponse } from "@lib/types"; -import { schemaBookingBodyParams, schemaBookingPublic } from "@lib/validations/booking"; +import { schemaBookingEditBodyParams, schemaBookingReadPublic } from "@lib/validations/booking"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, @@ -14,7 +14,7 @@ import { * @swagger * /bookings/{id}: * get: - * summary: Get a booking by ID + * summary: Find a booking by ID * parameters: * - in: path * name: id @@ -88,7 +88,6 @@ import { export async function bookingById(req: NextApiRequest, res: NextApiResponse) { const { method, query, body } = req; const safeQuery = schemaQueryIdParseInt.safeParse(query); - const safeBody = schemaBookingBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); const userId = req.userId; const userWithBookings = await prisma.user.findUnique({ @@ -103,7 +102,7 @@ export async function bookingById(req: NextApiRequest, res: NextApiResponse schemaBookingPublic.parse(data)) + .then((data) => schemaBookingReadPublic.parse(data)) .then((booking) => res.status(200).json({ booking })) .catch((error: Error) => res.status(404).json({ @@ -114,6 +113,8 @@ export async function bookingById(req: NextApiRequest, res: NextApiResponse schemaBookingPublic.parse(data)) + .then((data) => schemaBookingReadPublic.parse(data)) .then((booking) => res.status(200).json({ booking })) .catch((error: Error) => res.status(404).json({ diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index cb0f2089ed..8bb9cae30d 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -4,13 +4,13 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { BookingResponse, BookingsResponse } from "@lib/types"; -import { schemaBookingBodyParams, schemaBookingPublic, withValidBooking } from "@lib/validations/booking"; +import { schemaBookingCreateBodyParams, schemaBookingReadPublic } from "@lib/validations/booking"; /** * @swagger * /bookings: * get: - * summary: Get all bookings + * summary: Find all bookings * security: * - ApiKeyAuth: [] * tags: @@ -46,7 +46,7 @@ async function createOrlistAllBookings( if (method === "GET") { const data = await prisma.booking.findMany({ where: { userId } }); - const bookings = data.map((booking) => schemaBookingPublic.parse(booking)); + const bookings = data.map((booking) => schemaBookingReadPublic.parse(booking)); if (bookings) res.status(200).json({ bookings }); else (error: Error) => @@ -55,11 +55,11 @@ async function createOrlistAllBookings( error, }); } else if (method === "POST") { - const safe = schemaBookingBodyParams.safeParse(req.body); + const safe = schemaBookingCreateBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.booking.create({ data: { ...safe.data, userId } }); - const booking = schemaBookingPublic.parse(data); + const booking = schemaBookingReadPublic.parse(data); if (booking) res.status(201).json({ booking, message: "Booking created successfully" }); else diff --git a/pages/api/daily-event-references/[id].ts b/pages/api/daily-event-references/[id].ts index 280ad0c623..6ef4ac01e2 100644 --- a/pages/api/daily-event-references/[id].ts +++ b/pages/api/daily-event-references/[id].ts @@ -5,8 +5,8 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { DailyEventReferenceResponse } from "@lib/types"; import { - schemaDailyEventReferenceBodyParams, - schemaDailyEventReferencePublic, + schemaDailyEventReferenceEditBodyParams, + schemaDailyEventReferenceReadPublic, } from "@lib/validations/daily-event-reference"; import { schemaQueryIdParseInt, @@ -17,7 +17,7 @@ import { * @swagger * /daily-event-references/{id}: * get: - * summary: Get a daily event reference by ID + * summary: Find a daily event reference by ID * parameters: * - in: path * name: id @@ -94,7 +94,7 @@ export async function dailyEventReferenceById( ) { const { method, query, body } = req; const safeQuery = schemaQueryIdParseInt.safeParse(query); - const safeBody = schemaDailyEventReferenceBodyParams.safeParse(body); + const safeBody = schemaDailyEventReferenceEditBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); const userId = req.userId; const userBookings = await prisma.booking.findMany({ where: { userId } }); @@ -112,7 +112,7 @@ export async function dailyEventReferenceById( case "GET": await prisma.dailyEventReference .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaDailyEventReferencePublic.parse(data)) + .then((data) => schemaDailyEventReferenceReadPublic.parse(data)) .then((daily_event_reference) => res.status(200).json({ daily_event_reference })) .catch((error: Error) => res.status(404).json({ @@ -128,7 +128,7 @@ export async function dailyEventReferenceById( } await prisma.dailyEventReference .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) - .then((data) => schemaDailyEventReferencePublic.parse(data)) + .then((data) => schemaDailyEventReferenceReadPublic.parse(data)) .then((daily_event_reference) => res.status(200).json({ daily_event_reference })) .catch((error: Error) => res.status(404).json({ diff --git a/pages/api/daily-event-references/index.ts b/pages/api/daily-event-references/index.ts index 670b18421c..dfafe246ce 100644 --- a/pages/api/daily-event-references/index.ts +++ b/pages/api/daily-event-references/index.ts @@ -5,15 +5,15 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { DailyEventReferenceResponse, DailyEventReferencesResponse } from "@lib/types"; import { - schemaDailyEventReferenceBodyParams, - schemaDailyEventReferencePublic, + schemaDailyEventReferenceCreateBodyParams, + schemaDailyEventReferenceReadPublic, } from "@lib/validations/daily-event-reference"; /** * @swagger * /daily-event-references: * get: - * summary: Get all daily event reference + * summary: Find all daily event reference * security: * - ApiKeyAuth: [] * tags: @@ -54,7 +54,7 @@ async function createOrlistAllDailyEventReferences( where: { bookingId: { in: userBookingIds } }, }); const daily_event_references = data.map((dailyEventReference) => - schemaDailyEventReferencePublic.parse(dailyEventReference) + schemaDailyEventReferenceReadPublic.parse(dailyEventReference) ); if (daily_event_references) res.status(200).json({ daily_event_references }); else @@ -64,11 +64,11 @@ async function createOrlistAllDailyEventReferences( error, }); } else if (method === "POST") { - const safe = schemaDailyEventReferenceBodyParams.safeParse(req.body); + const safe = schemaDailyEventReferenceCreateBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.dailyEventReference.create({ data: safe.data }); - const daily_event_reference = schemaDailyEventReferencePublic.parse(data); + const daily_event_reference = schemaDailyEventReferenceReadPublic.parse(data); if (daily_event_reference) res.status(201).json({ daily_event_reference, message: "DailyEventReference created successfully" }); diff --git a/pages/api/destination-calendars/[id].ts b/pages/api/destination-calendars/[id].ts index f5ba4d90ee..60982a7058 100644 --- a/pages/api/destination-calendars/[id].ts +++ b/pages/api/destination-calendars/[id].ts @@ -5,8 +5,8 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { DestinationCalendarResponse } from "@lib/types"; import { - schemaDestinationCalendarBodyParams, - schemaDestinationCalendarPublic, + schemaDestinationCalendarEditBodyParams, + schemaDestinationCalendarReadPublic, } from "@lib/validations/destination-calendar"; import { schemaQueryIdParseInt, @@ -17,7 +17,7 @@ import { * @swagger * /destination-calendars/{id}: * get: - * summary: Get a destination calendar by ID + * summary: Find a destination calendar by ID * parameters: * - in: path * name: id @@ -94,7 +94,7 @@ export async function destionationCalendarById( ) { const { method, query, body } = req; const safeQuery = schemaQueryIdParseInt.safeParse(query); - const safeBody = schemaDestinationCalendarBodyParams.safeParse(body); + const safeBody = schemaDestinationCalendarEditBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); const userId = req.userId; const data = await prisma.destinationCalendar.findMany({ where: { userId } }); @@ -107,7 +107,7 @@ export async function destionationCalendarById( case "GET": await prisma.destinationCalendar .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaDestinationCalendarPublic.parse(data)) + .then((data) => schemaDestinationCalendarReadPublic.parse(data)) .then((destination_calendar) => res.status(200).json({ destination_calendar })) .catch((error: Error) => res.status(404).json({ @@ -123,7 +123,7 @@ export async function destionationCalendarById( } await prisma.destinationCalendar .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) - .then((data) => schemaDestinationCalendarPublic.parse(data)) + .then((data) => schemaDestinationCalendarReadPublic.parse(data)) .then((destination_calendar) => res.status(200).json({ destination_calendar })) .catch((error: Error) => res.status(404).json({ diff --git a/pages/api/destination-calendars/index.ts b/pages/api/destination-calendars/index.ts index 782612518c..d7921491c9 100644 --- a/pages/api/destination-calendars/index.ts +++ b/pages/api/destination-calendars/index.ts @@ -5,15 +5,15 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { DestinationCalendarResponse, DestinationCalendarsResponse } from "@lib/types"; import { - schemaDestinationCalendarBodyParams, - schemaDestinationCalendarPublic, + schemaDestinationCalendarCreateBodyParams, + schemaDestinationCalendarReadPublic, } from "@lib/validations/destination-calendar"; /** * @swagger * /destination-calendars: * get: - * summary: Get all destination calendars + * summary: Find all destination calendars * security: * - ApiKeyAuth: [] * tags: @@ -50,7 +50,7 @@ async function createOrlistAllDestinationCalendars( if (method === "GET") { const data = await prisma.destinationCalendar.findMany({ where: { userId } }); const destination_calendars = data.map((destinationCalendar) => - schemaDestinationCalendarPublic.parse(destinationCalendar) + schemaDestinationCalendarReadPublic.parse(destinationCalendar) ); if (data) res.status(200).json({ destination_calendars }); else @@ -60,11 +60,11 @@ async function createOrlistAllDestinationCalendars( error, }); } else if (method === "POST") { - const safe = schemaDestinationCalendarBodyParams.safeParse(req.body); + const safe = schemaDestinationCalendarCreateBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.destinationCalendar.create({ data: { ...safe.data, userId } }); - const destination_calendar = schemaDestinationCalendarPublic.parse(data); + const destination_calendar = schemaDestinationCalendarReadPublic.parse(data); if (destination_calendar) res.status(201).json({ destination_calendar, message: "DestinationCalendar created successfully" }); diff --git a/pages/api/docs.ts b/pages/api/docs.ts index 25d9c7ce1b..7dd7afa65d 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -20,6 +20,7 @@ const swaggerHandler = withSwagger({ }, components: { securitySchemes: { ApiKeyAuth: { type: "apiKey", in: "query", name: "apiKey" } }, + security: { ApiKeyAuth: [] }, schemas: { ...jsonSchema.definitions }, }, }, diff --git a/pages/api/event-type-custom-inputs/[id].ts b/pages/api/event-type-custom-inputs/[id].ts index 23e4c73a9a..7d3ffa7a5d 100644 --- a/pages/api/event-type-custom-inputs/[id].ts +++ b/pages/api/event-type-custom-inputs/[id].ts @@ -17,7 +17,7 @@ import { * @swagger * /event-type-custom-inputs/{id}: * get: - * summary: Get a eventTypeCustomInput by ID + * summary: Find a eventTypeCustomInput by ID * parameters: * - in: path * name: id diff --git a/pages/api/event-type-custom-inputs/index.ts b/pages/api/event-type-custom-inputs/index.ts index f1931b8b12..01f5af921f 100644 --- a/pages/api/event-type-custom-inputs/index.ts +++ b/pages/api/event-type-custom-inputs/index.ts @@ -13,7 +13,7 @@ import { * @swagger * /event-type-custom-inputs: * get: - * summary: Get all eventTypeCustomInputs + * summary: Find all eventTypeCustomInputs * security: * - ApiKeyAuth: [] * tags: diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 465e85b428..37a5b38be7 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -14,7 +14,7 @@ import { * @swagger * /event-types/{id}: * get: - * summary: Get a eventType by ID + * summary: Find a eventType by ID * parameters: * - in: path * name: id diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 9d73be9458..9e1e83c038 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -10,7 +10,7 @@ import { schemaEventTypeBodyParams, schemaEventTypePublic } from "@lib/validatio * @swagger * /event-types: * get: - * summary: Get all event types + * summary: Find all event types * security: * - ApiKeyAuth: [] * tags: diff --git a/pages/api/index.ts b/pages/api/index.ts index 94461cedce..3f72b7eaef 100644 --- a/pages/api/index.ts +++ b/pages/api/index.ts @@ -1,5 +1,10 @@ import type { NextApiRequest, NextApiResponse } from "next"; +/** + * @swagger + * security: + * - ApiKeyAuth: [] + */ export default async function CalcomApi(_: NextApiRequest, res: NextApiResponse) { res.status(201).json({ message: "Welcome to Cal.com API - docs are at https://docs.cal.com/api" }); } diff --git a/pages/api/memberships/[id].ts b/pages/api/memberships/[id].ts index c4a1d362f7..0e7498d16c 100644 --- a/pages/api/memberships/[id].ts +++ b/pages/api/memberships/[id].ts @@ -11,7 +11,7 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * @swagger * /memberships/{userId}_{teamId}: * get: - * summary: Get a membership by userID and teamID + * summary: Find a membership by userID and teamID * parameters: * - in: path * name: userId diff --git a/pages/api/memberships/index.ts b/pages/api/memberships/index.ts index 702effdfd6..3df3b56d13 100644 --- a/pages/api/memberships/index.ts +++ b/pages/api/memberships/index.ts @@ -10,7 +10,7 @@ import { schemaMembershipBodyParams, schemaMembershipPublic } from "@lib/validat * @swagger * /memberships: * get: - * summary: Get all memberships + * summary: Find all memberships * security: * - ApiKeyAuth: [] * tags: diff --git a/pages/api/payments/[id].ts b/pages/api/payments/[id].ts index 6ccf227641..8ab4d5eab9 100644 --- a/pages/api/payments/[id].ts +++ b/pages/api/payments/[id].ts @@ -14,7 +14,7 @@ import { * @swagger * /payments/{id}: * get: - * summary: Get one of your own payments by ID + * summary: Find one of your own payments by ID * parameters: * - in: path * name: id diff --git a/pages/api/payments/index.ts b/pages/api/payments/index.ts index 2b00d85ebb..db0cd349ca 100644 --- a/pages/api/payments/index.ts +++ b/pages/api/payments/index.ts @@ -10,7 +10,7 @@ import { schemaPaymentPublic } from "@lib/validations/payment"; * @swagger * /payments: * get: - * summary: Get all payments + * summary: Find all payments * security: * - ApiKeyAuth: [] * tags: diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index 154dfa41f1..8a08128f4f 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -14,7 +14,7 @@ import { * @swagger * /schedules/{id}: * get: - * summary: Get a schedule by ID + * summary: Find a schedule by ID * parameters: * - in: path * name: id diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index d04d35cccb..228599eef3 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -4,13 +4,13 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { ScheduleResponse, SchedulesResponse } from "@lib/types"; -import { schemaScheduleBodyParams, schemaSchedulePublic, withValidSchedule } from "@lib/validations/schedule"; +import { schemaScheduleBodyParams, schemaSchedulePublic } from "@lib/validations/schedule"; /** * @swagger * /schedules: * get: - * summary: Get all schedules + * summary: Find all schedules * security: * - ApiKeyAuth: [] * tags: diff --git a/pages/api/selected-calendars/[id].ts b/pages/api/selected-calendars/[id].ts index 1b3e5e9cd5..6efbca86ee 100644 --- a/pages/api/selected-calendars/[id].ts +++ b/pages/api/selected-calendars/[id].ts @@ -14,7 +14,7 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * @swagger * /selected-calendars/{userId}_{integration}_{externalId}: * get: - * summary: Get a selected-calendar by userID and teamID + * summary: Find a selected-calendar by userID and teamID * parameters: * - in: path * name: userId diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index d9b80a8541..83537208ba 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -13,7 +13,7 @@ import { * @swagger * /selected-calendars: * get: - * summary: Get all selected calendars + * summary: Find all selected calendars * security: * - ApiKeyAuth: [] * tags: diff --git a/pages/api/teams/[id].ts b/pages/api/teams/[id].ts index 2990d3642b..0fead8e066 100644 --- a/pages/api/teams/[id].ts +++ b/pages/api/teams/[id].ts @@ -14,7 +14,7 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * @swagger * /teams/{id}: * get: - * summary: Get a team by ID + * summary: Find a team by ID * parameters: * - in: path * name: id diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index d6392e0c1b..ce335fff9d 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -5,13 +5,13 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { TeamResponse, TeamsResponse } from "@lib/types"; import { schemaMembershipPublic } from "@lib/validations/membership"; -import { schemaTeamBodyParams, schemaTeamPublic, withValidTeam } from "@lib/validations/team"; +import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; /** * @swagger * /teams: * get: - * summary: Get all teams + * summary: Find all teams * security: * - ApiKeyAuth: [] * tags: diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index ee9279da0a..06e5612dd0 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -14,7 +14,7 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations * @swagger * /users/{id}: * get: - * summary: Get a user by ID, returns your user if regular user. + * summary: Find a user by ID, returns your user if regular user. * parameters: * - in: path * name: id diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index aa35dca042..fa28b36f5e 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -10,7 +10,7 @@ import { schemaUserReadPublic } from "@lib/validations/user"; * @swagger * /users: * get: - * summary: Get all users (admin only), returns your user if regular user. + * summary: Find all users (admin only), returns your user if regular user. * security: * - ApiKeyAuth: [] * tags: diff --git a/templates/endpoints/[id]/delete.ts b/templates/endpoints/[id]/delete.ts index 5cf646aee0..9c5c6f9f7c 100644 --- a/templates/endpoints/[id]/delete.ts +++ b/templates/endpoints/[id]/delete.ts @@ -22,7 +22,7 @@ import { * required: true * description: Numeric ID of the resource to delete * security: - * - ApiKeyAuth: [] + * - ApiKeyAuth: [] * tags: * - resources * responses: diff --git a/templates/endpoints/[id]/edit.ts b/templates/endpoints/[id]/edit.ts index 54b8fec540..8ddad4601d 100644 --- a/templates/endpoints/[id]/edit.ts +++ b/templates/endpoints/[id]/edit.ts @@ -23,7 +23,7 @@ import { * required: true * description: Numeric ID of the resource to edit * security: - * - ApiKeyAuth: [] + * - ApiKeyAuth: [] * tags: * - resources * responses: diff --git a/templates/endpoints/[id]/index.ts b/templates/endpoints/[id]/index.ts index 66e7ab105c..9f4c64f11d 100644 --- a/templates/endpoints/[id]/index.ts +++ b/templates/endpoints/[id]/index.ts @@ -14,7 +14,7 @@ import { * @swagger * /v1/resources/{id}: * get: - * summary: Get a resource by ID + * summary: Find a resource by ID * parameters: * - in: path * name: id diff --git a/templates/endpoints/get_all.ts b/templates/endpoints/get_all.ts index b3b9257e9a..ee66e7c773 100644 --- a/templates/endpoints/get_all.ts +++ b/templates/endpoints/get_all.ts @@ -10,7 +10,7 @@ import { schemaResourcePublic } from "@lib/validations/resource"; * @swagger * /v1/resources: * get: - * summary: Get all resources + * summary: Find all resources * security: * - ApiKeyAuth: [] * tags: diff --git a/templates/endpoints/get_all_and_post.ts b/templates/endpoints/get_all_and_post.ts index bf6fee016f..2ce4b8dfe9 100644 --- a/templates/endpoints/get_all_and_post.ts +++ b/templates/endpoints/get_all_and_post.ts @@ -10,7 +10,7 @@ import { schemaPaymentBodyParams, schemaPaymentPublic } from "@lib/validations/p * @swagger * /v1/payments: * get: - * summary: Get all payments + * summary: Find all payments * security: * - ApiKeyAuth: [] * tags: diff --git a/templates/endpoints/post.ts b/templates/endpoints/post.ts index e2b9e17683..999bce39c1 100644 --- a/templates/endpoints/post.ts +++ b/templates/endpoints/post.ts @@ -19,7 +19,7 @@ import { schemaResourceBodyParams, schemaResourcePublic, withValidResource } fro * schema: * $ref: '#/components/schemas/Resource' * security: - * - ApiKeyAuth: [] + * - ApiKeyAuth: [] * tags: * - resources * responses: diff --git a/templates/zod-validation.ts b/templates/zod-validation.ts index 02b0597529..82a95a97d1 100644 --- a/templates/zod-validation.ts +++ b/templates/zod-validation.ts @@ -1,4 +1,3 @@ -import { withValidation } from "next-validations"; import { z } from "zod"; import { _ModelModel as Model } from "@calcom/prisma/zod"; @@ -15,9 +14,3 @@ export const schemaModelPublic = Model.omit({ id: true, userId: true, }); - -export const withValidModel = withValidation({ - schema: schemaModelBodyParams, - type: "Zod", - mode: "body", -}); From 238b03791e819992bfe7979b66b4d994b6420388 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 27 Apr 2022 19:45:59 +0200 Subject: [PATCH 160/658] Fix: add strict and optional to have errors on extraneus params --- lib/validations/attendee.ts | 3 +- lib/validations/availability.ts | 29 ++++++++++------- lib/validations/booking-reference.ts | 38 +++++++++++++--------- lib/validations/booking.ts | 33 ++++++++++--------- lib/validations/daily-event-reference.ts | 23 +++++++------ lib/validations/destination-calendar.ts | 41 +++++++++++++----------- 6 files changed, 94 insertions(+), 73 deletions(-) diff --git a/lib/validations/attendee.ts b/lib/validations/attendee.ts index d603eaaf63..70444437aa 100644 --- a/lib/validations/attendee.ts +++ b/lib/validations/attendee.ts @@ -15,14 +15,13 @@ const schemaAttendeeCreateParams = z .object({ bookingId: z.number().int(), email: z.string().email(), - name: z.string(), + name: z.string().optional(), timeZone: timeZone, }) .strict(); const schemaAttendeeEditParams = z .object({ - // @note: disallowing bookingId changes in attendee via API for now as it would introduce side effects name: z.string().optional(), email: z.string().email().optional(), timeZone: timeZone.optional(), diff --git a/lib/validations/availability.ts b/lib/validations/availability.ts index 6039dfb80f..a6ddf4b5c6 100644 --- a/lib/validations/availability.ts +++ b/lib/validations/availability.ts @@ -21,19 +21,24 @@ export const schemaAvailabilityReadPublic = Availability.pick({ eventTypeId: true, }); -const schemaAvailabilityCreateParams = z.object({ - startTime: z.date().or(z.string()), - endTime: z.date().or(z.string()), - days: z.array(z.number()).optional(), - eventTypeId: z.number().optional(), -}); +const schemaAvailabilityCreateParams = z + .object({ + startTime: z.date().or(z.string()), + endTime: z.date().or(z.string()), + days: z.array(z.number()).optional(), + eventTypeId: z.number().optional(), + }) + .strict(); + +const schemaAvailabilityEditParams = z + .object({ + startTime: z.date().or(z.string()).optional(), + endTime: z.date().or(z.string()).optional(), + days: z.array(z.number()).optional(), + eventTypeId: z.number().optional(), + }) + .strict(); -const schemaAvailabilityEditParams = z.object({ - startTime: z.date().or(z.string()).optional(), - endTime: z.date().or(z.string()).optional(), - days: z.array(z.number()).optional(), - eventTypeId: z.number().optional(), -}); export const schemaAvailabilityEditBodyParams = schemaAvailabilityBaseBodyParams.merge( schemaAvailabilityEditParams ); diff --git a/lib/validations/booking-reference.ts b/lib/validations/booking-reference.ts index f207b09208..66aabc3d88 100644 --- a/lib/validations/booking-reference.ts +++ b/lib/validations/booking-reference.ts @@ -23,22 +23,28 @@ export const schemaBookingReferenceReadPublic = BookingReference.pick({ deleted: true, }); -const schemaBookingReferenceEditParams = z.object({ - type: z.string(), - uid: z.string(), - meetingId: z.string(), - meetingPassword: z.string(), - meetingUrl: z.string(), - deleted: z.boolean(), -}); -const schemaBookingReferenceCreateParams = z.object({ - type: z.string(), - uid: z.string(), - meetingId: z.string(), - meetingPassword: z.string(), - meetingUrl: z.string(), - deleted: z.boolean(), -}); +const schemaBookingReferenceCreateParams = z + .object({ + type: z.string(), + uid: z.string(), + meetingId: z.string(), + meetingPassword: z.string(), + meetingUrl: z.string(), + deleted: z.boolean(), + }) + .strict(); + +const schemaBookingReferenceEditParams = z + .object({ + type: z.string().optional(), + uid: z.string().optional(), + meetingId: z.string().optional(), + meetingPassword: z.string().optional(), + meetingUrl: z.string().optional(), + deleted: z.boolean().optional(), + }) + .strict(); + export const schemaBookingCreateBodyParams = schemaBookingReferenceBaseBodyParams.merge( schemaBookingReferenceCreateParams ); diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index 5bf187f523..60c231efa5 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -11,24 +11,27 @@ const schemaBookingBaseBodyParams = Booking.pick({ endTime: true, }).partial(); -const schemaBookingCreateParams = z.object({ - uid: z.string(), - userId: z.number(), - eventTypeId: z.number(), - title: z.string(), - startTime: z.date(), - endTime: z.date(), -}); +const schemaBookingCreateParams = z + .object({ + uid: z.string(), + userId: z.number(), + eventTypeId: z.number(), + title: z.string(), + startTime: z.date(), + endTime: z.date(), + }) + .strict(); export const schemaBookingCreateBodyParams = schemaBookingBaseBodyParams.merge(schemaBookingCreateParams); -// @note: disallowing userId/eventTypeId changes in booking endpoint via PATCH for now as it would introduce side effects -const schemaBookingEditParams = z.object({ - uid: z.string(), - title: z.string(), - startTime: z.date(), - endTime: z.date(), -}); +const schemaBookingEditParams = z + .object({ + uid: z.string().optional(), + title: z.string().optional(), + startTime: z.date().optional(), + endTime: z.date().optional(), + }) + .strict(); export const schemaBookingEditBodyParams = schemaBookingBaseBodyParams.merge(schemaBookingEditParams); diff --git a/lib/validations/daily-event-reference.ts b/lib/validations/daily-event-reference.ts index ca74d5a95f..0ce79e6324 100644 --- a/lib/validations/daily-event-reference.ts +++ b/lib/validations/daily-event-reference.ts @@ -8,21 +8,24 @@ export const schemaDailyEventReferenceBaseBodyParams = DailyEventReference.pick( bookingId: true, }).partial(); -const schemaDailyEventReferenceCreateParams = z.object({ - dailytoken: z.string(), - dailyurl: z.string(), - bookingId: z.number(), -}); +const schemaDailyEventReferenceCreateParams = z + .object({ + dailytoken: z.string(), + dailyurl: z.string(), + bookingId: z.number(), + }) + .strict(); export const schemaDailyEventReferenceCreateBodyParams = schemaDailyEventReferenceBaseBodyParams.merge( schemaDailyEventReferenceCreateParams ); -const schemaDailyEventReferenceEditParams = z.object({ - dailytoken: z.string(), - dailyurl: z.string(), - // @note: disallowing bookingId changes in daily-event-reference via API endpoint for now as it would introduce side effects -}); +const schemaDailyEventReferenceEditParams = z + .object({ + dailytoken: z.string().optional(), + dailyurl: z.string().optional(), + }) + .strict(); export const schemaDailyEventReferenceEditBodyParams = schemaDailyEventReferenceBaseBodyParams.merge( schemaDailyEventReferenceEditParams diff --git a/lib/validations/destination-calendar.ts b/lib/validations/destination-calendar.ts index 541260d4dc..7f90cd0002 100644 --- a/lib/validations/destination-calendar.ts +++ b/lib/validations/destination-calendar.ts @@ -10,29 +10,34 @@ export const schemaDestinationCalendarBaseBodyParams = DestinationCalendar.pick( userId: true, }).partial(); -const schemaDestinationCalendarEditParams = z.object({ - integration: z.string(), - externalId: z.string(), - eventTypeId: z.number(), - bookingId: z.number(), - userId: z.number(), -}); - -export const schemaDestinationCalendarEditBodyParams = schemaDestinationCalendarBaseBodyParams.merge( - schemaDestinationCalendarEditParams -); -const schemaDestinationCalendarCreateParams = z.object({ - integration: z.string(), - externalId: z.string(), - eventTypeId: z.number(), - bookingId: z.number(), - userId: z.number(), -}); +const schemaDestinationCalendarCreateParams = z + .object({ + integration: z.string(), + externalId: z.string(), + eventTypeId: z.number(), + bookingId: z.number(), + userId: z.number(), + }) + .strict(); export const schemaDestinationCalendarCreateBodyParams = schemaDestinationCalendarBaseBodyParams.merge( schemaDestinationCalendarCreateParams ); +const schemaDestinationCalendarEditParams = z + .object({ + integration: z.string().optional(), + externalId: z.string().optional(), + eventTypeId: z.number().optional(), + bookingId: z.number().optional(), + userId: z.number().optional(), + }) + .strict(); + +export const schemaDestinationCalendarEditBodyParams = schemaDestinationCalendarBaseBodyParams.merge( + schemaDestinationCalendarEditParams +); + export const schemaDestinationCalendarReadPublic = DestinationCalendar.pick({ id: true, integration: true, From 217336d13da3c2372b4707bc172b208cad3a7e40 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 27 Apr 2022 20:24:30 +0200 Subject: [PATCH 161/658] fixes build error removing optional from name in create params validation --- lib/validations/attendee.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/attendee.ts b/lib/validations/attendee.ts index 70444437aa..cf73bdb4d0 100644 --- a/lib/validations/attendee.ts +++ b/lib/validations/attendee.ts @@ -15,7 +15,7 @@ const schemaAttendeeCreateParams = z .object({ bookingId: z.number().int(), email: z.string().email(), - name: z.string().optional(), + name: z.string(), timeZone: timeZone, }) .strict(); From bb28680413c9b989604f0f26f8aef5d7bb51ad46 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 29 Apr 2022 01:38:40 +0200 Subject: [PATCH 162/658] fixes all openapi spect issues, removes json-schema auto-generated moving to manual examples --- json-schema/json-schema.json | 136 ++++++++++---------- pages/api/attendees/[id].ts | 13 +- pages/api/attendees/index.ts | 9 +- pages/api/availabilities/[id].ts | 20 +-- pages/api/availabilities/index.ts | 7 +- pages/api/booking-references/[id].ts | 21 +-- pages/api/booking-references/index.ts | 8 +- pages/api/bookings/[id].ts | 21 +-- pages/api/bookings/index.ts | 7 +- pages/api/daily-event-references/[id].ts | 21 +-- pages/api/daily-event-references/index.ts | 7 +- pages/api/destination-calendars/[id].ts | 21 +-- pages/api/destination-calendars/index.ts | 7 +- pages/api/docs.ts | 19 +-- pages/api/event-type-custom-inputs/[id].ts | 27 +--- pages/api/event-type-custom-inputs/index.ts | 7 +- pages/api/event-types/[id].ts | 11 -- pages/api/event-types/index.ts | 7 +- pages/api/index.ts | 5 - pages/api/memberships/[id].ts | 21 +-- pages/api/memberships/index.ts | 7 +- pages/api/payments/[id].ts | 3 +- pages/api/payments/index.ts | 3 +- pages/api/schedules/[id].ts | 22 +--- pages/api/schedules/index.ts | 7 +- pages/api/selected-calendars/[id].ts | 20 +-- pages/api/selected-calendars/index.ts | 7 +- pages/api/teams/[id].ts | 22 +--- pages/api/teams/index.ts | 7 +- pages/api/users/[id].ts | 19 +-- pages/api/users/index.ts | 3 +- templates/endpoints/[id]/delete.ts | 4 +- templates/endpoints/[id]/edit.ts | 4 +- templates/endpoints/[id]/index.ts | 3 +- templates/endpoints/get_all.ts | 3 +- templates/endpoints/get_all_and_post.ts | 7 +- templates/endpoints/post.ts | 4 +- 37 files changed, 154 insertions(+), 386 deletions(-) diff --git a/json-schema/json-schema.json b/json-schema/json-schema.json index 1ae113fddf..f6a197e4a5 100644 --- a/json-schema/json-schema.json +++ b/json-schema/json-schema.json @@ -36,7 +36,7 @@ "users": { "type": "array", "items": { - "$ref": "#/definitions/User" + "$ref": "#/components/schemas/User" } }, "userId": { @@ -45,7 +45,7 @@ "team": { "anyOf": [ { - "$ref": "#/definitions/Team" + "$ref": "#/components/schemas/Team" }, { "type": "null" @@ -55,25 +55,25 @@ "bookings": { "type": "array", "items": { - "$ref": "#/definitions/Booking" + "$ref": "#/components/schemas/Booking" } }, "availability": { "type": "array", "items": { - "$ref": "#/definitions/Availability" + "$ref": "#/components/schemas/Availability" } }, "webhooks": { "type": "array", "items": { - "$ref": "#/definitions/Webhook" + "$ref": "#/components/schemas/Webhook" } }, "destinationCalendar": { "anyOf": [ { - "$ref": "#/definitions/DestinationCalendar" + "$ref": "#/components/schemas/DestinationCalendar" }, { "type": "null" @@ -86,7 +86,7 @@ "customInputs": { "type": "array", "items": { - "$ref": "#/definitions/EventTypeCustomInput" + "$ref": "#/components/schemas/EventTypeCustomInput" } }, "timeZone": { @@ -138,7 +138,7 @@ "schedule": { "anyOf": [ { - "$ref": "#/definitions/Schedule" + "$ref": "#/components/schemas/Schedule" }, { "type": "null" @@ -176,7 +176,7 @@ "user": { "anyOf": [ { - "$ref": "#/definitions/User" + "$ref": "#/components/schemas/User" }, { "type": "null" @@ -200,7 +200,7 @@ "user": { "anyOf": [ { - "$ref": "#/definitions/User" + "$ref": "#/components/schemas/User" }, { "type": "null" @@ -210,7 +210,7 @@ "booking": { "anyOf": [ { - "$ref": "#/definitions/Booking" + "$ref": "#/components/schemas/Booking" }, { "type": "null" @@ -220,7 +220,7 @@ "eventType": { "anyOf": [ { - "$ref": "#/definitions/EventType" + "$ref": "#/components/schemas/EventType" }, { "type": "null" @@ -296,31 +296,31 @@ "eventTypes": { "type": "array", "items": { - "$ref": "#/definitions/EventType" + "$ref": "#/components/schemas/EventType" } }, "credentials": { "type": "array", "items": { - "$ref": "#/definitions/Credential" + "$ref": "#/components/schemas/Credential" } }, "teams": { "type": "array", "items": { - "$ref": "#/definitions/Membership" + "$ref": "#/components/schemas/Membership" } }, "bookings": { "type": "array", "items": { - "$ref": "#/definitions/Booking" + "$ref": "#/components/schemas/Booking" } }, "schedules": { "type": "array", "items": { - "$ref": "#/definitions/Schedule" + "$ref": "#/components/schemas/Schedule" } }, "defaultScheduleId": { @@ -329,7 +329,7 @@ "selectedCalendars": { "type": "array", "items": { - "$ref": "#/definitions/SelectedCalendar" + "$ref": "#/components/schemas/SelectedCalendar" } }, "completedOnboarding": { @@ -361,7 +361,7 @@ "availability": { "type": "array", "items": { - "$ref": "#/definitions/Availability" + "$ref": "#/components/schemas/Availability" } }, "invitedTo": { @@ -375,7 +375,7 @@ "webhooks": { "type": "array", "items": { - "$ref": "#/definitions/Webhook" + "$ref": "#/components/schemas/Webhook" } }, "brandColor": { @@ -389,7 +389,7 @@ "destinationCalendar": { "anyOf": [ { - "$ref": "#/definitions/DestinationCalendar" + "$ref": "#/components/schemas/DestinationCalendar" }, { "type": "null" @@ -410,7 +410,7 @@ "apiKeys": { "type": "array", "items": { - "$ref": "#/definitions/ApiKey" + "$ref": "#/components/schemas/ApiKey" } } } @@ -440,13 +440,13 @@ "members": { "type": "array", "items": { - "$ref": "#/definitions/Membership" + "$ref": "#/components/schemas/Membership" } }, "eventTypes": { "type": "array", "items": { - "$ref": "#/definitions/EventType" + "$ref": "#/components/schemas/EventType" } } } @@ -463,10 +463,10 @@ "enum": ["MEMBER", "ADMIN", "OWNER"] }, "team": { - "$ref": "#/definitions/Team" + "$ref": "#/components/schemas/Team" }, "user": { - "$ref": "#/definitions/User" + "$ref": "#/components/schemas/User" } } }, @@ -520,7 +520,7 @@ "booking": { "anyOf": [ { - "$ref": "#/definitions/Booking" + "$ref": "#/components/schemas/Booking" }, { "type": "null" @@ -551,7 +551,7 @@ "booking": { "anyOf": [ { - "$ref": "#/definitions/Booking" + "$ref": "#/components/schemas/Booking" }, { "type": "null" @@ -577,7 +577,7 @@ "booking": { "anyOf": [ { - "$ref": "#/definitions/Booking" + "$ref": "#/components/schemas/Booking" }, { "type": "null" @@ -598,7 +598,7 @@ "user": { "anyOf": [ { - "$ref": "#/definitions/User" + "$ref": "#/components/schemas/User" }, { "type": "null" @@ -608,13 +608,13 @@ "references": { "type": "array", "items": { - "$ref": "#/definitions/BookingReference" + "$ref": "#/components/schemas/BookingReference" } }, "eventType": { "anyOf": [ { - "$ref": "#/definitions/EventType" + "$ref": "#/components/schemas/EventType" }, { "type": "null" @@ -638,7 +638,7 @@ "attendees": { "type": "array", "items": { - "$ref": "#/definitions/Attendee" + "$ref": "#/components/schemas/Attendee" } }, "location": { @@ -647,7 +647,7 @@ "dailyRef": { "anyOf": [ { - "$ref": "#/definitions/DailyEventReference" + "$ref": "#/components/schemas/DailyEventReference" }, { "type": "null" @@ -682,13 +682,13 @@ "payment": { "type": "array", "items": { - "$ref": "#/definitions/Payment" + "$ref": "#/components/schemas/Payment" } }, "destinationCalendar": { "anyOf": [ { - "$ref": "#/definitions/DestinationCalendar" + "$ref": "#/components/schemas/DestinationCalendar" }, { "type": "null" @@ -710,12 +710,12 @@ "type": "integer" }, "user": { - "$ref": "#/definitions/User" + "$ref": "#/components/schemas/User" }, "eventType": { "anyOf": [ { - "$ref": "#/definitions/EventType" + "$ref": "#/components/schemas/EventType" }, { "type": "null" @@ -731,7 +731,7 @@ "availability": { "type": "array", "items": { - "$ref": "#/definitions/Availability" + "$ref": "#/components/schemas/Availability" } } } @@ -745,7 +745,7 @@ "user": { "anyOf": [ { - "$ref": "#/definitions/User" + "$ref": "#/components/schemas/User" }, { "type": "null" @@ -755,7 +755,7 @@ "eventType": { "anyOf": [ { - "$ref": "#/definitions/EventType" + "$ref": "#/components/schemas/EventType" }, { "type": "null" @@ -783,7 +783,7 @@ "Schedule": { "anyOf": [ { - "$ref": "#/definitions/Schedule" + "$ref": "#/components/schemas/Schedule" }, { "type": "null" @@ -796,7 +796,7 @@ "type": "object", "properties": { "user": { - "$ref": "#/definitions/User" + "$ref": "#/components/schemas/User" }, "integration": { "type": "string" @@ -813,7 +813,7 @@ "type": "integer" }, "eventType": { - "$ref": "#/definitions/EventType" + "$ref": "#/components/schemas/EventType" }, "label": { "type": "string" @@ -892,7 +892,7 @@ "booking": { "anyOf": [ { - "$ref": "#/definitions/Booking" + "$ref": "#/components/schemas/Booking" }, { "type": "null" @@ -949,7 +949,7 @@ "user": { "anyOf": [ { - "$ref": "#/definitions/User" + "$ref": "#/components/schemas/User" }, { "type": "null" @@ -959,7 +959,7 @@ "eventType": { "anyOf": [ { - "$ref": "#/definitions/EventType" + "$ref": "#/components/schemas/EventType" }, { "type": "null" @@ -977,7 +977,7 @@ "user": { "anyOf": [ { - "$ref": "#/definitions/User" + "$ref": "#/components/schemas/User" }, { "type": "null" @@ -1001,64 +1001,64 @@ "type": "object", "properties": { "eventType": { - "$ref": "#/definitions/EventType" + "$ref": "#/components/schemas/EventType" }, "credential": { - "$ref": "#/definitions/Credential" + "$ref": "#/components/schemas/Credential" }, "destinationCalendar": { - "$ref": "#/definitions/DestinationCalendar" + "$ref": "#/components/schemas/DestinationCalendar" }, "user": { - "$ref": "#/definitions/User" + "$ref": "#/components/schemas/User" }, "team": { - "$ref": "#/definitions/Team" + "$ref": "#/components/schemas/Team" }, "membership": { - "$ref": "#/definitions/Membership" + "$ref": "#/components/schemas/Membership" }, "verificationRequest": { - "$ref": "#/definitions/VerificationRequest" + "$ref": "#/components/schemas/VerificationRequest" }, "bookingReference": { - "$ref": "#/definitions/BookingReference" + "$ref": "#/components/schemas/BookingReference" }, "attendee": { - "$ref": "#/definitions/Attendee" + "$ref": "#/components/schemas/Attendee" }, "dailyEventReference": { - "$ref": "#/definitions/DailyEventReference" + "$ref": "#/components/schemas/DailyEventReference" }, "booking": { - "$ref": "#/definitions/Booking" + "$ref": "#/components/schemas/Booking" }, "schedule": { - "$ref": "#/definitions/Schedule" + "$ref": "#/components/schemas/Schedule" }, "availability": { - "$ref": "#/definitions/Availability" + "$ref": "#/components/schemas/Availability" }, "selectedCalendar": { - "$ref": "#/definitions/SelectedCalendar" + "$ref": "#/components/schemas/SelectedCalendar" }, "eventTypeCustomInput": { - "$ref": "#/definitions/EventTypeCustomInput" + "$ref": "#/components/schemas/EventTypeCustomInput" }, "resetPasswordRequest": { - "$ref": "#/definitions/ResetPasswordRequest" + "$ref": "#/components/schemas/ResetPasswordRequest" }, "reminderMail": { - "$ref": "#/definitions/ReminderMail" + "$ref": "#/components/schemas/ReminderMail" }, "payment": { - "$ref": "#/definitions/Payment" + "$ref": "#/components/schemas/Payment" }, "webhook": { - "$ref": "#/definitions/Webhook" + "$ref": "#/components/schemas/Webhook" }, "apiKey": { - "$ref": "#/definitions/ApiKey" + "$ref": "#/components/schemas/ApiKey" } } } diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index ce41228cd0..b27c2e40fb 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -23,8 +23,7 @@ import { * required: true * description: Numeric ID of the attendee to get * example: 3 - * security: - * - ApiKeyAuth: [] + * tags: * - attendees * responses: @@ -36,8 +35,6 @@ import { * description: Attendee was not found * patch: * summary: Edit an existing attendee - * consumes: - * - application/json * requestBody: * description: Edit an existing attendee related to one of your bookings * required: true @@ -68,14 +65,12 @@ import { * example: 3 * required: true * description: Numeric ID of the attendee to edit - * security: - * - ApiKeyAuth: [] + * tags: * - attendees * responses: * 201: * description: OK, attendee edited successfuly - * model: Attendee * 400: * description: Bad request. Attendee body is invalid. * 401: @@ -89,14 +84,12 @@ import { * type: integer * required: true * description: Numeric ID of the attendee to delete - * security: - * - ApiKeyAuth: [] + * tags: * - attendees * responses: * 201: * description: OK, attendee removed successfuly - * model: Attendee * 400: * description: Bad request. Attendee id is invalid. * 401: diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index 3adbc8a78c..a0514bb8df 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -11,8 +11,7 @@ import { schemaAttendeeCreateBodyParams, schemaAttendeeReadPublic } from "@lib/v * /attendees: * get: * summary: Find all attendees - * security: - * - ApiKeyAuth: [] + * tags: * - attendees * responses: @@ -24,10 +23,7 @@ import { schemaAttendeeCreateBodyParams, schemaAttendeeReadPublic } from "@lib/v * description: No attendees were found * post: * summary: Creates a new attendee - * security: - * - ApiKeyAuth: [] - * consumes: - * - application/json + * requestBody: * description: Create a new attendee related to one of your bookings * required: true @@ -58,7 +54,6 @@ import { schemaAttendeeCreateBodyParams, schemaAttendeeReadPublic } from "@lib/v * responses: * 201: * description: OK, attendee created - * model: Attendee * 400: * description: Bad request. Attendee body is invalid. * 401: diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index 65f750dba7..ad6826a6d3 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -25,8 +25,7 @@ import { * type: integer * required: true * description: Numeric ID of the availability to get - * security: - * - ApiKeyAuth: [] + * tags: * - availabilities * externalDocs: @@ -40,24 +39,14 @@ import { * description: Availability was not found * patch: * summary: Edit an existing availability - * consumes: - * - application/json * parameters: - * - in: body - * name: availability - * description: The availability to edit - * schema: - * type: object - * $ref: '#/components/schemas/Availability' - * required: true * - in: path * name: id * schema: * type: integer * required: true * description: Numeric ID of the availability to edit - * security: - * - ApiKeyAuth: [] + * tags: * - availabilities * externalDocs: @@ -65,7 +54,6 @@ import { * responses: * 201: * description: OK, availability edited successfuly - * model: Availability * 400: * description: Bad request. Availability body is invalid. * 401: @@ -79,8 +67,7 @@ import { * type: integer * required: true * description: Numeric ID of the availability to delete - * security: - * - ApiKeyAuth: [] + * tags: * - availabilities * externalDocs: @@ -88,7 +75,6 @@ import { * responses: * 201: * description: OK, availability removed successfuly - * model: Availability * 400: * description: Bad request. Availability id is invalid. * 401: diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index 3e519bc6ad..7d8f18eac3 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -14,8 +14,7 @@ import { * /availabilities: * get: * summary: Find all availabilities - * security: - * - ApiKeyAuth: [] + * tags: * - availabilities * externalDocs: @@ -29,8 +28,7 @@ import { * description: No availabilities were found * post: * summary: Creates a new availability - * security: - * - ApiKeyAuth: [] + * tags: * - availabilities * externalDocs: @@ -38,7 +36,6 @@ import { * responses: * 201: * description: OK, availability created - * model: Availability * 400: * description: Bad request. Availability body is invalid. * 401: diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index 21b314f728..4014707eb4 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -26,8 +26,7 @@ import { * type: integer * required: true * description: Numeric ID of the booking reference to get - * security: - * - ApiKeyAuth: [] + * tags: * - booking-references * responses: @@ -39,30 +38,20 @@ import { * description: BookingReference was not found * patch: * summary: Edit an existing booking reference - * consumes: - * - application/json + * parameters: - * - in: body - * name: bookingReference - * description: The bookingReference to edit - * schema: - * type: object - * $ref: '#/components/schemas/BookingReference' - * required: true * - in: path * name: id * schema: * type: integer * required: true * description: Numeric ID of the booking reference to edit - * security: - * - ApiKeyAuth: [] + * tags: * - booking-references * responses: * 201: * description: OK, bookingReference edited successfuly - * model: BookingReference * 400: * description: Bad request. BookingReference body is invalid. * 401: @@ -76,14 +65,12 @@ import { * type: integer * required: true * description: Numeric ID of the booking reference to delete - * security: - * - ApiKeyAuth: [] + * tags: * - booking-references * responses: * 201: * description: OK, bookingReference removed successfuly - * model: BookingReference * 400: * description: Bad request. BookingReference id is invalid. * 401: diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index bc82f23701..c214b305db 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -14,8 +14,7 @@ import { * /booking-references: * get: * summary: Find all booking references - * security: - * - ApiKeyAuth: [] + * tags: * - booking-references * responses: @@ -27,14 +26,13 @@ import { * description: No booking references were found * post: * summary: Creates a new booking reference - * security: - * - ApiKeyAuth: [] + * tags: * - booking-references * responses: * 201: * description: OK, booking reference created - * model: BookingReference + * 400: * description: Bad request. BookingReference body is invalid. * 401: diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index 21be432cd1..9c1b647b20 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -22,8 +22,7 @@ import { * type: integer * required: true * description: Numeric ID of the booking to get - * security: - * - ApiKeyAuth: [] + * tags: * - bookings * responses: @@ -35,30 +34,20 @@ import { * description: Booking was not found * patch: * summary: Edit an existing booking - * consumes: - * - application/json + * parameters: - * - in: body - * name: booking - * description: The booking to edit - * schema: - * type: object - * $ref: '#/components/schemas/Booking' - * required: true * - in: path * name: id * schema: * type: integer * required: true * description: Numeric ID of the booking to edit - * security: - * - ApiKeyAuth: [] + * tags: * - bookings * responses: * 201: * description: OK, booking edited successfuly - * model: Booking * 400: * description: Bad request. Booking body is invalid. * 401: @@ -72,14 +61,12 @@ import { * type: integer * required: true * description: Numeric ID of the booking to delete - * security: - * - ApiKeyAuth: [] + * tags: * - bookings * responses: * 201: * description: OK, booking removed successfuly - * model: Booking * 400: * description: Bad request. Booking id is invalid. * 401: diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 8bb9cae30d..311a79b4dd 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -11,8 +11,7 @@ import { schemaBookingCreateBodyParams, schemaBookingReadPublic } from "@lib/val * /bookings: * get: * summary: Find all bookings - * security: - * - ApiKeyAuth: [] + * tags: * - bookings * responses: @@ -24,14 +23,12 @@ import { schemaBookingCreateBodyParams, schemaBookingReadPublic } from "@lib/val * description: No bookings were found * post: * summary: Creates a new booking - * security: - * - ApiKeyAuth: [] + * tags: * - bookings * responses: * 201: * description: OK, booking created - * model: Booking * 400: * description: Bad request. Booking body is invalid. * 401: diff --git a/pages/api/daily-event-references/[id].ts b/pages/api/daily-event-references/[id].ts index 6ef4ac01e2..a59beeebbf 100644 --- a/pages/api/daily-event-references/[id].ts +++ b/pages/api/daily-event-references/[id].ts @@ -25,8 +25,7 @@ import { * type: integer * required: true * description: Numeric ID of the daily event reference to get - * security: - * - ApiKeyAuth: [] + * tags: * - daily-event-references * responses: @@ -38,30 +37,20 @@ import { * description: DailyEventReference was not found * patch: * summary: Edit an existing daily event reference - * consumes: - * - application/json + * parameters: - * - in: body - * name: dailyEventReference - * description: The dailyEventReference to edit - * schema: - * type: object - * $ref: '#/components/schemas/DailyEventReference' - * required: true * - in: path * name: id * schema: * type: integer * required: true * description: Numeric ID of the daily event reference to edit - * security: - * - ApiKeyAuth: [] + * tags: * - daily-event-references * responses: * 201: * description: OK, dailyEventReference edited successfuly - * model: DailyEventReference * 400: * description: Bad request. DailyEventReference body is invalid. * 401: @@ -75,14 +64,12 @@ import { * type: integer * required: true * description: Numeric ID of the daily event reference to delete - * security: - * - ApiKeyAuth: [] + * tags: * - daily-event-references * responses: * 201: * description: OK, dailyEventReference removed successfuly - * model: DailyEventReference * 400: * description: Bad request. DailyEventReference id is invalid. * 401: diff --git a/pages/api/daily-event-references/index.ts b/pages/api/daily-event-references/index.ts index dfafe246ce..290469f307 100644 --- a/pages/api/daily-event-references/index.ts +++ b/pages/api/daily-event-references/index.ts @@ -14,8 +14,7 @@ import { * /daily-event-references: * get: * summary: Find all daily event reference - * security: - * - ApiKeyAuth: [] + * tags: * - daily-event-references * responses: @@ -27,14 +26,12 @@ import { * description: No daily event references were found * post: * summary: Creates a new daily event reference - * security: - * - ApiKeyAuth: [] + * tags: * - daily-event-references * responses: * 201: * description: OK, daily event reference created - * model: DailyEventReference * 400: * description: Bad request. DailyEventReference body is invalid. * 401: diff --git a/pages/api/destination-calendars/[id].ts b/pages/api/destination-calendars/[id].ts index 60982a7058..ecfe646b09 100644 --- a/pages/api/destination-calendars/[id].ts +++ b/pages/api/destination-calendars/[id].ts @@ -25,8 +25,7 @@ import { * type: integer * required: true * description: Numeric ID of the destination calendar to get - * security: - * - ApiKeyAuth: [] + * tags: * - destination-calendars * responses: @@ -38,30 +37,20 @@ import { * description: DestinationCalendar was not found * patch: * summary: Edit an existing destination calendar - * consumes: - * - application/json + * parameters: - * - in: body - * name: destinationCalendar - * description: The destinationCalendar to edit - * schema: - * type: object - * $ref: '#/components/schemas/DestinationCalendar' - * required: true * - in: path * name: id * schema: * type: integer * required: true * description: Numeric ID of the destination calendar to edit - * security: - * - ApiKeyAuth: [] + * tags: * - destination-calendars * responses: * 201: * description: OK, destinationCalendar edited successfuly - * model: DestinationCalendar * 400: * description: Bad request. DestinationCalendar body is invalid. * 401: @@ -75,14 +64,12 @@ import { * type: integer * required: true * description: Numeric ID of the destination calendar to delete - * security: - * - ApiKeyAuth: [] + * tags: * - destination-calendars * responses: * 201: * description: OK, destinationCalendar removed successfuly - * model: DestinationCalendar * 400: * description: Bad request. DestinationCalendar id is invalid. * 401: diff --git a/pages/api/destination-calendars/index.ts b/pages/api/destination-calendars/index.ts index d7921491c9..cf33e0fa58 100644 --- a/pages/api/destination-calendars/index.ts +++ b/pages/api/destination-calendars/index.ts @@ -14,8 +14,7 @@ import { * /destination-calendars: * get: * summary: Find all destination calendars - * security: - * - ApiKeyAuth: [] + * tags: * - destination-calendars * responses: @@ -27,14 +26,12 @@ import { * description: No destination calendars were found * post: * summary: Creates a new destination calendar - * security: - * - ApiKeyAuth: [] + * tags: * - destination-calendars * responses: * 201: * description: OK, destination calendar created - * model: DestinationCalendar * 400: * description: Bad request. DestinationCalendar body is invalid. * 401: diff --git a/pages/api/docs.ts b/pages/api/docs.ts index 7dd7afa65d..356967d4a2 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -20,26 +20,9 @@ const swaggerHandler = withSwagger({ }, components: { securitySchemes: { ApiKeyAuth: { type: "apiKey", in: "query", name: "apiKey" } }, - security: { ApiKeyAuth: [] }, - schemas: { ...jsonSchema.definitions }, }, + security: [{ apiKey: [] }], }, apiFolder: "pages/api", - tags: [ - "users", - "teams", - "memeberships", - "selected-calendars", - "schedules", - "payments", - "event-types", - "event-type-custom-inputs", - "destination-calendars", - "daily-event-references", - "booking-references", - "availabilities", - "attendees", - ], - sort: true, }); export default swaggerHandler(); diff --git a/pages/api/event-type-custom-inputs/[id].ts b/pages/api/event-type-custom-inputs/[id].ts index 7d3ffa7a5d..6760e4b39c 100644 --- a/pages/api/event-type-custom-inputs/[id].ts +++ b/pages/api/event-type-custom-inputs/[id].ts @@ -25,8 +25,7 @@ import { * type: integer * required: true * description: Numeric ID of the eventTypeCustomInput to get - * security: - * - ApiKeyAuth: [] + * tags: * - event-type-custom-inputs * responses: @@ -35,35 +34,25 @@ import { * 401: * description: Authorization information is missing or invalid. * 404: - * deCustomInputscription: EventType was not found + * description: EventType was not found * patch: * summary: Edit an existing eventTypeCustomInput - * consumes: - * - application/json + * parameters: - * - in: body - * name: eventTypeCustomInput - * description: The eventTypeCustomInput to edit - * schema: - * type: object - * $ref: '#/components/schemas/EventTypeCustomInput' - * required: true * - in: path * name: id * schema: * type: integer * required: true * description: Numeric ID of the eventTypeCustomInput to edit - * security: - * - ApiKeyAuth: [] + * tags: * - event-type-custom-inputs * responses: * 201: * description: OK, eventTypeCustomInput edited successfuly - * model: EventTypeCustomInput * 400: - * desCustomInputcription: Bad request. EventType body is invalid. + * description: Bad request. EventType body is invalid. * 401: * description: Authorization information is missing or invalid. * delete: @@ -75,16 +64,14 @@ import { * type: integer * required: true * description: Numeric ID of the eventTypeCustomInput to delete - * security: - * - ApiKeyAuth: [] + * tags: * - event-type-custom-inputs * responses: * 201: * description: OK, eventTypeCustomInput removed successfuly - * model: EventTypeCustomInput * 400: - * desCustomInputcription: Bad request. EventType id is invalid. + * description: Bad request. EventType id is invalid. * 401: * description: Authorization information is missing or invalid. */ diff --git a/pages/api/event-type-custom-inputs/index.ts b/pages/api/event-type-custom-inputs/index.ts index 01f5af921f..e7cc037cd9 100644 --- a/pages/api/event-type-custom-inputs/index.ts +++ b/pages/api/event-type-custom-inputs/index.ts @@ -14,8 +14,7 @@ import { * /event-type-custom-inputs: * get: * summary: Find all eventTypeCustomInputs - * security: - * - ApiKeyAuth: [] + * tags: * - event-type-custom-inputs * responses: @@ -27,14 +26,12 @@ import { * description: No eventTypeCustomInputs were found * post: * summary: Creates a new eventTypeCustomInput - * security: - * - ApiKeyAuth: [] + * tags: * - event-type-custom-inputs * responses: * 201: * description: OK, eventTypeCustomInput created - * model: EventTypeCustomInput * 400: * description: Bad request. EventTypeCustomInput body is invalid. * 401: diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 37a5b38be7..ebb440bd37 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -37,16 +37,7 @@ import { * description: EventType was not found * patch: * summary: Edit an existing eventType - * consumes: - * - application/json * parameters: - * - in: body - * name: eventType - * description: The eventType to edit - * schema: - * type: object - * $ref: '#/components/schemas/EventType' - * required: true * - in: path * name: id * schema: @@ -62,7 +53,6 @@ import { * responses: * 201: * description: OK, eventType edited successfuly - * model: EventType * 400: * description: Bad request. EventType body is invalid. * 401: @@ -85,7 +75,6 @@ import { * responses: * 201: * description: OK, eventType removed successfuly - * model: EventType * 400: * description: Bad request. EventType id is invalid. * 401: diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 9e1e83c038..eb6c7d1290 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -11,8 +11,7 @@ import { schemaEventTypeBodyParams, schemaEventTypePublic } from "@lib/validatio * /event-types: * get: * summary: Find all event types - * security: - * - ApiKeyAuth: [] + * tags: * - event-types * externalDocs: @@ -26,8 +25,7 @@ import { schemaEventTypeBodyParams, schemaEventTypePublic } from "@lib/validatio * description: No event types were found * post: * summary: Creates a new event type - * security: - * - ApiKeyAuth: [] + * tags: * - event-types * externalDocs: @@ -35,7 +33,6 @@ import { schemaEventTypeBodyParams, schemaEventTypePublic } from "@lib/validatio * responses: * 201: * description: OK, event type created - * model: EventType * 400: * description: Bad request. EventType body is invalid. * 401: diff --git a/pages/api/index.ts b/pages/api/index.ts index 3f72b7eaef..94461cedce 100644 --- a/pages/api/index.ts +++ b/pages/api/index.ts @@ -1,10 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; -/** - * @swagger - * security: - * - ApiKeyAuth: [] - */ export default async function CalcomApi(_: NextApiRequest, res: NextApiResponse) { res.status(201).json({ message: "Welcome to Cal.com API - docs are at https://docs.cal.com/api" }); } diff --git a/pages/api/memberships/[id].ts b/pages/api/memberships/[id].ts index 0e7498d16c..3172428ec3 100644 --- a/pages/api/memberships/[id].ts +++ b/pages/api/memberships/[id].ts @@ -25,8 +25,7 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * type: integer * required: true * description: Numeric teamId of the membership to get - * security: - * - ApiKeyAuth: [] + * tags: * - memberships * responses: @@ -38,16 +37,8 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * description: Membership was not found * patch: * summary: Edit an existing membership - * consumes: - * - application/json + * parameters: - * - in: body - * name: membership - * description: The membership to edit - * schema: - * type: object - * $ref: '#/components/schemas/Membership' - * required: true * - in: path * name: userId * schema: @@ -60,14 +51,12 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * type: integer * required: true * description: Numeric teamId of the membership to get - * security: - * - ApiKeyAuth: [] + * tags: * - memberships * responses: * 201: * description: OK, membership edited successfuly - * model: Membership * 400: * description: Bad request. Membership body is invalid. * 401: @@ -87,14 +76,12 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * type: integer * required: true * description: Numeric teamId of the membership to get - * security: - * - ApiKeyAuth: [] + * tags: * - memberships * responses: * 201: * description: OK, membership removed successfuly - * model: Membership * 400: * description: Bad request. Membership id is invalid. * 401: diff --git a/pages/api/memberships/index.ts b/pages/api/memberships/index.ts index 3df3b56d13..78072dd68d 100644 --- a/pages/api/memberships/index.ts +++ b/pages/api/memberships/index.ts @@ -11,8 +11,7 @@ import { schemaMembershipBodyParams, schemaMembershipPublic } from "@lib/validat * /memberships: * get: * summary: Find all memberships - * security: - * - ApiKeyAuth: [] + * tags: * - memberships * responses: @@ -24,14 +23,12 @@ import { schemaMembershipBodyParams, schemaMembershipPublic } from "@lib/validat * description: No memberships were found * post: * summary: Creates a new membership - * security: - * - ApiKeyAuth: [] + * tags: * - memberships * responses: * 201: * description: OK, membership created - * model: Membership * 400: * description: Bad request. Membership body is invalid. * 401: diff --git a/pages/api/payments/[id].ts b/pages/api/payments/[id].ts index 8ab4d5eab9..9f0d8315dd 100644 --- a/pages/api/payments/[id].ts +++ b/pages/api/payments/[id].ts @@ -22,8 +22,7 @@ import { * type: integer * required: true * description: Numeric ID of the payment to get - * security: - * - ApiKeyAuth: [] + * tags: * - payments * responses: diff --git a/pages/api/payments/index.ts b/pages/api/payments/index.ts index db0cd349ca..5d16b911df 100644 --- a/pages/api/payments/index.ts +++ b/pages/api/payments/index.ts @@ -11,8 +11,7 @@ import { schemaPaymentPublic } from "@lib/validations/payment"; * /payments: * get: * summary: Find all payments - * security: - * - ApiKeyAuth: [] + * tags: * - payments * responses: diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index 8a08128f4f..a2d9da0366 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -22,8 +22,7 @@ import { * type: integer * required: true * description: Numeric ID of the schedule to get - * security: - * - ApiKeyAuth: [] + * tags: * - schedules * responses: @@ -35,30 +34,21 @@ import { * description: Schedule was not found * patch: * summary: Edit an existing schedule - * consumes: - * - application/json + * parameters: - * - in: body - * name: schedule - * description: The schedule to edit - * schema: - * type: object - * $ref: '#/components/schemas/Schedule' - * required: true + * - in: path * name: id * schema: * type: integer * required: true * description: Numeric ID of the schedule to edit - * security: - * - ApiKeyAuth: [] + * tags: * - schedules * responses: * 201: * description: OK, schedule edited successfuly - * model: Schedule * 400: * description: Bad request. Schedule body is invalid. * 401: @@ -72,14 +62,12 @@ import { * type: integer * required: true * description: Numeric ID of the schedule to delete - * security: - * - ApiKeyAuth: [] + * tags: * - schedules * responses: * 201: * description: OK, schedule removed successfuly - * model: Schedule * 400: * description: Bad request. Schedule id is invalid. * 401: diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index 228599eef3..29fe160340 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -11,8 +11,7 @@ import { schemaScheduleBodyParams, schemaSchedulePublic } from "@lib/validations * /schedules: * get: * summary: Find all schedules - * security: - * - ApiKeyAuth: [] + * tags: * - schedules * responses: @@ -24,14 +23,12 @@ import { schemaScheduleBodyParams, schemaSchedulePublic } from "@lib/validations * description: No schedules were found * post: * summary: Creates a new schedule - * security: - * - ApiKeyAuth: [] + * tags: * - schedules * responses: * 201: * description: OK, schedule created - * model: Schedule * 400: * description: Bad request. Schedule body is invalid. * 401: diff --git a/pages/api/selected-calendars/[id].ts b/pages/api/selected-calendars/[id].ts index 6efbca86ee..b3df3b88b2 100644 --- a/pages/api/selected-calendars/[id].ts +++ b/pages/api/selected-calendars/[id].ts @@ -34,8 +34,7 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * type: string * required: true * description: integration of the selected calendar to get - * security: - * - ApiKeyAuth: [] + * tags: * - selected-calendars * responses: @@ -47,16 +46,7 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * description: SelectedCalendar was not found * patch: * summary: Edit an existing selected calendar - * consumes: - * - application/json * parameters: - * - in: body - * name: selected-calendar - * description: The selected-calendar to edit - * schema: - * type: object - * $ref: '#/components/schemas/SelectedCalendar' - * required: true * - in: path * name: userId * schema: @@ -75,14 +65,12 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * type: string * required: true * description: integration of the selected calendar to get - * security: - * - ApiKeyAuth: [] + * tags: * - selected-calendars * responses: * 201: * description: OK, selected-calendar edited successfuly - * model: SelectedCalendar * 400: * description: Bad request. SelectedCalendar body is invalid. * 401: @@ -108,14 +96,12 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * type: string * required: true * description: integration of the selected calendar to get - * security: - * - ApiKeyAuth: [] + * tags: * - selected-calendars * responses: * 201: * description: OK, selected-calendar removed successfuly - * model: SelectedCalendar * 400: * description: Bad request. SelectedCalendar id is invalid. * 401: diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index 83537208ba..055ae51346 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -14,8 +14,7 @@ import { * /selected-calendars: * get: * summary: Find all selected calendars - * security: - * - ApiKeyAuth: [] + * tags: * - selected-calendars * responses: @@ -27,14 +26,12 @@ import { * description: No selected calendars were found * post: * summary: Creates a new selected calendar - * security: - * - ApiKeyAuth: [] + * tags: * - selected-calendars * responses: * 201: * description: OK, selected calendar created - * model: SelectedCalendar * 400: * description: Bad request. SelectedCalendar body is invalid. * 401: diff --git a/pages/api/teams/[id].ts b/pages/api/teams/[id].ts index 0fead8e066..9fb11b5e50 100644 --- a/pages/api/teams/[id].ts +++ b/pages/api/teams/[id].ts @@ -22,8 +22,7 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * type: integer * required: true * description: Numeric ID of the team to get - * security: - * - ApiKeyAuth: [] + * tags: * - teams * responses: @@ -33,36 +32,27 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * description: Authorization information is missing or invalid. * 404: * description: Team was not found + * patch: * summary: Edit an existing team - * consumes: - * - application/json * parameters: - * - in: body - * name: team - * description: The team to edit - * schema: - * type: object - * $ref: '#/components/schemas/Team' - * required: true * - in: path * name: id * schema: * type: integer * required: true * description: Numeric ID of the team to edit - * security: - * - ApiKeyAuth: [] + * tags: * - teams * responses: * 201: * description: OK, team edited successfuly - * model: Team * 400: * description: Bad request. Team body is invalid. * 401: * description: Authorization information is missing or invalid. + * delete: * summary: Remove an existing team * parameters: @@ -72,14 +62,12 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * type: integer * required: true * description: Numeric ID of the team to delete - * security: - * - ApiKeyAuth: [] + * tags: * - teams * responses: * 201: * description: OK, team removed successfuly - * model: Team * 400: * description: Bad request. Team id is invalid. * 401: diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index ce335fff9d..11d646f70f 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -12,8 +12,7 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * /teams: * get: * summary: Find all teams - * security: - * - ApiKeyAuth: [] + * tags: * - teams * responses: @@ -25,14 +24,12 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * description: No teams were found * post: * summary: Creates a new team - * security: - * - ApiKeyAuth: [] + * tags: * - teams * responses: * 201: * description: OK, team created - * model: Team * 400: * description: Bad request. Team body is invalid. * 401: diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index 06e5612dd0..f8aed85d7d 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -22,8 +22,7 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations * type: integer * required: true * description: Numeric ID of the user to get - * security: - * - ApiKeyAuth: [] + * tags: * - users * responses: @@ -35,28 +34,20 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations * description: User was not found * patch: * summary: Edit an existing user - * consumes: - * - application/json + * parameters: - * - in: body - * name: name - * description: The users full name - * schema: - * type: string * - in: path * name: id * schema: * type: integer * required: true * description: Numeric ID of the user to edit - * security: - * - ApiKeyAuth: [] + * tags: * - users * responses: * 201: * description: OK, user edited successfuly - * model: User * 400: * description: Bad request. User body is invalid. * 401: @@ -70,14 +61,12 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations * type: integer * required: true * description: Numeric ID of the user to delete - * security: - * - ApiKeyAuth: [] + * tags: * - users * responses: * 201: * description: OK, user removed successfuly - * model: User * 400: * description: Bad request. User id is invalid. * 401: diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index fa28b36f5e..c5dfd71b68 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -11,8 +11,7 @@ import { schemaUserReadPublic } from "@lib/validations/user"; * /users: * get: * summary: Find all users (admin only), returns your user if regular user. - * security: - * - ApiKeyAuth: [] + * tags: * - users * responses: diff --git a/templates/endpoints/[id]/delete.ts b/templates/endpoints/[id]/delete.ts index 9c5c6f9f7c..908e74b7d5 100644 --- a/templates/endpoints/[id]/delete.ts +++ b/templates/endpoints/[id]/delete.ts @@ -21,14 +21,12 @@ import { * type: integer * required: true * description: Numeric ID of the resource to delete - * security: - * - ApiKeyAuth: [] + * tags: * - resources * responses: * 201: * description: OK, resource removed successfuly - * model: Resource * 400: * description: Bad request. Resource id is invalid. * 401: diff --git a/templates/endpoints/[id]/edit.ts b/templates/endpoints/[id]/edit.ts index 8ddad4601d..43cb6c8f8e 100644 --- a/templates/endpoints/[id]/edit.ts +++ b/templates/endpoints/[id]/edit.ts @@ -22,14 +22,12 @@ import { * type: integer * required: true * description: Numeric ID of the resource to edit - * security: - * - ApiKeyAuth: [] + * tags: * - resources * responses: * 201: * description: OK, resource edited successfuly - * model: Resource * 400: * description: Bad request. Resource body is invalid. * 401: diff --git a/templates/endpoints/[id]/index.ts b/templates/endpoints/[id]/index.ts index 9f4c64f11d..c3297459ac 100644 --- a/templates/endpoints/[id]/index.ts +++ b/templates/endpoints/[id]/index.ts @@ -22,8 +22,7 @@ import { * type: integer * required: true * description: Numeric ID of the resource to get - * security: - * - ApiKeyAuth: [] + * tags: * - resources * responses: diff --git a/templates/endpoints/get_all.ts b/templates/endpoints/get_all.ts index ee66e7c773..e925133346 100644 --- a/templates/endpoints/get_all.ts +++ b/templates/endpoints/get_all.ts @@ -11,8 +11,7 @@ import { schemaResourcePublic } from "@lib/validations/resource"; * /v1/resources: * get: * summary: Find all resources - * security: - * - ApiKeyAuth: [] + * tags: * - resources * responses: diff --git a/templates/endpoints/get_all_and_post.ts b/templates/endpoints/get_all_and_post.ts index 2ce4b8dfe9..d20075e52c 100644 --- a/templates/endpoints/get_all_and_post.ts +++ b/templates/endpoints/get_all_and_post.ts @@ -11,8 +11,7 @@ import { schemaPaymentBodyParams, schemaPaymentPublic } from "@lib/validations/p * /v1/payments: * get: * summary: Find all payments - * security: - * - ApiKeyAuth: [] + * tags: * - payments * responses: @@ -24,14 +23,12 @@ import { schemaPaymentBodyParams, schemaPaymentPublic } from "@lib/validations/p * description: No payments were found * post: * summary: Creates a new payment - * security: - * - ApiKeyAuth: [] + * tags: * - payments * responses: * 201: * description: OK, payment created - * model: Payment * 400: * description: Bad request. Payment body is invalid. * 401: diff --git a/templates/endpoints/post.ts b/templates/endpoints/post.ts index 999bce39c1..3f5b7403d7 100644 --- a/templates/endpoints/post.ts +++ b/templates/endpoints/post.ts @@ -18,14 +18,12 @@ import { schemaResourceBodyParams, schemaResourcePublic, withValidResource } fro * application/json: * schema: * $ref: '#/components/schemas/Resource' - * security: - * - ApiKeyAuth: [] + * tags: * - resources * responses: * 201: * description: OK, resource created - * model: Resource * 400: * description: Bad request. Resource body is invalid. * 401: From d6c34a8e51d6d9a380affc7ab5886ddb97b94c38 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 29 Apr 2022 01:54:21 +0200 Subject: [PATCH 163/658] fix: remove empty lines --- pages/api/attendees/[id].ts | 3 --- pages/api/attendees/index.ts | 2 -- pages/api/availabilities/[id].ts | 3 --- pages/api/availabilities/index.ts | 2 -- pages/api/booking-references/[id].ts | 3 --- pages/api/booking-references/index.ts | 3 --- pages/api/bookings/[id].ts | 4 ---- pages/api/bookings/index.ts | 2 -- pages/api/daily-event-references/[id].ts | 4 ---- pages/api/daily-event-references/index.ts | 2 -- pages/api/destination-calendars/[id].ts | 3 --- pages/api/destination-calendars/index.ts | 2 -- pages/api/event-type-custom-inputs/[id].ts | 4 ---- pages/api/event-type-custom-inputs/index.ts | 2 -- pages/api/event-types/index.ts | 2 -- pages/api/memberships/[id].ts | 4 ---- pages/api/memberships/index.ts | 2 -- pages/api/payments/[id].ts | 1 - pages/api/payments/index.ts | 1 - pages/api/schedules/[id].ts | 5 ----- pages/api/selected-calendars/[id].ts | 2 -- pages/api/selected-calendars/index.ts | 2 -- pages/api/teams/[id].ts | 5 ----- pages/api/teams/index.ts | 2 -- pages/api/users/[id].ts | 4 ---- pages/api/users/index.ts | 1 - 26 files changed, 70 deletions(-) diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index b27c2e40fb..3d6d16c9a1 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -23,7 +23,6 @@ import { * required: true * description: Numeric ID of the attendee to get * example: 3 - * tags: * - attendees * responses: @@ -65,7 +64,6 @@ import { * example: 3 * required: true * description: Numeric ID of the attendee to edit - * tags: * - attendees * responses: @@ -84,7 +82,6 @@ import { * type: integer * required: true * description: Numeric ID of the attendee to delete - * tags: * - attendees * responses: diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index a0514bb8df..262f7a0e0c 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -11,7 +11,6 @@ import { schemaAttendeeCreateBodyParams, schemaAttendeeReadPublic } from "@lib/v * /attendees: * get: * summary: Find all attendees - * tags: * - attendees * responses: @@ -23,7 +22,6 @@ import { schemaAttendeeCreateBodyParams, schemaAttendeeReadPublic } from "@lib/v * description: No attendees were found * post: * summary: Creates a new attendee - * requestBody: * description: Create a new attendee related to one of your bookings * required: true diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index ad6826a6d3..21348a990c 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -25,7 +25,6 @@ import { * type: integer * required: true * description: Numeric ID of the availability to get - * tags: * - availabilities * externalDocs: @@ -46,7 +45,6 @@ import { * type: integer * required: true * description: Numeric ID of the availability to edit - * tags: * - availabilities * externalDocs: @@ -67,7 +65,6 @@ import { * type: integer * required: true * description: Numeric ID of the availability to delete - * tags: * - availabilities * externalDocs: diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index 7d8f18eac3..7ef5e65b8b 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -14,7 +14,6 @@ import { * /availabilities: * get: * summary: Find all availabilities - * tags: * - availabilities * externalDocs: @@ -28,7 +27,6 @@ import { * description: No availabilities were found * post: * summary: Creates a new availability - * tags: * - availabilities * externalDocs: diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index 4014707eb4..cba249df5a 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -26,7 +26,6 @@ import { * type: integer * required: true * description: Numeric ID of the booking reference to get - * tags: * - booking-references * responses: @@ -38,7 +37,6 @@ import { * description: BookingReference was not found * patch: * summary: Edit an existing booking reference - * parameters: * - in: path * name: id @@ -46,7 +44,6 @@ import { * type: integer * required: true * description: Numeric ID of the booking reference to edit - * tags: * - booking-references * responses: diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index c214b305db..7bd47a56f5 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -14,7 +14,6 @@ import { * /booking-references: * get: * summary: Find all booking references - * tags: * - booking-references * responses: @@ -26,13 +25,11 @@ import { * description: No booking references were found * post: * summary: Creates a new booking reference - * tags: * - booking-references * responses: * 201: * description: OK, booking reference created - * 400: * description: Bad request. BookingReference body is invalid. * 401: diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index 9c1b647b20..ddfa7a34ce 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -22,7 +22,6 @@ import { * type: integer * required: true * description: Numeric ID of the booking to get - * tags: * - bookings * responses: @@ -34,7 +33,6 @@ import { * description: Booking was not found * patch: * summary: Edit an existing booking - * parameters: * - in: path * name: id @@ -42,7 +40,6 @@ import { * type: integer * required: true * description: Numeric ID of the booking to edit - * tags: * - bookings * responses: @@ -61,7 +58,6 @@ import { * type: integer * required: true * description: Numeric ID of the booking to delete - * tags: * - bookings * responses: diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 311a79b4dd..444fda9488 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -11,7 +11,6 @@ import { schemaBookingCreateBodyParams, schemaBookingReadPublic } from "@lib/val * /bookings: * get: * summary: Find all bookings - * tags: * - bookings * responses: @@ -23,7 +22,6 @@ import { schemaBookingCreateBodyParams, schemaBookingReadPublic } from "@lib/val * description: No bookings were found * post: * summary: Creates a new booking - * tags: * - bookings * responses: diff --git a/pages/api/daily-event-references/[id].ts b/pages/api/daily-event-references/[id].ts index a59beeebbf..7f1b026e5c 100644 --- a/pages/api/daily-event-references/[id].ts +++ b/pages/api/daily-event-references/[id].ts @@ -25,7 +25,6 @@ import { * type: integer * required: true * description: Numeric ID of the daily event reference to get - * tags: * - daily-event-references * responses: @@ -37,7 +36,6 @@ import { * description: DailyEventReference was not found * patch: * summary: Edit an existing daily event reference - * parameters: * - in: path * name: id @@ -45,7 +43,6 @@ import { * type: integer * required: true * description: Numeric ID of the daily event reference to edit - * tags: * - daily-event-references * responses: @@ -64,7 +61,6 @@ import { * type: integer * required: true * description: Numeric ID of the daily event reference to delete - * tags: * - daily-event-references * responses: diff --git a/pages/api/daily-event-references/index.ts b/pages/api/daily-event-references/index.ts index 290469f307..c129eef677 100644 --- a/pages/api/daily-event-references/index.ts +++ b/pages/api/daily-event-references/index.ts @@ -14,7 +14,6 @@ import { * /daily-event-references: * get: * summary: Find all daily event reference - * tags: * - daily-event-references * responses: @@ -26,7 +25,6 @@ import { * description: No daily event references were found * post: * summary: Creates a new daily event reference - * tags: * - daily-event-references * responses: diff --git a/pages/api/destination-calendars/[id].ts b/pages/api/destination-calendars/[id].ts index ecfe646b09..679dcd5d29 100644 --- a/pages/api/destination-calendars/[id].ts +++ b/pages/api/destination-calendars/[id].ts @@ -25,7 +25,6 @@ import { * type: integer * required: true * description: Numeric ID of the destination calendar to get - * tags: * - destination-calendars * responses: @@ -37,7 +36,6 @@ import { * description: DestinationCalendar was not found * patch: * summary: Edit an existing destination calendar - * parameters: * - in: path * name: id @@ -45,7 +43,6 @@ import { * type: integer * required: true * description: Numeric ID of the destination calendar to edit - * tags: * - destination-calendars * responses: diff --git a/pages/api/destination-calendars/index.ts b/pages/api/destination-calendars/index.ts index cf33e0fa58..81a3d36c97 100644 --- a/pages/api/destination-calendars/index.ts +++ b/pages/api/destination-calendars/index.ts @@ -14,7 +14,6 @@ import { * /destination-calendars: * get: * summary: Find all destination calendars - * tags: * - destination-calendars * responses: @@ -26,7 +25,6 @@ import { * description: No destination calendars were found * post: * summary: Creates a new destination calendar - * tags: * - destination-calendars * responses: diff --git a/pages/api/event-type-custom-inputs/[id].ts b/pages/api/event-type-custom-inputs/[id].ts index 6760e4b39c..0d84a2a6fb 100644 --- a/pages/api/event-type-custom-inputs/[id].ts +++ b/pages/api/event-type-custom-inputs/[id].ts @@ -25,7 +25,6 @@ import { * type: integer * required: true * description: Numeric ID of the eventTypeCustomInput to get - * tags: * - event-type-custom-inputs * responses: @@ -37,7 +36,6 @@ import { * description: EventType was not found * patch: * summary: Edit an existing eventTypeCustomInput - * parameters: * - in: path * name: id @@ -45,7 +43,6 @@ import { * type: integer * required: true * description: Numeric ID of the eventTypeCustomInput to edit - * tags: * - event-type-custom-inputs * responses: @@ -64,7 +61,6 @@ import { * type: integer * required: true * description: Numeric ID of the eventTypeCustomInput to delete - * tags: * - event-type-custom-inputs * responses: diff --git a/pages/api/event-type-custom-inputs/index.ts b/pages/api/event-type-custom-inputs/index.ts index e7cc037cd9..ac6c0f94cb 100644 --- a/pages/api/event-type-custom-inputs/index.ts +++ b/pages/api/event-type-custom-inputs/index.ts @@ -14,7 +14,6 @@ import { * /event-type-custom-inputs: * get: * summary: Find all eventTypeCustomInputs - * tags: * - event-type-custom-inputs * responses: @@ -26,7 +25,6 @@ import { * description: No eventTypeCustomInputs were found * post: * summary: Creates a new eventTypeCustomInput - * tags: * - event-type-custom-inputs * responses: diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index eb6c7d1290..4030e84186 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -11,7 +11,6 @@ import { schemaEventTypeBodyParams, schemaEventTypePublic } from "@lib/validatio * /event-types: * get: * summary: Find all event types - * tags: * - event-types * externalDocs: @@ -25,7 +24,6 @@ import { schemaEventTypeBodyParams, schemaEventTypePublic } from "@lib/validatio * description: No event types were found * post: * summary: Creates a new event type - * tags: * - event-types * externalDocs: diff --git a/pages/api/memberships/[id].ts b/pages/api/memberships/[id].ts index 3172428ec3..fa4c298be4 100644 --- a/pages/api/memberships/[id].ts +++ b/pages/api/memberships/[id].ts @@ -25,7 +25,6 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * type: integer * required: true * description: Numeric teamId of the membership to get - * tags: * - memberships * responses: @@ -37,7 +36,6 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * description: Membership was not found * patch: * summary: Edit an existing membership - * parameters: * - in: path * name: userId @@ -51,7 +49,6 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * type: integer * required: true * description: Numeric teamId of the membership to get - * tags: * - memberships * responses: @@ -76,7 +73,6 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * type: integer * required: true * description: Numeric teamId of the membership to get - * tags: * - memberships * responses: diff --git a/pages/api/memberships/index.ts b/pages/api/memberships/index.ts index 78072dd68d..137eaf48ac 100644 --- a/pages/api/memberships/index.ts +++ b/pages/api/memberships/index.ts @@ -11,7 +11,6 @@ import { schemaMembershipBodyParams, schemaMembershipPublic } from "@lib/validat * /memberships: * get: * summary: Find all memberships - * tags: * - memberships * responses: @@ -23,7 +22,6 @@ import { schemaMembershipBodyParams, schemaMembershipPublic } from "@lib/validat * description: No memberships were found * post: * summary: Creates a new membership - * tags: * - memberships * responses: diff --git a/pages/api/payments/[id].ts b/pages/api/payments/[id].ts index 9f0d8315dd..90882e760c 100644 --- a/pages/api/payments/[id].ts +++ b/pages/api/payments/[id].ts @@ -22,7 +22,6 @@ import { * type: integer * required: true * description: Numeric ID of the payment to get - * tags: * - payments * responses: diff --git a/pages/api/payments/index.ts b/pages/api/payments/index.ts index 5d16b911df..0c6eae0f85 100644 --- a/pages/api/payments/index.ts +++ b/pages/api/payments/index.ts @@ -11,7 +11,6 @@ import { schemaPaymentPublic } from "@lib/validations/payment"; * /payments: * get: * summary: Find all payments - * tags: * - payments * responses: diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index a2d9da0366..d6645597a6 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -22,7 +22,6 @@ import { * type: integer * required: true * description: Numeric ID of the schedule to get - * tags: * - schedules * responses: @@ -34,16 +33,13 @@ import { * description: Schedule was not found * patch: * summary: Edit an existing schedule - * parameters: - * - in: path * name: id * schema: * type: integer * required: true * description: Numeric ID of the schedule to edit - * tags: * - schedules * responses: @@ -62,7 +58,6 @@ import { * type: integer * required: true * description: Numeric ID of the schedule to delete - * tags: * - schedules * responses: diff --git a/pages/api/selected-calendars/[id].ts b/pages/api/selected-calendars/[id].ts index b3df3b88b2..a8e1e7ab15 100644 --- a/pages/api/selected-calendars/[id].ts +++ b/pages/api/selected-calendars/[id].ts @@ -34,7 +34,6 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * type: string * required: true * description: integration of the selected calendar to get - * tags: * - selected-calendars * responses: @@ -65,7 +64,6 @@ import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/ * type: string * required: true * description: integration of the selected calendar to get - * tags: * - selected-calendars * responses: diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index 055ae51346..c6e1b122d9 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -14,7 +14,6 @@ import { * /selected-calendars: * get: * summary: Find all selected calendars - * tags: * - selected-calendars * responses: @@ -26,7 +25,6 @@ import { * description: No selected calendars were found * post: * summary: Creates a new selected calendar - * tags: * - selected-calendars * responses: diff --git a/pages/api/teams/[id].ts b/pages/api/teams/[id].ts index 9fb11b5e50..0368a69f5c 100644 --- a/pages/api/teams/[id].ts +++ b/pages/api/teams/[id].ts @@ -22,7 +22,6 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * type: integer * required: true * description: Numeric ID of the team to get - * tags: * - teams * responses: @@ -32,7 +31,6 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * description: Authorization information is missing or invalid. * 404: * description: Team was not found - * patch: * summary: Edit an existing team * parameters: @@ -42,7 +40,6 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * type: integer * required: true * description: Numeric ID of the team to edit - * tags: * - teams * responses: @@ -52,7 +49,6 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * description: Bad request. Team body is invalid. * 401: * description: Authorization information is missing or invalid. - * delete: * summary: Remove an existing team * parameters: @@ -62,7 +58,6 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * type: integer * required: true * description: Numeric ID of the team to delete - * tags: * - teams * responses: diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index 11d646f70f..e5ae852dd8 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -12,7 +12,6 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * /teams: * get: * summary: Find all teams - * tags: * - teams * responses: @@ -24,7 +23,6 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * description: No teams were found * post: * summary: Creates a new team - * tags: * - teams * responses: diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index f8aed85d7d..4cea26e8e3 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -22,7 +22,6 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations * type: integer * required: true * description: Numeric ID of the user to get - * tags: * - users * responses: @@ -34,7 +33,6 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations * description: User was not found * patch: * summary: Edit an existing user - * parameters: * - in: path * name: id @@ -42,7 +40,6 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations * type: integer * required: true * description: Numeric ID of the user to edit - * tags: * - users * responses: @@ -61,7 +58,6 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations * type: integer * required: true * description: Numeric ID of the user to delete - * tags: * - users * responses: diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index c5dfd71b68..4ef860e18f 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -11,7 +11,6 @@ import { schemaUserReadPublic } from "@lib/validations/user"; * /users: * get: * summary: Find all users (admin only), returns your user if regular user. - * tags: * - users * responses: From e13ea234b84578a716bab7702060028b2386bb9d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 29 Apr 2022 02:30:59 +0200 Subject: [PATCH 164/658] fix: improve docs in attendees availabilities and booking references --- pages/api/attendees/[id].ts | 180 ++++++++++++++------------ pages/api/attendees/index.ts | 114 ++++++++-------- pages/api/availabilities/[id].ts | 146 +++++++++++---------- pages/api/availabilities/index.ts | 70 +++++----- pages/api/booking-references/[id].ts | 132 +++++++++---------- pages/api/booking-references/index.ts | 60 ++++----- 6 files changed, 360 insertions(+), 342 deletions(-) diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index 3d6d16c9a1..01ae4f5449 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -10,90 +10,10 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -/** - * @swagger - * /attendees/{id}: - * get: - * summary: Find an attendee by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the attendee to get - * example: 3 - * tags: - * - attendees - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Attendee was not found - * patch: - * summary: Edit an existing attendee - * requestBody: - * description: Edit an existing attendee related to one of your bookings - * required: true - * content: - * application/json: - * schema: - * type: object - * required: - * - bookingId - * - name - * - email - * - timeZone - * properties: - * email: - * type: string - * example: email@example.com - * name: - * type: string - * example: John Doe - * timeZone: - * type: string - * example: Europe/London - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * example: 3 - * required: true - * description: Numeric ID of the attendee to edit - * tags: - * - attendees - * responses: - * 201: - * description: OK, attendee edited successfuly - * 400: - * description: Bad request. Attendee body is invalid. - * 401: - * description: Authorization information is missing or invalid. - * delete: - * summary: Remove an existing attendee - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the attendee to delete - * tags: - * - attendees - * responses: - * 201: - * description: OK, attendee removed successfuly - * 400: - * description: Bad request. Attendee id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function attendeeById(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body, userId } = req; +export async function attendeeById( + { method, query, body, userId }: NextApiRequest, + res: NextApiResponse +) { const safeQuery = schemaQueryIdParseInt.safeParse(query); if (!safeQuery.success) { res.status(400).json({ error: safeQuery.error }); @@ -109,6 +29,29 @@ export async function attendeeById(req: NextApiRequest, res: NextApiResponse ) { - const { method, userId } = req; - // Here we make sure to only return attendee's of the user's own bookings. const userBookings = await prisma.booking.findMany({ where: { userId, @@ -73,6 +20,21 @@ async function createOrlistAllAttendees( }); const attendees = userBookings.map((booking) => booking.attendees).flat(); if (method === "GET") { + /** + * @swagger + * /attendees: + * get: + * summary: Find all attendees + * tags: + * - attendees + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No attendees were found + */ if (attendees) res.status(200).json({ attendees }); else (error: Error) => @@ -81,13 +43,51 @@ async function createOrlistAllAttendees( error, }); } else if (method === "POST") { - const safePost = schemaAttendeeCreateBodyParams.safeParse(req.body); + /** + * @swagger + * /attendees: + * post: + * summary: Creates a new attendee + * requestBody: + * description: Create a new attendee related to one of your bookings + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - bookingId + * - name + * - email + * - timeZone + * properties: + * bookingId: + * type: number + * example: 1 + * email: + * type: string + * example: email@example.com + * name: + * type: string + * example: John Doe + * timeZone: + * type: string + * example: Europe/London + * tags: + * - attendees + * responses: + * 201: + * description: OK, attendee created + * 400: + * description: Bad request. Attendee body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safePost = schemaAttendeeCreateBodyParams.safeParse(body); if (!safePost.success) { - console.log(safePost.error); res.status(400).json({ error: safePost.error }); throw new Error("Invalid request body", safePost.error); } - const userId = req.userId; const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index 21348a990c..de131eb0ff 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -13,80 +13,41 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -/** - * @swagger - * /availabilities/{id}: - * get: - * summary: Find an availability by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the availability to get - * tags: - * - availabilities - * externalDocs: - * url: https://docs.cal.com/availability - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Availability was not found - * patch: - * summary: Edit an existing availability - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the availability to edit - * tags: - * - availabilities - * externalDocs: - * url: https://docs.cal.com/availability - * responses: - * 201: - * description: OK, availability edited successfuly - * 400: - * description: Bad request. Availability body is invalid. - * 401: - * description: Authorization information is missing or invalid. - * delete: - * summary: Remove an existing availability - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the availability to delete - * tags: - * - availabilities - * externalDocs: - * url: https://docs.cal.com/availability - * responses: - * 201: - * description: OK, availability removed successfuly - * 400: - * description: Bad request. Availability id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function availabilityById(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body } = req; +export async function availabilityById( + { method, query, body, userId }: NextApiRequest, + res: NextApiResponse +) { const safeQuery = schemaQueryIdParseInt.safeParse(query); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = req.userId; const data = await prisma.availability.findMany({ where: { userId } }); const availabiltiesIds = data.map((availability) => availability.id); if (!availabiltiesIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { + /** + * @swagger + * /availabilities/{id}: + * get: + * summary: Find an availability by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the availability to get + * tags: + * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Availability was not found + */ case "GET": await prisma.availability .findUnique({ where: { id: safeQuery.data.id } }) @@ -96,7 +57,30 @@ export async function availabilityById(req: NextApiRequest, res: NextApiResponse res.status(404).json({ message: `Availability with id: ${safeQuery.data.id} not found`, error }) ); break; - + /** + * @swagger + * /availabilities/{id}: + * patch: + * summary: Edit an existing availability + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the availability to edit + * tags: + * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability + * responses: + * 201: + * description: OK, availability edited successfuly + * 400: + * description: Bad request. Availability body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ case "PATCH": const safeBody = schemaAvailabilityEditBodyParams.safeParse(body); if (!safeBody.success) throw new Error("Invalid request body"); @@ -115,14 +99,36 @@ export async function availabilityById(req: NextApiRequest, res: NextApiResponse .then((data) => schemaAvailabilityReadPublic.parse(data)) .then((availability) => res.status(200).json({ availability })) .catch((error: Error) => { - console.log(error); res.status(404).json({ message: `Availability with id: ${safeQuery.data.id} not found`, error, }); }); break; - + /** + * @swagger + * /availabilities/{id}: + * delete: + * summary: Remove an existing availability + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the availability to delete + * tags: + * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability + * responses: + * 201: + * description: OK, availability removed successfuly + * 400: + * description: Bad request. Availability id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ case "DELETE": await prisma.availability .delete({ where: { id: safeQuery.data.id } }) diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index 7ef5e65b8b..25b0866071 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -9,44 +9,28 @@ import { schemaAvailabilityReadPublic, } from "@lib/validations/availability"; -/** - * @swagger - * /availabilities: - * get: - * summary: Find all availabilities - * tags: - * - availabilities - * externalDocs: - * url: https://docs.cal.com/availability - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No availabilities were found - * post: - * summary: Creates a new availability - * tags: - * - availabilities - * externalDocs: - * url: https://docs.cal.com/availability - * responses: - * 201: - * description: OK, availability created - * 400: - * description: Bad request. Availability body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ async function createOrlistAllAvailabilities( - req: NextApiRequest, + { method, userId }: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; - if (method === "GET") { + /** + * @swagger + * /availabilities: + * get: + * summary: Find all availabilities + * tags: + * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No availabilities were found + */ const data = await prisma.availability.findMany({ where: { userId } }); const availabilities = data.map((availability) => schemaAvailabilityReadPublic.parse(availability)); if (availabilities) res.status(200).json({ availabilities }); @@ -57,11 +41,27 @@ async function createOrlistAllAvailabilities( error, }); } else if (method === "POST") { + /** + * @swagger + * /availabilities: + * post: + * summary: Creates a new availability + * tags: + * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability + * responses: + * 201: + * description: OK, availability created + * 400: + * description: Bad request. Availability body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ const safe = schemaAvailabilityCreateBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.availability.create({ data: { ...safe.data, userId } }); - console.log(data); const availability = schemaAvailabilityReadPublic.parse(data); if (availability) res.status(201).json({ availability, message: "Availability created successfully" }); diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index cba249df5a..bbc2ea6fa2 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -14,73 +14,12 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -/** - * @swagger - * /booking-references/{id}: - * get: - * summary: Find a booking reference by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the booking reference to get - * tags: - * - booking-references - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: BookingReference was not found - * patch: - * summary: Edit an existing booking reference - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the booking reference to edit - * tags: - * - booking-references - * responses: - * 201: - * description: OK, bookingReference edited successfuly - * 400: - * description: Bad request. BookingReference body is invalid. - * 401: - * description: Authorization information is missing or invalid. - * delete: - * summary: Remove an existing booking reference - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the booking reference to delete - - * tags: - * - booking-references - * responses: - * 201: - * description: OK, bookingReference removed successfuly - * 400: - * description: Bad request. BookingReference id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ export async function bookingReferenceById( - req: NextApiRequest, + { method, query, body, userId }: NextApiRequest, res: NextApiResponse ) { - const { method, query, body } = req; const safeQuery = schemaQueryIdParseInt.safeParse(query); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = req.userId; const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, @@ -91,6 +30,28 @@ export async function bookingReferenceById( if (!bookingReference) throw new Error("BookingReference not found"); if (userBookingIds.includes(bookingReference.bookingId)) { switch (method) { + /** + * @swagger + * /booking-references/{id}: + * get: + * summary: Find a booking reference by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the booking reference to get + * tags: + * - booking-references + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: BookingReference was not found + */ case "GET": await prisma.bookingReference .findUnique({ where: { id: safeQuery.data.id } }) @@ -103,10 +64,30 @@ export async function bookingReferenceById( }) ); break; - + /** + * @swagger + * /booking-references/{id}: + * patch: + * summary: Edit an existing booking reference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the booking reference to edit + * tags: + * - booking-references + * responses: + * 201: + * description: OK, bookingReference edited successfuly + * 400: + * description: Bad request. BookingReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ case "PATCH": const safeBody = schemaBookingEditBodyParams.safeParse(body); - if (!safeBody.success) { throw new Error("Invalid request body"); } @@ -121,7 +102,28 @@ export async function bookingReferenceById( }) ); break; - + /** + * @swagger + * /booking-references/{id}: + * delete: + * summary: Remove an existing booking reference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the booking reference to delete + * tags: + * - booking-references + * responses: + * 201: + * description: OK, bookingReference removed successfuly + * 400: + * description: Bad request. BookingReference id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ case "DELETE": await prisma.bookingReference .delete({ diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index 7bd47a56f5..a4ced04215 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -9,38 +9,10 @@ import { schemaBookingReferenceReadPublic, } from "@lib/validations/booking-reference"; -/** - * @swagger - * /booking-references: - * get: - * summary: Find all booking references - * tags: - * - booking-references - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No booking references were found - * post: - * summary: Creates a new booking reference - * tags: - * - booking-references - * responses: - * 201: - * description: OK, booking reference created - * 400: - * description: Bad request. BookingReference body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ async function createOrlistAllBookingReferences( - req: NextApiRequest, + { method, userId }: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, @@ -48,6 +20,21 @@ async function createOrlistAllBookingReferences( if (!userWithBookings) throw new Error("User not found"); const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); if (method === "GET") { + /** + * @swagger + * /booking-references: + * get: + * summary: Find all booking references + * tags: + * - booking-references + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No booking references were found + */ const data = await prisma.bookingReference.findMany({ where: { id: { in: userBookingIds } } }); const booking_references = data.map((bookingReference) => schemaBookingReferenceReadPublic.parse(bookingReference) @@ -60,6 +47,21 @@ async function createOrlistAllBookingReferences( error, }); } else if (method === "POST") { + /** + * @swagger + * /booking-references: + * post: + * summary: Creates a new booking reference + * tags: + * - booking-references + * responses: + * 201: + * description: OK, booking reference created + * 400: + * description: Bad request. BookingReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ const safe = schemaBookingCreateBodyParams.safeParse(req.body); if (!safe.success) { throw new Error("Invalid request body"); From d06a9488e4a339fba17d56f3639727bd2d967dcc Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 29 Apr 2022 02:49:38 +0200 Subject: [PATCH 165/658] fix: rename endpoints to be only 2 words max --- README.md | 4 +- pages/api/attendees/[id].ts | 24 ++-- pages/api/bookings/[id].ts | 127 +++++++++--------- pages/api/bookings/index.ts | 42 +++--- .../[id].ts | 8 +- .../index.ts | 6 +- .../[id].ts | 124 +++++++++-------- .../index.ts | 6 +- 8 files changed, 184 insertions(+), 157 deletions(-) rename pages/api/{event-type-custom-inputs => custom-inputs}/[id].ts (97%) rename pages/api/{event-type-custom-inputs => custom-inputs}/index.ts (97%) rename pages/api/{daily-event-references => event-references}/[id].ts (61%) rename pages/api/{daily-event-references => event-references}/index.ts (96%) diff --git a/README.md b/README.md index 17082202cd..a9904ac3ff 100644 --- a/README.md +++ b/README.md @@ -127,9 +127,9 @@ We aim to provide a fully tested API for our peace of mind, this is accomplished | attendees | ✅ | ✅ | ✅ | ✅ | ✅ | | availabilities | ✅ | ✅ | ✅ | ✅ | ✅ | | booking-references | ✅ | ✅ | ✅ | ✅ | ✅ | -| daily-event-references | ✅ | ✅ | ✅ | ✅ | ✅ | +| event-references | ✅ | ✅ | ✅ | ✅ | ✅ | | destination-calendars | ✅ | ✅ | ✅ | ✅ | ✅ | -| event-type-custom-inputs | ✅ | ✅ | ✅ | ✅ | ✅ | +| custom-inputs | ✅ | ✅ | ✅ | ✅ | ✅ | | event-types | ✅ | ✅ | ✅ | ✅ | ✅ | | memberships | ✅ | ✅ | ✅ | ✅ | ✅ | | payments | ✅ | ✅ | ❌ | ❌ | ❌ | diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index 01ae4f5449..b0bf73796f 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -19,14 +19,22 @@ export async function attendeeById( res.status(400).json({ error: safeQuery.error }); throw new Error("Invalid request query", safeQuery.error); } - const userBookings = await prisma.booking.findMany({ - where: { userId }, - include: { attendees: true }, - }); - const attendees = userBookings.map((booking) => booking.attendees).flat(); - const attendeeIds = attendees.map((attendee) => attendee.id); - // Here we make sure to only return attendee's of the user's own bookings. - if (!attendeeIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); + const userBookingsAttendeeIds = await prisma.booking + // Find all user bookings, including attendees + .findMany({ + where: { userId }, + include: { attendees: true }, + }) + .then( + // Flatten and merge all the attendees in one array + (bookings) => + bookings + .map((bookings) => bookings.attendees) // Get the attendees IDs from user bookings + .flat() // Needed to flatten the array of arrays of all bookings attendees + .map((attendee) => attendee.id) // We only need the attendee IDs + ); + // @note: Here we make sure to only return attendee's of the user's own bookings. + if (!userBookingsAttendeeIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { /** diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index ddfa7a34ce..0974bd55b1 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -10,64 +10,6 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -/** - * @swagger - * /bookings/{id}: - * get: - * summary: Find a booking by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the booking to get - * tags: - * - bookings - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Booking was not found - * patch: - * summary: Edit an existing booking - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the booking to edit - * tags: - * - bookings - * responses: - * 201: - * description: OK, booking edited successfuly - * 400: - * description: Bad request. Booking body is invalid. - * 401: - * description: Authorization information is missing or invalid. - * delete: - * summary: Remove an existing booking - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the booking to delete - * tags: - * - bookings - * responses: - * 201: - * description: OK, booking removed successfuly - * 400: - * description: Bad request. Booking id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ export async function bookingById(req: NextApiRequest, res: NextApiResponse) { const { method, query, body } = req; const safeQuery = schemaQueryIdParseInt.safeParse(query); @@ -82,6 +24,28 @@ export async function bookingById(req: NextApiRequest, res: NextApiResponse +) { + const { method } = req; + const userId = req.userId; + + if (method === "GET") { + /** * @swagger * /bookings: @@ -20,6 +29,21 @@ import { schemaBookingCreateBodyParams, schemaBookingReadPublic } from "@lib/val * description: Authorization information is missing or invalid. * 404: * description: No bookings were found + */ + const data = await prisma.booking.findMany({ where: { userId } }); + const bookings = data.map((booking) => schemaBookingReadPublic.parse(booking)); + if (bookings) res.status(200).json({ bookings }); + else + (error: Error) => + res.status(404).json({ + message: "No Bookings were found", + error, + }); + } else if (method === "POST") { + +/** + * @swagger + * /bookings: * post: * summary: Creates a new booking * tags: @@ -32,24 +56,6 @@ import { schemaBookingCreateBodyParams, schemaBookingReadPublic } from "@lib/val * 401: * description: Authorization information is missing or invalid. */ -async function createOrlistAllBookings( - req: NextApiRequest, - res: NextApiResponse -) { - const { method } = req; - const userId = req.userId; - - if (method === "GET") { - const data = await prisma.booking.findMany({ where: { userId } }); - const bookings = data.map((booking) => schemaBookingReadPublic.parse(booking)); - if (bookings) res.status(200).json({ bookings }); - else - (error: Error) => - res.status(404).json({ - message: "No Bookings were found", - error, - }); - } else if (method === "POST") { const safe = schemaBookingCreateBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body"); diff --git a/pages/api/event-type-custom-inputs/[id].ts b/pages/api/custom-inputs/[id].ts similarity index 97% rename from pages/api/event-type-custom-inputs/[id].ts rename to pages/api/custom-inputs/[id].ts index 0d84a2a6fb..2860d9a525 100644 --- a/pages/api/event-type-custom-inputs/[id].ts +++ b/pages/api/custom-inputs/[id].ts @@ -15,7 +15,7 @@ import { /** * @swagger - * /event-type-custom-inputs/{id}: + * /custom-inputs/{id}: * get: * summary: Find a eventTypeCustomInput by ID * parameters: @@ -26,7 +26,7 @@ import { * required: true * description: Numeric ID of the eventTypeCustomInput to get * tags: - * - event-type-custom-inputs + * - custom-inputs * responses: * 200: * description: OK @@ -44,7 +44,7 @@ import { * required: true * description: Numeric ID of the eventTypeCustomInput to edit * tags: - * - event-type-custom-inputs + * - custom-inputs * responses: * 201: * description: OK, eventTypeCustomInput edited successfuly @@ -62,7 +62,7 @@ import { * required: true * description: Numeric ID of the eventTypeCustomInput to delete * tags: - * - event-type-custom-inputs + * - custom-inputs * responses: * 201: * description: OK, eventTypeCustomInput removed successfuly diff --git a/pages/api/event-type-custom-inputs/index.ts b/pages/api/custom-inputs/index.ts similarity index 97% rename from pages/api/event-type-custom-inputs/index.ts rename to pages/api/custom-inputs/index.ts index ac6c0f94cb..ee1232d83c 100644 --- a/pages/api/event-type-custom-inputs/index.ts +++ b/pages/api/custom-inputs/index.ts @@ -11,11 +11,11 @@ import { /** * @swagger - * /event-type-custom-inputs: + * /custom-inputs: * get: * summary: Find all eventTypeCustomInputs * tags: - * - event-type-custom-inputs + * - custom-inputs * responses: * 200: * description: OK @@ -26,7 +26,7 @@ import { * post: * summary: Creates a new eventTypeCustomInput * tags: - * - event-type-custom-inputs + * - custom-inputs * responses: * 201: * description: OK, eventTypeCustomInput created diff --git a/pages/api/daily-event-references/[id].ts b/pages/api/event-references/[id].ts similarity index 61% rename from pages/api/daily-event-references/[id].ts rename to pages/api/event-references/[id].ts index 7f1b026e5c..d0a31fcf11 100644 --- a/pages/api/daily-event-references/[id].ts +++ b/pages/api/event-references/[id].ts @@ -13,64 +13,6 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -/** - * @swagger - * /daily-event-references/{id}: - * get: - * summary: Find a daily event reference by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the daily event reference to get - * tags: - * - daily-event-references - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: DailyEventReference was not found - * patch: - * summary: Edit an existing daily event reference - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the daily event reference to edit - * tags: - * - daily-event-references - * responses: - * 201: - * description: OK, dailyEventReference edited successfuly - * 400: - * description: Bad request. DailyEventReference body is invalid. - * 401: - * description: Authorization information is missing or invalid. - * delete: - * summary: Remove an existing daily event reference - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the daily event reference to delete - * tags: - * - daily-event-references - * responses: - * 201: - * description: OK, dailyEventReference removed successfuly - * 400: - * description: Bad request. DailyEventReference id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ export async function dailyEventReferenceById( req: NextApiRequest, res: NextApiResponse @@ -92,6 +34,28 @@ export async function dailyEventReferenceById( res.status(401).json({ message: "Unauthorized" }); else { switch (method) { + /** + * @swagger + * /event-references/{id}: + * get: + * summary: Find a event reference by ID + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the event reference to get + * tags: + * - event-references + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: EventReference was not found + */ case "GET": await prisma.dailyEventReference .findUnique({ where: { id: safeQuery.data.id } }) @@ -105,6 +69,28 @@ export async function dailyEventReferenceById( ); break; + /** + * @swagger + * /event-references/{id}: + * patch: + * summary: Edit an existing event reference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the event reference to edit + * tags: + * - event-references + * responses: + * 201: + * description: OK, EventReference edited successfuly + * 400: + * description: Bad request. EventReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ case "PATCH": if (!safeBody.success) { throw new Error("Invalid request body"); @@ -121,6 +107,28 @@ export async function dailyEventReferenceById( ); break; + /** + * @swagger + * /event-references/{id}: + * delete: + * summary: Remove an existing event reference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the event reference to delete + * tags: + * - event-references + * responses: + * 201: + * description: OK, EventReference removed successfuly + * 400: + * description: Bad request. EventReference id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ case "DELETE": await prisma.dailyEventReference .delete({ diff --git a/pages/api/daily-event-references/index.ts b/pages/api/event-references/index.ts similarity index 96% rename from pages/api/daily-event-references/index.ts rename to pages/api/event-references/index.ts index c129eef677..1168ccbda6 100644 --- a/pages/api/daily-event-references/index.ts +++ b/pages/api/event-references/index.ts @@ -11,11 +11,11 @@ import { /** * @swagger - * /daily-event-references: + * /event-references: * get: * summary: Find all daily event reference * tags: - * - daily-event-references + * - event-references * responses: * 200: * description: OK @@ -26,7 +26,7 @@ import { * post: * summary: Creates a new daily event reference * tags: - * - daily-event-references + * - event-references * responses: * 201: * description: OK, daily event reference created From 9bb0f82075998477a8872b4ad021d208ef4e8574 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 29 Apr 2022 17:29:57 +0200 Subject: [PATCH 166/658] fix: improve comments, no anys --- pages/api/attendees/[id].ts | 2 +- pages/api/attendees/index.ts | 2 +- pages/api/availabilities/[id].ts | 2 +- pages/api/booking-references/[id].ts | 4 +- pages/api/booking-references/index.ts | 10 +- pages/api/bookings/[id].ts | 11 +- pages/api/bookings/index.ts | 67 ++++---- pages/api/custom-inputs/[id].ts | 9 +- pages/api/custom-inputs/index.ts | 65 ++++---- pages/api/destination-calendars/[id].ts | 167 +++++++++++-------- pages/api/destination-calendars/index.ts | 63 ++++---- pages/api/event-references/[id].ts | 8 +- pages/api/event-references/index.ts | 62 +++---- pages/api/event-types/[id].ts | 159 +++++++++--------- pages/api/event-types/index.ts | 71 ++++---- pages/api/memberships/[id].ts | 169 ++++++++++--------- pages/api/memberships/index.ts | 62 +++---- pages/api/payments/[id].ts | 10 +- pages/api/schedules/[id].ts | 124 +++++++------- pages/api/schedules/index.ts | 58 +++---- pages/api/selected-calendars/[id].ts | 198 ++++++++++++----------- pages/api/selected-calendars/index.ts | 72 +++++---- pages/api/teams/[id].ts | 2 +- pages/api/users/[id].ts | 2 +- templates/endpoints/[id]/index.ts | 2 +- 25 files changed, 742 insertions(+), 659 deletions(-) diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index b0bf73796f..4e044790a4 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -41,7 +41,7 @@ export async function attendeeById( * @swagger * /attendees/{id}: * get: - * summary: Find an attendee by ID + * summary: Find an attendee * parameters: * - in: path * name: id diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index 4f57b8e9b7..18bbce51d7 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -95,7 +95,7 @@ async function createOrlistAllAttendees( if (!userWithBookings) { throw new Error("User not found"); } - const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); + const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); // Here we make sure to only return attendee's of the user's own bookings. if (!userBookingIds.includes(safePost.data.bookingId)) res.status(401).json({ message: "Unauthorized" }); else { diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index de131eb0ff..139e36e22f 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -28,7 +28,7 @@ export async function availabilityById( * @swagger * /availabilities/{id}: * get: - * summary: Find an availability by ID + * summary: Find an availability * parameters: * - in: path * name: id diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index bbc2ea6fa2..cb0358d901 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -25,7 +25,7 @@ export async function bookingReferenceById( include: { bookings: true }, }); if (!userWithBookings) throw new Error("User not found"); - const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); + const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); const bookingReference = await prisma.bookingReference.findUnique({ where: { id: safeQuery.data.id } }); if (!bookingReference) throw new Error("BookingReference not found"); if (userBookingIds.includes(bookingReference.bookingId)) { @@ -34,7 +34,7 @@ export async function bookingReferenceById( * @swagger * /booking-references/{id}: * get: - * summary: Find a booking reference by ID + * summary: Find a booking reference * parameters: * - in: path * name: id diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index a4ced04215..87cbe25cdc 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -10,7 +10,7 @@ import { } from "@lib/validations/booking-reference"; async function createOrlistAllBookingReferences( - { method, userId }: NextApiRequest, + { method, userId, body }: NextApiRequest, res: NextApiResponse ) { const userWithBookings = await prisma.user.findUnique({ @@ -18,7 +18,7 @@ async function createOrlistAllBookingReferences( include: { bookings: true }, }); if (!userWithBookings) throw new Error("User not found"); - const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); + const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); if (method === "GET") { /** * @swagger @@ -62,13 +62,11 @@ async function createOrlistAllBookingReferences( * 401: * description: Authorization information is missing or invalid. */ - const safe = schemaBookingCreateBodyParams.safeParse(req.body); + const safe = schemaBookingCreateBodyParams.safeParse(body); if (!safe.success) { throw new Error("Invalid request body"); } - // const booking_reference = schemaBookingReferencePublic.parse(data); - const userId = req.userId; const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, @@ -76,7 +74,7 @@ async function createOrlistAllBookingReferences( if (!userWithBookings) { throw new Error("User not found"); } - const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); + const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); if (!userBookingIds.includes(safe.data.bookingId)) res.status(401).json({ message: "Unauthorized" }); else { const booking_reference = await prisma.bookingReference.create({ diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index 0974bd55b1..21fdd9a937 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -10,17 +10,18 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -export async function bookingById(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body } = req; +export async function bookingById( + { method, query, body, userId }: NextApiRequest, + res: NextApiResponse +) { const safeQuery = schemaQueryIdParseInt.safeParse(query); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = req.userId; const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, }); if (!userWithBookings) throw new Error("User not found"); - const userBookingIds = userWithBookings.bookings.map((booking: any) => booking.id).flat(); + const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); if (!userBookingIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { @@ -28,7 +29,7 @@ export async function bookingById(req: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; - if (method === "GET") { - -/** - * @swagger - * /bookings: - * get: - * summary: Find all bookings - * tags: - * - bookings - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No bookings were found - */ + /** + * @swagger + * /bookings: + * get: + * summary: Find all bookings + * tags: + * - bookings + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No bookings were found + */ const data = await prisma.booking.findMany({ where: { userId } }); const bookings = data.map((booking) => schemaBookingReadPublic.parse(booking)); if (bookings) res.status(200).json({ bookings }); @@ -40,22 +36,21 @@ async function createOrlistAllBookings( error, }); } else if (method === "POST") { - -/** - * @swagger - * /bookings: - * post: - * summary: Creates a new booking - * tags: - * - bookings - * responses: - * 201: - * description: OK, booking created - * 400: - * description: Bad request. Booking body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ + /** + * @swagger + * /bookings: + * post: + * summary: Creates a new booking + * tags: + * - bookings + * responses: + * 201: + * description: OK, booking created + * 400: + * description: Bad request. Booking body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ const safe = schemaBookingCreateBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body"); diff --git a/pages/api/custom-inputs/[id].ts b/pages/api/custom-inputs/[id].ts index 2860d9a525..3339f31027 100644 --- a/pages/api/custom-inputs/[id].ts +++ b/pages/api/custom-inputs/[id].ts @@ -17,7 +17,7 @@ import { * @swagger * /custom-inputs/{id}: * get: - * summary: Find a eventTypeCustomInput by ID + * summary: Find a eventTypeCustomInput * parameters: * - in: path * name: id @@ -71,12 +71,13 @@ import { * 401: * description: Authorization information is missing or invalid. */ -async function eventTypeById(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body } = req; +async function eventTypeById( + { method, query, body, userId }: NextApiRequest, + res: NextApiResponse +) { const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaEventTypeCustomInputBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = req.userId; const data = await prisma.eventType.findMany({ where: { userId } }); const userEventTypes = data.map((eventType) => eventType.id); const userEventTypeCustomInputs = await prisma.eventTypeCustomInput.findMany({ diff --git a/pages/api/custom-inputs/index.ts b/pages/api/custom-inputs/index.ts index ee1232d83c..c7d5f9df90 100644 --- a/pages/api/custom-inputs/index.ts +++ b/pages/api/custom-inputs/index.ts @@ -9,42 +9,28 @@ import { schemaEventTypeCustomInputPublic, } from "@lib/validations/event-type-custom-input"; -/** - * @swagger - * /custom-inputs: - * get: - * summary: Find all eventTypeCustomInputs - * tags: - * - custom-inputs - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No eventTypeCustomInputs were found - * post: - * summary: Creates a new eventTypeCustomInput - * tags: - * - custom-inputs - * responses: - * 201: - * description: OK, eventTypeCustomInput created - * 400: - * description: Bad request. EventTypeCustomInput body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ async function createOrlistAllEventTypeCustomInputs( - req: NextApiRequest, + { userId, method, body }: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; const data = await prisma.eventType.findMany({ where: { userId } }); - const userEventTypes = data.map((eventType) => eventType.id); - + const userEventTypes: number[] = data.map((eventType) => eventType.id); if (method === "GET") { + /** + * @swagger + * /custom-inputs: + * get: + * summary: Find all eventTypeCustomInputs + * tags: + * - custom-inputs + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No eventTypeCustomInputs were found + */ const data = await prisma.eventTypeCustomInput.findMany({ where: { eventType: userEventTypes } }); const event_type_custom_inputs = data.map((eventTypeCustomInput) => schemaEventTypeCustomInputPublic.parse(eventTypeCustomInput) @@ -57,7 +43,22 @@ async function createOrlistAllEventTypeCustomInputs( error, }); } else if (method === "POST") { - const safe = schemaEventTypeCustomInputBodyParams.safeParse(req.body); + /** + * @swagger + * /custom-inputs: + * post: + * summary: Creates a new eventTypeCustomInput + * tags: + * - custom-inputs + * responses: + * 201: + * description: OK, eventTypeCustomInput created + * 400: + * description: Bad request. EventTypeCustomInput body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safe = schemaEventTypeCustomInputBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); // Since we're supporting a create or connect relation on eventType, we need to treat them differently // When using connect on event type, check if userId is the owner of the event diff --git a/pages/api/destination-calendars/[id].ts b/pages/api/destination-calendars/[id].ts index 679dcd5d29..f5d187eb25 100644 --- a/pages/api/destination-calendars/[id].ts +++ b/pages/api/destination-calendars/[id].ts @@ -13,74 +13,13 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -/** - * @swagger - * /destination-calendars/{id}: - * get: - * summary: Find a destination calendar by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the destination calendar to get - * tags: - * - destination-calendars - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: DestinationCalendar was not found - * patch: - * summary: Edit an existing destination calendar - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the destination calendar to edit - * tags: - * - destination-calendars - * responses: - * 201: - * description: OK, destinationCalendar edited successfuly - * 400: - * description: Bad request. DestinationCalendar body is invalid. - * 401: - * description: Authorization information is missing or invalid. - * delete: - * summary: Remove an existing destination calendar - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the destination calendar to delete - - * tags: - * - destination-calendars - * responses: - * 201: - * description: OK, destinationCalendar removed successfuly - * 400: - * description: Bad request. DestinationCalendar id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ export async function destionationCalendarById( - req: NextApiRequest, + { method, query, body, userId }: NextApiRequest, res: NextApiResponse ) { - const { method, query, body } = req; const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaDestinationCalendarEditBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = req.userId; const data = await prisma.destinationCalendar.findMany({ where: { userId } }); const userDestinationCalendars = data.map((destinationCalendar) => destinationCalendar.id); // FIXME: Should we also check ownership of bokingId and eventTypeId to avoid users cross-pollinating other users calendars. @@ -88,6 +27,64 @@ export async function destionationCalendarById( if (userDestinationCalendars.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { + /** + * @swagger + * /destination-calendars/{id}: + * get: + * summary: Find a destination calendar + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the destination calendar to get + * tags: + * - destination-calendars + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: DestinationCalendar was not found + * patch: + * summary: Edit an existing destination calendar + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the destination calendar to edit + * tags: + * - destination-calendars + * responses: + * 201: + * description: OK, destinationCalendar edited successfuly + * 400: + * description: Bad request. DestinationCalendar body is invalid. + * 401: + * description: Authorization information is missing or invalid. + * delete: + * summary: Remove an existing destination calendar + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the destination calendar to delete + * tags: + * - destination-calendars + * responses: + * 201: + * description: OK, destinationCalendar removed successfuly + * 400: + * description: Bad request. DestinationCalendar id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ case "GET": await prisma.destinationCalendar .findUnique({ where: { id: safeQuery.data.id } }) @@ -100,7 +97,28 @@ export async function destionationCalendarById( }) ); break; - + /** + * @swagger + * /destination-calendars/{id}: + * patch: + * summary: Edit an existing destination calendar + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the destination calendar to edit + * tags: + * - destination-calendars + * responses: + * 201: + * description: OK, destinationCalendar edited successfuly + * 400: + * description: Bad request. DestinationCalendar body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ case "PATCH": if (!safeBody.success) { throw new Error("Invalid request body"); @@ -116,7 +134,28 @@ export async function destionationCalendarById( }) ); break; - + /** + * @swagger + * /destination-calendars/{id}: + * delete: + * summary: Remove an existing destination calendar + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the destination calendar to delete + * tags: + * - destination-calendars + * responses: + * 201: + * description: OK, destinationCalendar removed successfuly + * 400: + * description: Bad request. DestinationCalendar id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ case "DELETE": await prisma.destinationCalendar .delete({ diff --git a/pages/api/destination-calendars/index.ts b/pages/api/destination-calendars/index.ts index 81a3d36c97..4006a67c72 100644 --- a/pages/api/destination-calendars/index.ts +++ b/pages/api/destination-calendars/index.ts @@ -9,40 +9,26 @@ import { schemaDestinationCalendarReadPublic, } from "@lib/validations/destination-calendar"; -/** - * @swagger - * /destination-calendars: - * get: - * summary: Find all destination calendars - * tags: - * - destination-calendars - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No destination calendars were found - * post: - * summary: Creates a new destination calendar - * tags: - * - destination-calendars - * responses: - * 201: - * description: OK, destination calendar created - * 400: - * description: Bad request. DestinationCalendar body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ async function createOrlistAllDestinationCalendars( - req: NextApiRequest, + { method, body, userId }: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; - if (method === "GET") { + /** + * @swagger + * /destination-calendars: + * get: + * summary: Find all destination calendars + * tags: + * - destination-calendars + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No destination calendars were found + */ const data = await prisma.destinationCalendar.findMany({ where: { userId } }); const destination_calendars = data.map((destinationCalendar) => schemaDestinationCalendarReadPublic.parse(destinationCalendar) @@ -55,7 +41,22 @@ async function createOrlistAllDestinationCalendars( error, }); } else if (method === "POST") { - const safe = schemaDestinationCalendarCreateBodyParams.safeParse(req.body); + /** + * @swagger + * /destination-calendars: + * post: + * summary: Creates a new destination calendar + * tags: + * - destination-calendars + * responses: + * 201: + * description: OK, destination calendar created + * 400: + * description: Bad request. DestinationCalendar body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safe = schemaDestinationCalendarCreateBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.destinationCalendar.create({ data: { ...safe.data, userId } }); diff --git a/pages/api/event-references/[id].ts b/pages/api/event-references/[id].ts index d0a31fcf11..a98d5f74e9 100644 --- a/pages/api/event-references/[id].ts +++ b/pages/api/event-references/[id].ts @@ -14,16 +14,14 @@ import { } from "@lib/validations/shared/queryIdTransformParseInt"; export async function dailyEventReferenceById( - req: NextApiRequest, + { method, query, body, userId }: NextApiRequest, res: NextApiResponse ) { - const { method, query, body } = req; const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaDailyEventReferenceEditBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = req.userId; const userBookings = await prisma.booking.findMany({ where: { userId } }); - const userBookingIds = userBookings.map((booking) => booking.id); + const userBookingIds: number[] = userBookings.map((booking) => booking.id); const userBookingDailyEventReferences = await prisma.dailyEventReference.findMany({ where: { bookingId: { in: userBookingIds } }, }); @@ -38,7 +36,7 @@ export async function dailyEventReferenceById( * @swagger * /event-references/{id}: * get: - * summary: Find a event reference by ID + * summary: Find a event reference * parameters: * - in: path * name: id diff --git a/pages/api/event-references/index.ts b/pages/api/event-references/index.ts index 1168ccbda6..bc19171de8 100644 --- a/pages/api/event-references/index.ts +++ b/pages/api/event-references/index.ts @@ -9,42 +9,29 @@ import { schemaDailyEventReferenceReadPublic, } from "@lib/validations/daily-event-reference"; -/** - * @swagger - * /event-references: - * get: - * summary: Find all daily event reference - * tags: - * - event-references - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No daily event references were found - * post: - * summary: Creates a new daily event reference - * tags: - * - event-references - * responses: - * 201: - * description: OK, daily event reference created - * 400: - * description: Bad request. DailyEventReference body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ async function createOrlistAllDailyEventReferences( - req: NextApiRequest, + { method, body, userId }: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; const userBookings = await prisma.booking.findMany({ where: { userId } }); const userBookingIds = userBookings.map((booking) => booking.id); if (method === "GET") { + /** + * @swagger + * /event-references: + * get: + * summary: Find all daily event reference + * tags: + * - event-references + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No daily event references were found + */ const data = await prisma.dailyEventReference.findMany({ where: { bookingId: { in: userBookingIds } }, }); @@ -59,7 +46,22 @@ async function createOrlistAllDailyEventReferences( error, }); } else if (method === "POST") { - const safe = schemaDailyEventReferenceCreateBodyParams.safeParse(req.body); + /** + * @swagger + * /event-references: + * post: + * summary: Creates a new daily event reference + * tags: + * - event-references + * responses: + * 201: + * description: OK, daily event reference created + * 400: + * description: Bad request. DailyEventReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safe = schemaDailyEventReferenceCreateBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.dailyEventReference.create({ data: safe.data }); diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index ebb440bd37..0ece116d17 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -10,87 +10,43 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -/** - * @swagger - * /event-types/{id}: - * get: - * summary: Find a eventType by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the eventType to get - * security: - * - ApiKeyAuth: [] - * tags: - * - event-types - * externalDocs: - * url: https://docs.cal.com/event-types - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: EventType was not found - * patch: - * summary: Edit an existing eventType - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the eventType to edit - * security: - * - ApiKeyAuth: [] - * tags: - * - event-types - * externalDocs: - * url: https://docs.cal.com/event-types - * responses: - * 201: - * description: OK, eventType edited successfuly - * 400: - * description: Bad request. EventType body is invalid. - * 401: - * description: Authorization information is missing or invalid. - * delete: - * summary: Remove an existing eventType - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the eventType to delete - * security: - * - ApiKeyAuth: [] - * tags: - * - event-types - * externalDocs: - * url: https://docs.cal.com/event-types - * responses: - * 201: - * description: OK, eventType removed successfuly - * 400: - * description: Bad request. EventType id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function eventTypeById(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body } = req; +export async function eventTypeById( + { method, query, body, userId }: NextApiRequest, + res: NextApiResponse +) { const safeQuery = schemaQueryIdParseInt.safeParse(query); - const safeBody = schemaEventTypeBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = req.userId; const data = await prisma.eventType.findMany({ where: { userId } }); const userEventTypes = data.map((eventType) => eventType.id); if (!userEventTypes.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { + /** + * @swagger + * /event-types/{id}: + * get: + * summary: Find a eventType + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the eventType to get + * security: + * - ApiKeyAuth: [] + * tags: + * - event-types + * externalDocs: + * url: https://docs.cal.com/event-types + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: EventType was not found + */ case "GET": await prisma.eventType .findUnique({ where: { id: safeQuery.data.id } }) @@ -103,8 +59,34 @@ export async function eventTypeById(req: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; - if (method === "GET") { + /** + * @swagger + * /event-types: + * get: + * summary: Find all event types + * tags: + * - event-types + * externalDocs: + * url: https://docs.cal.com/event-types + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No event types were found + */ const data = await prisma.eventType.findMany({ where: { userId } }); const event_types = data.map((eventType) => schemaEventTypePublic.parse(eventType)); if (event_types) res.status(200).json({ event_types }); @@ -54,7 +38,24 @@ async function createOrlistAllEventTypes( error, }); } else if (method === "POST") { - const safe = schemaEventTypeBodyParams.safeParse(req.body); + /** + * @swagger + * /event-types: + * post: + * summary: Creates a new event type + * tags: + * - event-types + * externalDocs: + * url: https://docs.cal.com/event-types + * responses: + * 201: + * description: OK, event type created + * 400: + * description: Bad request. EventType body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safe = schemaEventTypeBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.eventType.create({ data: { ...safe.data, userId } }); diff --git a/pages/api/memberships/[id].ts b/pages/api/memberships/[id].ts index fa4c298be4..0681a629a9 100644 --- a/pages/api/memberships/[id].ts +++ b/pages/api/memberships/[id].ts @@ -7,93 +7,45 @@ import type { MembershipResponse } from "@lib/types"; import { schemaMembershipBodyParams, schemaMembershipPublic } from "@lib/validations/membership"; import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; -/** - * @swagger - * /memberships/{userId}_{teamId}: - * get: - * summary: Find a membership by userID and teamID - * parameters: - * - in: path - * name: userId - * schema: - * type: integer - * required: true - * description: Numeric userId of the membership to get - * - in: path - * name: teamId - * schema: - * type: integer - * required: true - * description: Numeric teamId of the membership to get - * tags: - * - memberships - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Membership was not found - * patch: - * summary: Edit an existing membership - * parameters: - * - in: path - * name: userId - * schema: - * type: integer - * required: true - * description: Numeric userId of the membership to get - * - in: path - * name: teamId - * schema: - * type: integer - * required: true - * description: Numeric teamId of the membership to get - * tags: - * - memberships - * responses: - * 201: - * description: OK, membership edited successfuly - * 400: - * description: Bad request. Membership body is invalid. - * 401: - * description: Authorization information is missing or invalid. - * delete: - * summary: Remove an existing membership - * parameters: - * - in: path - * name: userId - * schema: - * type: integer - * required: true - * description: Numeric userId of the membership to get - * - in: path - * name: teamId - * schema: - * type: integer - * required: true - * description: Numeric teamId of the membership to get - * tags: - * - memberships - * responses: - * 201: - * description: OK, membership removed successfuly - * 400: - * description: Bad request. Membership id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function membershipById(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body } = req; +export async function membershipById( + { method, query, body, userId }: NextApiRequest, + res: NextApiResponse +) { const safeQuery = schemaQueryIdAsString.safeParse(query); - const safeBody = schemaMembershipBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); // This is how we set the userId and teamId in the query for managing compoundId. const [paramUserId, teamId] = safeQuery.data.id.split("_"); - const userId = req.userId; if (parseInt(paramUserId) !== userId) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { + /** + * @swagger + * /memberships/{userId}_{teamId}: + * get: + * summary: Find a membership by userID and teamID + * parameters: + * - in: path + * name: userId + * schema: + * type: integer + * required: true + * description: Numeric userId of the membership to get + * - in: path + * name: teamId + * schema: + * type: integer + * required: true + * description: Numeric teamId of the membership to get + * tags: + * - memberships + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Membership was not found + */ case "GET": await prisma.membership .findUnique({ @@ -114,7 +66,36 @@ export async function membershipById(req: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; if (method === "GET") { + /** + * @swagger + * /memberships: + * get: + * summary: Find all memberships + * tags: + * - memberships + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No memberships were found + */ const data = await prisma.membership.findMany({ where: { userId } }); const memberships = data.map((membership) => schemaMembershipPublic.parse(membership)); if (memberships) res.status(200).json({ memberships }); @@ -49,7 +36,22 @@ async function createOrlistAllMemberships( error, }); } else if (method === "POST") { - const safe = schemaMembershipBodyParams.safeParse(req.body); + /** + * @swagger + * /memberships: + * post: + * summary: Creates a new membership + * tags: + * - memberships + * responses: + * 201: + * description: OK, membership created + * 400: + * description: Bad request. Membership body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safe = schemaMembershipBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.membership.create({ data: { ...safe.data, userId } }); diff --git a/pages/api/payments/[id].ts b/pages/api/payments/[id].ts index 90882e760c..ebcaa0c504 100644 --- a/pages/api/payments/[id].ts +++ b/pages/api/payments/[id].ts @@ -14,7 +14,7 @@ import { * @swagger * /payments/{id}: * get: - * summary: Find one of your own payments by ID + * summary: Find a payment * parameters: * - in: path * name: id @@ -32,11 +32,11 @@ import { * 404: * description: Payment was not found */ -export async function paymentById(req: NextApiRequest, res: NextApiResponse) { - const { method, query } = req; +export async function paymentById( + { method, query, userId }: NextApiRequest, + res: NextApiResponse +) { const safeQuery = schemaQueryIdParseInt.safeParse(query); - const userId = req.userId; - if (safeQuery.success && method === "GET") { const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index d6645597a6..af63d8af2b 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -10,64 +10,6 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -/** - * @swagger - * /schedules/{id}: - * get: - * summary: Find a schedule by ID - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the schedule to get - * tags: - * - schedules - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Schedule was not found - * patch: - * summary: Edit an existing schedule - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the schedule to edit - * tags: - * - schedules - * responses: - * 201: - * description: OK, schedule edited successfuly - * 400: - * description: Bad request. Schedule body is invalid. - * 401: - * description: Authorization information is missing or invalid. - * delete: - * summary: Remove an existing schedule - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the schedule to delete - * tags: - * - schedules - * responses: - * 201: - * description: OK, schedule removed successfuly - * 400: - * description: Bad request. Schedule id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ export async function scheduleById(req: NextApiRequest, res: NextApiResponse) { const { method, query, body } = req; const safeQuery = schemaQueryIdParseInt.safeParse(query); @@ -79,6 +21,28 @@ export async function scheduleById(req: NextApiRequest, res: NextApiResponse @@ -42,6 +14,21 @@ async function createOrlistAllSchedules( const userId = req.userId; if (method === "GET") { + /** + * @swagger + * /schedules: + * get: + * summary: Find all schedules + * tags: + * - schedules + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No schedules were found + */ const data = await prisma.schedule.findMany({ where: { userId } }); const schedules = data.map((schedule) => schemaSchedulePublic.parse(schedule)); if (schedules) res.status(200).json({ schedules }); @@ -52,6 +39,21 @@ async function createOrlistAllSchedules( error, }); } else if (method === "POST") { + /** + * @swagger + * /schedules: + * post: + * summary: Creates a new schedule + * tags: + * - schedules + * responses: + * 201: + * description: OK, schedule created + * 400: + * description: Bad request. Schedule body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ const safe = schemaScheduleBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.schedule.create({ data: { ...safe.data, userId } }); diff --git a/pages/api/selected-calendars/[id].ts b/pages/api/selected-calendars/[id].ts index a8e1e7ab15..10fb737cf9 100644 --- a/pages/api/selected-calendars/[id].ts +++ b/pages/api/selected-calendars/[id].ts @@ -10,101 +10,6 @@ import { } from "@lib/validations/selected-calendar"; import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; -/** - * @swagger - * /selected-calendars/{userId}_{integration}_{externalId}: - * get: - * summary: Find a selected-calendar by userID and teamID - * parameters: - * - in: path - * name: userId - * schema: - * type: integer - * required: true - * description: userId of the selected calendar to get - * - in: path - * name: externalId - * schema: - * type: string - * required: true - * description: externalId of the selected calendar to get - * - in: path - * name: integration - * schema: - * type: string - * required: true - * description: integration of the selected calendar to get - * tags: - * - selected-calendars - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: SelectedCalendar was not found - * patch: - * summary: Edit an existing selected calendar - * parameters: - * - in: path - * name: userId - * schema: - * type: integer - * required: true - * description: userId of the selected calendar to get - * - in: path - * name: externalId - * schema: - * type: string - * required: true - * description: externalId of the selected calendar to get - * - in: path - * name: integration - * schema: - * type: string - * required: true - * description: integration of the selected calendar to get - * tags: - * - selected-calendars - * responses: - * 201: - * description: OK, selected-calendar edited successfuly - * 400: - * description: Bad request. SelectedCalendar body is invalid. - * 401: - * description: Authorization information is missing or invalid. - * delete: - * summary: Remove an existing selected-calendar - * parameters: - * - in: path - * name: userId - * schema: - * type: integer - * required: true - * description: userId of the selected calendar to get - * - in: path - * name: externalId - * schema: - * type: integer - * required: true - * description: externalId of the selected-calendar to get - * - in: path - * name: integration - * schema: - * type: string - * required: true - * description: integration of the selected calendar to get - - * tags: - * - selected-calendars - * responses: - * 201: - * description: OK, selected-calendar removed successfuly - * 400: - * description: Bad request. SelectedCalendar id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ export async function selectedCalendarById( req: NextApiRequest, res: NextApiResponse @@ -119,6 +24,40 @@ export async function selectedCalendarById( if (userId !== parseInt(paramUserId)) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { + /** + * @swagger + * /selected-calendars/{userId}_{integration}_{externalId}: + * get: + * summary: Find a selected calendar + * parameters: + * - in: path + * name: userId + * schema: + * type: integer + * required: true + * description: userId of the selected calendar to get + * - in: path + * name: externalId + * schema: + * type: string + * required: true + * description: externalId of the selected calendar to get + * - in: path + * name: integration + * schema: + * type: string + * required: true + * description: integration of the selected calendar to get + * tags: + * - selected-calendars + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: SelectedCalendar was not found + */ case "GET": await prisma.selectedCalendar .findUnique({ @@ -140,6 +79,40 @@ export async function selectedCalendarById( ); break; + /** + * @swagger + * /selected-calendars/{userId}_{integration}_{externalId}: + * patch: + * summary: Edit a selected calendar + * parameters: + * - in: path + * name: userId + * schema: + * type: integer + * required: true + * description: userId of the selected calendar to get + * - in: path + * name: externalId + * schema: + * type: string + * required: true + * description: externalId of the selected calendar to get + * - in: path + * name: integration + * schema: + * type: string + * required: true + * description: integration of the selected calendar to get + * tags: + * - selected-calendars + * responses: + * 201: + * description: OK, selected-calendar edited successfuly + * 400: + * description: Bad request. SelectedCalendar body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ case "PATCH": if (!safeBody.success) { throw new Error("Invalid request body"); @@ -164,7 +137,40 @@ export async function selectedCalendarById( }) ); break; - + /** + * @swagger + * /selected-calendars/{userId}_{integration}_{externalId}: + * delete: + * summary: Remove a selected calendar + * parameters: + * - in: path + * name: userId + * schema: + * type: integer + * required: true + * description: userId of the selected calendar to get + * - in: path + * name: externalId + * schema: + * type: integer + * required: true + * description: externalId of the selected-calendar to get + * - in: path + * name: integration + * schema: + * type: string + * required: true + * description: integration of the selected calendar to get + * tags: + * - selected-calendars + * responses: + * 201: + * description: OK, selected-calendar removed successfuly + * 400: + * description: Bad request. SelectedCalendar id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ case "DELETE": await prisma.selectedCalendar .delete({ diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index c6e1b122d9..758d663b8f 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -9,40 +9,26 @@ import { schemaSelectedCalendarPublic, } from "@lib/validations/selected-calendar"; -/** - * @swagger - * /selected-calendars: - * get: - * summary: Find all selected calendars - * tags: - * - selected-calendars - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No selected calendars were found - * post: - * summary: Creates a new selected calendar - * tags: - * - selected-calendars - * responses: - * 201: - * description: OK, selected calendar created - * 400: - * description: Bad request. SelectedCalendar body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ async function createOrlistAllSelectedCalendars( - req: NextApiRequest, + { method, userId }: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; - if (method === "GET") { + /** + * @swagger + * /selected-calendars: + * get: + * summary: Find all selected calendars + * tags: + * - selected-calendars + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No selected calendars were found + */ const data = await prisma.selectedCalendar.findMany({ where: { userId } }); const selected_calendars = data.map((selected_calendar) => schemaSelectedCalendarPublic.parse(selected_calendar) @@ -55,6 +41,32 @@ async function createOrlistAllSelectedCalendars( error, }); } else if (method === "POST") { + /** + * @swagger + * /selected-calendars: + * get: + * summary: Find all selected calendars + * tags: + * - selected-calendars + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No selected calendars were found + * post: + * summary: Creates a new selected calendar + * tags: + * - selected-calendars + * responses: + * 201: + * description: OK, selected calendar created + * 400: + * description: Bad request. SelectedCalendar body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ const safe = schemaSelectedCalendarBodyParams.safeParse(req.body); if (!safe.success) throw new Error("Invalid request body"); // Create new selectedCalendar connecting it to current userId diff --git a/pages/api/teams/[id].ts b/pages/api/teams/[id].ts index 0368a69f5c..d3e971d487 100644 --- a/pages/api/teams/[id].ts +++ b/pages/api/teams/[id].ts @@ -14,7 +14,7 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * @swagger * /teams/{id}: * get: - * summary: Find a team by ID + * summary: Find a team * parameters: * - in: path * name: id diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index 4cea26e8e3..58d0b41d36 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -14,7 +14,7 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations * @swagger * /users/{id}: * get: - * summary: Find a user by ID, returns your user if regular user. + * summary: Find a user, returns your user if regular user. * parameters: * - in: path * name: id diff --git a/templates/endpoints/[id]/index.ts b/templates/endpoints/[id]/index.ts index c3297459ac..c9b1d85152 100644 --- a/templates/endpoints/[id]/index.ts +++ b/templates/endpoints/[id]/index.ts @@ -14,7 +14,7 @@ import { * @swagger * /v1/resources/{id}: * get: - * summary: Find a resource by ID + * summary: Find a resource * parameters: * - in: path * name: id From c8d776aeb7ce1b2f360b14395d802ca9adceba21 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 29 Apr 2022 17:36:25 +0200 Subject: [PATCH 167/658] fix: remove extra comments --- pages/api/attendees/[id].ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index 4e044790a4..9a2e40f106 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -29,9 +29,9 @@ export async function attendeeById( // Flatten and merge all the attendees in one array (bookings) => bookings - .map((bookings) => bookings.attendees) // Get the attendees IDs from user bookings - .flat() // Needed to flatten the array of arrays of all bookings attendees - .map((attendee) => attendee.id) // We only need the attendee IDs + .map((bookings) => bookings.attendees) + .flat() + .map((attendee) => attendee.id) ); // @note: Here we make sure to only return attendee's of the user's own bookings. if (!userBookingsAttendeeIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); From 57aeb19c66a0055943be39472693e56d0396f0a4 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 29 Apr 2022 19:45:33 +0200 Subject: [PATCH 168/658] fix: pass enableCors true to swaggeruireact props doesn't seem to work --- pages/api/docs.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/docs.ts b/pages/api/docs.ts index 356967d4a2..e87c6c1f5c 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -21,7 +21,7 @@ const swaggerHandler = withSwagger({ components: { securitySchemes: { ApiKeyAuth: { type: "apiKey", in: "query", name: "apiKey" } }, }, - security: [{ apiKey: [] }], + security: [{ ApiKeyAuth: [] }], }, apiFolder: "pages/api", }); From 4321fec7344498b9874b9480bf203ff6d46379ab Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 30 Apr 2022 05:09:54 +0200 Subject: [PATCH 169/658] fix: remove json schema --- json-schema/json-schema.json | 1064 ---------------------------------- next.config.js | 10 +- 2 files changed, 3 insertions(+), 1071 deletions(-) delete mode 100644 json-schema/json-schema.json diff --git a/json-schema/json-schema.json b/json-schema/json-schema.json deleted file mode 100644 index f6a197e4a5..0000000000 --- a/json-schema/json-schema.json +++ /dev/null @@ -1,1064 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema#", - "definitions": { - "EventType": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "title": { - "type": "string", - "description": "@zod.nonempty()" - }, - "slug": { - "type": "string", - "description": "@zod.custom(imports.eventTypeSlug)" - }, - "description": { - "type": ["string", "null"] - }, - "position": { - "type": "integer", - "default": 0 - }, - "locations": { - "type": ["number", "string", "boolean", "object", "array", "null"], - "description": "@zod.custom(imports.eventTypeLocations)" - }, - "length": { - "type": "integer" - }, - "hidden": { - "type": "boolean", - "default": false - }, - "users": { - "type": "array", - "items": { - "$ref": "#/components/schemas/User" - } - }, - "userId": { - "type": ["integer", "null"] - }, - "team": { - "anyOf": [ - { - "$ref": "#/components/schemas/Team" - }, - { - "type": "null" - } - ] - }, - "bookings": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Booking" - } - }, - "availability": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Availability" - } - }, - "webhooks": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Webhook" - } - }, - "destinationCalendar": { - "anyOf": [ - { - "$ref": "#/components/schemas/DestinationCalendar" - }, - { - "type": "null" - } - ] - }, - "eventName": { - "type": ["string", "null"] - }, - "customInputs": { - "type": "array", - "items": { - "$ref": "#/components/schemas/EventTypeCustomInput" - } - }, - "timeZone": { - "type": ["string", "null"] - }, - "periodType": { - "type": "string", - "default": "UNLIMITED", - "enum": ["UNLIMITED", "ROLLING", "RANGE"] - }, - "periodStartDate": { - "type": ["string", "null"], - "format": "date-time" - }, - "periodEndDate": { - "type": ["string", "null"], - "format": "date-time" - }, - "periodDays": { - "type": ["integer", "null"] - }, - "periodCountCalendarDays": { - "type": ["boolean", "null"] - }, - "requiresConfirmation": { - "type": "boolean", - "default": false - }, - "disableGuests": { - "type": "boolean", - "default": false - }, - "minimumBookingNotice": { - "type": "integer", - "default": 120 - }, - "beforeEventBuffer": { - "type": "integer", - "default": 0 - }, - "afterEventBuffer": { - "type": "integer", - "default": 0 - }, - "schedulingType": { - "type": ["string", "null"], - "enum": ["ROUND_ROBIN", "COLLECTIVE"] - }, - "schedule": { - "anyOf": [ - { - "$ref": "#/components/schemas/Schedule" - }, - { - "type": "null" - } - ] - }, - "price": { - "type": "integer", - "default": 0 - }, - "currency": { - "type": "string", - "default": "usd" - }, - "slotInterval": { - "type": ["integer", "null"] - }, - "metadata": { - "type": ["number", "string", "boolean", "object", "array", "null"] - } - } - }, - "Credential": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "type": { - "type": "string" - }, - "key": { - "type": ["number", "string", "boolean", "object", "array", "null"] - }, - "user": { - "anyOf": [ - { - "$ref": "#/components/schemas/User" - }, - { - "type": "null" - } - ] - } - } - }, - "DestinationCalendar": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "integration": { - "type": "string" - }, - "externalId": { - "type": "string" - }, - "user": { - "anyOf": [ - { - "$ref": "#/components/schemas/User" - }, - { - "type": "null" - } - ] - }, - "booking": { - "anyOf": [ - { - "$ref": "#/components/schemas/Booking" - }, - { - "type": "null" - } - ] - }, - "eventType": { - "anyOf": [ - { - "$ref": "#/components/schemas/EventType" - }, - { - "type": "null" - } - ] - } - } - }, - "User": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "username": { - "type": ["string", "null"] - }, - "name": { - "type": ["string", "null"] - }, - "email": { - "type": "string", - "description": "@zod.email()" - }, - "emailVerified": { - "type": ["string", "null"], - "format": "date-time" - }, - "password": { - "type": ["string", "null"] - }, - "bio": { - "type": ["string", "null"] - }, - "avatar": { - "type": ["string", "null"] - }, - "timeZone": { - "type": "string", - "default": "Europe/London" - }, - "weekStart": { - "type": "string", - "default": "Sunday" - }, - "startTime": { - "type": "integer", - "default": 0 - }, - "endTime": { - "type": "integer", - "default": 1440 - }, - "bufferTime": { - "type": "integer", - "default": 0 - }, - "hideBranding": { - "type": "boolean", - "default": false - }, - "theme": { - "type": ["string", "null"] - }, - "createdDate": { - "type": "string", - "format": "date-time" - }, - "trialEndsAt": { - "type": ["string", "null"], - "format": "date-time" - }, - "eventTypes": { - "type": "array", - "items": { - "$ref": "#/components/schemas/EventType" - } - }, - "credentials": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Credential" - } - }, - "teams": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Membership" - } - }, - "bookings": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Booking" - } - }, - "schedules": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Schedule" - } - }, - "defaultScheduleId": { - "type": ["integer", "null"] - }, - "selectedCalendars": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SelectedCalendar" - } - }, - "completedOnboarding": { - "type": "boolean", - "default": false - }, - "locale": { - "type": ["string", "null"] - }, - "timeFormat": { - "type": ["integer", "null"], - "default": 12 - }, - "twoFactorSecret": { - "type": ["string", "null"] - }, - "twoFactorEnabled": { - "type": "boolean", - "default": false - }, - "identityProvider": { - "type": "string", - "default": "CAL", - "enum": ["CAL", "GOOGLE", "SAML"] - }, - "identityProviderId": { - "type": ["string", "null"] - }, - "availability": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Availability" - } - }, - "invitedTo": { - "type": ["integer", "null"] - }, - "plan": { - "type": "string", - "default": "TRIAL", - "enum": ["FREE", "TRIAL", "PRO"] - }, - "webhooks": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Webhook" - } - }, - "brandColor": { - "type": "string", - "default": "#292929" - }, - "darkBrandColor": { - "type": "string", - "default": "#fafafa" - }, - "destinationCalendar": { - "anyOf": [ - { - "$ref": "#/components/schemas/DestinationCalendar" - }, - { - "type": "null" - } - ] - }, - "away": { - "type": "boolean", - "default": false - }, - "metadata": { - "type": ["number", "string", "boolean", "object", "array", "null"] - }, - "verified": { - "type": ["boolean", "null"], - "default": false - }, - "apiKeys": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ApiKey" - } - } - } - }, - "Team": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "name": { - "type": ["string", "null"] - }, - "slug": { - "type": ["string", "null"] - }, - "logo": { - "type": ["string", "null"] - }, - "bio": { - "type": ["string", "null"] - }, - "hideBranding": { - "type": "boolean", - "default": false - }, - "members": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Membership" - } - }, - "eventTypes": { - "type": "array", - "items": { - "$ref": "#/components/schemas/EventType" - } - } - } - }, - "Membership": { - "type": "object", - "properties": { - "accepted": { - "type": "boolean", - "default": false - }, - "role": { - "type": "string", - "enum": ["MEMBER", "ADMIN", "OWNER"] - }, - "team": { - "$ref": "#/components/schemas/Team" - }, - "user": { - "$ref": "#/components/schemas/User" - } - } - }, - "VerificationRequest": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "identifier": { - "type": "string" - }, - "token": { - "type": "string" - }, - "expires": { - "type": "string", - "format": "date-time" - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - } - } - }, - "BookingReference": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "type": { - "type": "string" - }, - "uid": { - "type": "string" - }, - "meetingId": { - "type": ["string", "null"] - }, - "meetingPassword": { - "type": ["string", "null"] - }, - "meetingUrl": { - "type": ["string", "null"] - }, - "booking": { - "anyOf": [ - { - "$ref": "#/components/schemas/Booking" - }, - { - "type": "null" - } - ] - } - } - }, - "Attendee": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "email": { - "type": "string" - }, - "name": { - "type": "string" - }, - "timeZone": { - "type": "string" - }, - "locale": { - "type": ["string", "null"], - "default": "en" - }, - "booking": { - "anyOf": [ - { - "$ref": "#/components/schemas/Booking" - }, - { - "type": "null" - } - ] - } - } - }, - "DailyEventReference": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "dailyurl": { - "type": "string", - "default": "dailycallurl" - }, - "dailytoken": { - "type": "string", - "default": "dailytoken" - }, - "booking": { - "anyOf": [ - { - "$ref": "#/components/schemas/Booking" - }, - { - "type": "null" - } - ] - } - } - }, - "Booking": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "uid": { - "type": "string" - }, - "user": { - "anyOf": [ - { - "$ref": "#/components/schemas/User" - }, - { - "type": "null" - } - ] - }, - "references": { - "type": "array", - "items": { - "$ref": "#/components/schemas/BookingReference" - } - }, - "eventType": { - "anyOf": [ - { - "$ref": "#/components/schemas/EventType" - }, - { - "type": "null" - } - ] - }, - "title": { - "type": "string" - }, - "description": { - "type": ["string", "null"] - }, - "startTime": { - "type": "string", - "format": "date-time" - }, - "endTime": { - "type": "string", - "format": "date-time" - }, - "attendees": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Attendee" - } - }, - "location": { - "type": ["string", "null"] - }, - "dailyRef": { - "anyOf": [ - { - "$ref": "#/components/schemas/DailyEventReference" - }, - { - "type": "null" - } - ] - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": ["string", "null"], - "format": "date-time" - }, - "confirmed": { - "type": "boolean", - "default": true - }, - "rejected": { - "type": "boolean", - "default": false - }, - "status": { - "type": "string", - "default": "ACCEPTED", - "enum": ["CANCELLED", "ACCEPTED", "REJECTED", "PENDING"] - }, - "paid": { - "type": "boolean", - "default": false - }, - "payment": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Payment" - } - }, - "destinationCalendar": { - "anyOf": [ - { - "$ref": "#/components/schemas/DestinationCalendar" - }, - { - "type": "null" - } - ] - }, - "cancellationReason": { - "type": ["string", "null"] - }, - "rejectionReason": { - "type": ["string", "null"] - } - } - }, - "Schedule": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "user": { - "$ref": "#/components/schemas/User" - }, - "eventType": { - "anyOf": [ - { - "$ref": "#/components/schemas/EventType" - }, - { - "type": "null" - } - ] - }, - "name": { - "type": "string" - }, - "timeZone": { - "type": ["string", "null"] - }, - "availability": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Availability" - } - } - } - }, - "Availability": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "user": { - "anyOf": [ - { - "$ref": "#/components/schemas/User" - }, - { - "type": "null" - } - ] - }, - "eventType": { - "anyOf": [ - { - "$ref": "#/components/schemas/EventType" - }, - { - "type": "null" - } - ] - }, - "days": { - "type": "array", - "items": { - "type": "integer" - } - }, - "startTime": { - "type": "string", - "format": "date-time" - }, - "endTime": { - "type": "string", - "format": "date-time" - }, - "date": { - "type": ["string", "null"], - "format": "date-time" - }, - "Schedule": { - "anyOf": [ - { - "$ref": "#/components/schemas/Schedule" - }, - { - "type": "null" - } - ] - } - } - }, - "SelectedCalendar": { - "type": "object", - "properties": { - "user": { - "$ref": "#/components/schemas/User" - }, - "integration": { - "type": "string" - }, - "externalId": { - "type": "string" - } - } - }, - "EventTypeCustomInput": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "eventType": { - "$ref": "#/components/schemas/EventType" - }, - "label": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["TEXT", "TEXTLONG", "NUMBER", "BOOL"] - }, - "required": { - "type": "boolean" - }, - "placeholder": { - "type": "string", - "default": "" - } - } - }, - "ResetPasswordRequest": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "updatedAt": { - "type": "string", - "format": "date-time" - }, - "email": { - "type": "string" - }, - "expires": { - "type": "string", - "format": "date-time" - } - } - }, - "ReminderMail": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "referenceId": { - "type": "integer" - }, - "reminderType": { - "type": "string", - "enum": ["PENDING_BOOKING_CONFIRMATION"] - }, - "elapsedMinutes": { - "type": "integer" - }, - "createdAt": { - "type": "string", - "format": "date-time" - } - } - }, - "Payment": { - "type": "object", - "properties": { - "id": { - "type": "integer" - }, - "uid": { - "type": "string" - }, - "type": { - "type": "string", - "enum": ["STRIPE"] - }, - "booking": { - "anyOf": [ - { - "$ref": "#/components/schemas/Booking" - }, - { - "type": "null" - } - ] - }, - "amount": { - "type": "integer" - }, - "fee": { - "type": "integer" - }, - "currency": { - "type": "string" - }, - "success": { - "type": "boolean" - }, - "refunded": { - "type": "boolean" - }, - "data": { - "type": ["number", "string", "boolean", "object", "array", "null"] - }, - "externalId": { - "type": "string" - } - } - }, - "Webhook": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "subscriberUrl": { - "type": "string" - }, - "payloadTemplate": { - "type": ["string", "null"] - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "active": { - "type": "boolean", - "default": true - }, - "eventTriggers": { - "type": "array", - "enum": ["BOOKING_CREATED", "BOOKING_RESCHEDULED", "BOOKING_CANCELLED"] - }, - "user": { - "anyOf": [ - { - "$ref": "#/components/schemas/User" - }, - { - "type": "null" - } - ] - }, - "eventType": { - "anyOf": [ - { - "$ref": "#/components/schemas/EventType" - }, - { - "type": "null" - } - ] - } - } - }, - "ApiKey": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "user": { - "anyOf": [ - { - "$ref": "#/components/schemas/User" - }, - { - "type": "null" - } - ] - }, - "createdAt": { - "type": "string", - "format": "date-time" - }, - "expiresAt": { - "type": "string", - "format": "date-time" - }, - "note": { - "type": ["string", "null"] - } - } - } - }, - "type": "object", - "properties": { - "eventType": { - "$ref": "#/components/schemas/EventType" - }, - "credential": { - "$ref": "#/components/schemas/Credential" - }, - "destinationCalendar": { - "$ref": "#/components/schemas/DestinationCalendar" - }, - "user": { - "$ref": "#/components/schemas/User" - }, - "team": { - "$ref": "#/components/schemas/Team" - }, - "membership": { - "$ref": "#/components/schemas/Membership" - }, - "verificationRequest": { - "$ref": "#/components/schemas/VerificationRequest" - }, - "bookingReference": { - "$ref": "#/components/schemas/BookingReference" - }, - "attendee": { - "$ref": "#/components/schemas/Attendee" - }, - "dailyEventReference": { - "$ref": "#/components/schemas/DailyEventReference" - }, - "booking": { - "$ref": "#/components/schemas/Booking" - }, - "schedule": { - "$ref": "#/components/schemas/Schedule" - }, - "availability": { - "$ref": "#/components/schemas/Availability" - }, - "selectedCalendar": { - "$ref": "#/components/schemas/SelectedCalendar" - }, - "eventTypeCustomInput": { - "$ref": "#/components/schemas/EventTypeCustomInput" - }, - "resetPasswordRequest": { - "$ref": "#/components/schemas/ResetPasswordRequest" - }, - "reminderMail": { - "$ref": "#/components/schemas/ReminderMail" - }, - "payment": { - "$ref": "#/components/schemas/Payment" - }, - "webhook": { - "$ref": "#/components/schemas/Webhook" - }, - "apiKey": { - "$ref": "#/components/schemas/ApiKey" - } - } -} diff --git a/next.config.js b/next.config.js index fa5bc84e10..1542c7f0ff 100644 --- a/next.config.js +++ b/next.config.js @@ -1,5 +1,3 @@ -// https://www.npmjs.com/package/next-transpile-modules -// This makes our @calcom/prisma package from the monorepo to be transpiled and usable by API const withTM = require("next-transpile-modules")([ "@calcom/app-store", "@calcom/prisma", @@ -7,13 +5,11 @@ const withTM = require("next-transpile-modules")([ "@calcom/ee", ]); -// use something like withPlugins([withTM], {}) if more plugins added later. - module.exports = withTM({ async headers() { return [ { - // matching all API routes + // @note: disabling CORS matching all API routes as this will be a our Public API source: "/api/:path*", headers: [ { key: "Access-Control-Allow-Credentials", value: "true" }, @@ -30,12 +26,12 @@ module.exports = withTM({ }, async rewrites() { return [ - // This redirects requests recieved at / the root to the /api/ folder. + // @note: redirects requests from: "/:rest*" the root level to the "/api/:rest*" folder by default. { source: "/:rest*", destination: "/api/:rest*", }, - // This redirects requests to api/v*/ to /api/ passing version as a query parameter. + // @note: redirects requests from api/v*/:rest to /api/:rest?version=* passing version as a query parameter. { source: "/api/v:version/:rest*", destination: "/api/:rest*?version=:version", From 005d0f804046be8b40658ebc4fad4a98d0b39ab5 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 30 Apr 2022 19:46:04 +0200 Subject: [PATCH 170/658] fix: channels removed --- package.json | 1 + pages/api/docs.ts | 16 ++++++++++++++-- pages/api/users/[id].ts | 3 +++ pages/api/users/index.ts | 3 ++- types.d.ts | 1 + 5 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 types.d.ts diff --git a/package.json b/package.json index 0c1cb9556e..42f655236a 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "dependencies": { "@calcom/prisma": "*", "@sentry/nextjs": "^6.19.3", + "modify-response-middleware": "^1.1.0", "next": "^12.1.4", "next-api-middleware": "^1.0.1", "next-swagger-doc": "^0.2.1", diff --git a/pages/api/docs.ts b/pages/api/docs.ts index e87c6c1f5c..1e8bcf2175 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -1,6 +1,9 @@ -import jsonSchema from "@/json-schema/json-schema.json"; import pjson from "@/package.json"; +// import cors from "cors"; +import modifyRes from "modify-response-middleware"; +import { use } from "next-api-middleware"; import { withSwagger } from "next-swagger-doc"; +import { NextApiRequest, NextApiResponse } from "next/types"; const swaggerHandler = withSwagger({ definition: { @@ -25,4 +28,13 @@ const swaggerHandler = withSwagger({ }, apiFolder: "pages/api", }); -export default swaggerHandler(); + +export default use( + modifyRes((content: string, _req: NextApiRequest, _res: NextApiResponse) => { + if (content) { + const parsed = JSON.parse(content); + delete parsed.channels; + return Buffer.from(JSON.stringify(parsed)); + } + }) +)(swaggerHandler()); diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index 58d0b41d36..6b3e7ec784 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -15,6 +15,7 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations * /users/{id}: * get: * summary: Find a user, returns your user if regular user. + * operationId: getUserById * parameters: * - in: path * name: id @@ -33,6 +34,7 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations * description: User was not found * patch: * summary: Edit an existing user + * operationId: editUserById * parameters: * - in: path * name: id @@ -51,6 +53,7 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations * description: Authorization information is missing or invalid. * delete: * summary: Remove an existing user + * operationId: deleteUserById * parameters: * - in: path * name: id diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 4ef860e18f..5f6c64d604 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -10,9 +10,10 @@ import { schemaUserReadPublic } from "@lib/validations/user"; * @swagger * /users: * get: - * summary: Find all users (admin only), returns your user if regular user. + * summary: Find all users. * tags: * - users + * operationId: listUsers * responses: * 200: * description: OK diff --git a/types.d.ts b/types.d.ts new file mode 100644 index 0000000000..9a7af651d1 --- /dev/null +++ b/types.d.ts @@ -0,0 +1 @@ +declare module "modify-response-middleware"; From e27600b8c7c5f5eddd943b29ee13d56114f6f43c Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 30 Apr 2022 19:47:26 +0200 Subject: [PATCH 171/658] remove comment --- pages/api/docs.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/pages/api/docs.ts b/pages/api/docs.ts index 1e8bcf2175..dd544e89ae 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -1,5 +1,4 @@ import pjson from "@/package.json"; -// import cors from "cors"; import modifyRes from "modify-response-middleware"; import { use } from "next-api-middleware"; import { withSwagger } from "next-swagger-doc"; From b572e4b0ffb5a6c8d4f0c0a9a463c5a3e53aa43d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 30 Apr 2022 20:53:19 +0200 Subject: [PATCH 172/658] fix: move all req to deconstructed --- README.md | 2 - lib/helpers/verifyApiKey.ts | 18 ++--- pages/api/availabilities/index.ts | 4 +- pages/api/booking-references/[id].ts | 93 +++++++++++++------------ pages/api/booking-references/index.ts | 1 + pages/api/bookings/index.ts | 4 +- pages/api/payments/index.ts | 4 +- pages/api/schedules/[id].ts | 7 +- pages/api/schedules/index.ts | 7 +- pages/api/selected-calendars/[id].ts | 4 +- pages/api/selected-calendars/index.ts | 4 +- pages/api/teams/[id].ts | 7 +- pages/api/teams/index.ts | 65 +++++++++-------- pages/api/users/[id].ts | 3 +- pages/api/users/index.ts | 3 +- templates/endpoints/[id]/delete.ts | 6 +- templates/endpoints/[id]/edit.ts | 6 +- templates/endpoints/[id]/index.ts | 4 +- templates/endpoints/get_all_and_post.ts | 39 ++++++----- templates/endpoints/post.ts | 6 +- types.d.ts | 1 + 21 files changed, 148 insertions(+), 140 deletions(-) diff --git a/README.md b/README.md index a9904ac3ff..4bba94e69a 100644 --- a/README.md +++ b/README.md @@ -108,8 +108,6 @@ We have some shared validations which several resources require, like baseApiPar - **[*]BodyParams** which merges both `[*]BaseBodyParams.merge([*]RequiredParams);` -- **withValid[*]** which is currently not being much used because is only useful in only post endpoints (we do post/get all in same file). This would validate the req.body of a POST call to API against our BaseBodyParams validation - ### Next Validations [Next-Validations Docs](https://next-validations.productsway.com/) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index cf5c4a8472..c4fabac652 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -8,6 +8,8 @@ import prisma from "@calcom/prisma"; declare module "next" { export interface NextApiRequest extends IncomingMessage { userId: number; + body: any; + query: { [key: string]: string | string[] }; } } @@ -20,21 +22,21 @@ export const dateNotInPast = function (date: Date) { }; // This verifies the apiKey and sets the user if it is valid. -export const verifyApiKey: NextMiddleware = async (req, res, next) => { - if (!req.query.apiKey) return res.status(401).json({ message: "No apiKey provided" }); +export const verifyApiKey: NextMiddleware = async ({ query: { apiKey }, ...req }, res, next) => { + if (!apiKey) return res.status(401).json({ message: "No apiKey provided" }); // We remove the prefix from the user provided api_key. If no env set default to "cal_" - const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "cal_", ""); + const strippedApiKey = `${apiKey}`.replace(process.env.API_KEY_PREFIX || " cal_", ""); // Hash the key again before matching against the database records. const hashedKey = hashAPIKey(strippedApiKey); // Check if the hashed api key exists in database. - const apiKey = await prisma.apiKey.findUnique({ where: { hashedKey } }); + const validApiKey = await prisma.apiKey.findUnique({ where: { hashedKey } }); // If we cannot find any api key. Throw a 401 Unauthorized. - if (!apiKey) return res.status(401).json({ error: "Your apiKey is not valid" }); - if (apiKey.expiresAt && dateNotInPast(apiKey.expiresAt)) { + if (!validApiKey) return res.status(401).json({ error: "Your apiKey is not valid" }); + if (validApiKey.expiresAt && dateNotInPast(validApiKey.expiresAt)) { return res.status(401).json({ error: "This apiKey is expired" }); } - if (!apiKey.userId) return res.status(404).json({ error: "No user found for this apiKey" }); + if (!validApiKey.userId) return res.status(404).json({ error: "No user found for this apiKey" }); /* We save the user id in the request for later use */ - req.userId = apiKey.userId; + req.userId = validApiKey.userId; await next(); }; diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index 25b0866071..c7b53c211d 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -10,7 +10,7 @@ import { } from "@lib/validations/availability"; async function createOrlistAllAvailabilities( - { method, userId }: NextApiRequest, + { method, body, userId }: NextApiRequest, res: NextApiResponse ) { if (method === "GET") { @@ -58,7 +58,7 @@ async function createOrlistAllAvailabilities( * 401: * description: Authorization information is missing or invalid. */ - const safe = schemaAvailabilityCreateBodyParams.safeParse(req.body); + const safe = schemaAvailabilityCreateBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.availability.create({ data: { ...safe.data, userId } }); diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index cb0358d901..03bc87fafb 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -27,32 +27,33 @@ export async function bookingReferenceById( if (!userWithBookings) throw new Error("User not found"); const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); const bookingReference = await prisma.bookingReference.findUnique({ where: { id: safeQuery.data.id } }); - if (!bookingReference) throw new Error("BookingReference not found"); + if (!bookingReference?.bookingId) throw new Error("BookingReference: bookingId not found"); if (userBookingIds.includes(bookingReference.bookingId)) { switch (method) { - /** - * @swagger - * /booking-references/{id}: - * get: - * summary: Find a booking reference - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the booking reference to get - * tags: - * - booking-references - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: BookingReference was not found - */ case "GET": + /** + * @swagger + * /booking-references/{id}: + * get: + * summary: Find a booking reference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the booking reference to get + * tags: + * - booking-references + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: BookingReference was not found + */ + await prisma.bookingReference .findUnique({ where: { id: safeQuery.data.id } }) .then((data) => schemaBookingReferenceReadPublic.parse(data)) @@ -63,30 +64,32 @@ export async function bookingReferenceById( error, }) ); + break; - /** - * @swagger - * /booking-references/{id}: - * patch: - * summary: Edit an existing booking reference - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the booking reference to edit - * tags: - * - booking-references - * responses: - * 201: - * description: OK, bookingReference edited successfuly - * 400: - * description: Bad request. BookingReference body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ case "PATCH": + /** + * @swagger + * /booking-references/{id}: + * patch: + * summary: Edit an existing booking reference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the booking reference to edit + * tags: + * - booking-references + * responses: + * 201: + * description: OK, bookingReference edited successfuly + * 400: + * description: Bad request. BookingReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safeBody = schemaBookingEditBodyParams.safeParse(body); if (!safeBody.success) { throw new Error("Invalid request body"); diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index 87cbe25cdc..c228673240 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -75,6 +75,7 @@ async function createOrlistAllBookingReferences( throw new Error("User not found"); } const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); + if (!safe.data.bookingId) throw new Error("BookingReference: bookingId not found"); if (!userBookingIds.includes(safe.data.bookingId)) res.status(401).json({ message: "Unauthorized" }); else { const booking_reference = await prisma.bookingReference.create({ diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 57a774a916..bd1595ff6c 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -7,7 +7,7 @@ import { BookingResponse, BookingsResponse } from "@lib/types"; import { schemaBookingCreateBodyParams, schemaBookingReadPublic } from "@lib/validations/booking"; async function createOrlistAllBookings( - { method, userId }: NextApiRequest, + { method, body, userId }: NextApiRequest, res: NextApiResponse ) { if (method === "GET") { @@ -51,7 +51,7 @@ async function createOrlistAllBookings( * 401: * description: Authorization information is missing or invalid. */ - const safe = schemaBookingCreateBodyParams.safeParse(req.body); + const safe = schemaBookingCreateBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.booking.create({ data: { ...safe.data, userId } }); diff --git a/pages/api/payments/index.ts b/pages/api/payments/index.ts index 0c6eae0f85..d758421f46 100644 --- a/pages/api/payments/index.ts +++ b/pages/api/payments/index.ts @@ -21,9 +21,7 @@ import { schemaPaymentPublic } from "@lib/validations/payment"; * 404: * description: No payments were found */ -async function allPayments(req: NextApiRequest, res: NextApiResponse) { - const userId = req.userId; - +async function allPayments({ userId }: NextApiRequest, res: NextApiResponse) { const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index af63d8af2b..38066c4ab8 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -10,12 +10,13 @@ import { withValidQueryIdTransformParseInt, } from "@lib/validations/shared/queryIdTransformParseInt"; -export async function scheduleById(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body } = req; +export async function scheduleById( + { method, query, body, userId }: NextApiRequest, + res: NextApiResponse +) { const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaScheduleBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = req.userId; const userSchedules = await prisma.schedule.findMany({ where: { userId } }); const userScheduleIds = userSchedules.map((schedule) => schedule.id); if (!userScheduleIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index 5da47e226c..04dbc6b1a1 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -7,12 +7,9 @@ import { ScheduleResponse, SchedulesResponse } from "@lib/types"; import { schemaScheduleBodyParams, schemaSchedulePublic } from "@lib/validations/schedule"; async function createOrlistAllSchedules( - req: NextApiRequest, + { method, body, userId }: NextApiRequest, res: NextApiResponse ) { - const { method } = req; - const userId = req.userId; - if (method === "GET") { /** * @swagger @@ -54,7 +51,7 @@ async function createOrlistAllSchedules( * 401: * description: Authorization information is missing or invalid. */ - const safe = schemaScheduleBodyParams.safeParse(req.body); + const safe = schemaScheduleBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.schedule.create({ data: { ...safe.data, userId } }); const schedule = schemaSchedulePublic.parse(data); diff --git a/pages/api/selected-calendars/[id].ts b/pages/api/selected-calendars/[id].ts index 10fb737cf9..de4d7a5570 100644 --- a/pages/api/selected-calendars/[id].ts +++ b/pages/api/selected-calendars/[id].ts @@ -11,16 +11,14 @@ import { import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; export async function selectedCalendarById( - req: NextApiRequest, + { method, query, body, userId }: NextApiRequest, res: NextApiResponse ) { - const { method, query, body } = req; const safeQuery = schemaQueryIdAsString.safeParse(query); const safeBody = schemaSelectedCalendarBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); // This is how we set the userId and externalId in the query for managing compoundId. const [paramUserId, integration, externalId] = safeQuery.data.id.split("_"); - const userId = req.userId; if (userId !== parseInt(paramUserId)) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index 758d663b8f..cbf2e94b81 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -10,7 +10,7 @@ import { } from "@lib/validations/selected-calendar"; async function createOrlistAllSelectedCalendars( - { method, userId }: NextApiRequest, + { method, body, userId }: NextApiRequest, res: NextApiResponse ) { if (method === "GET") { @@ -67,7 +67,7 @@ async function createOrlistAllSelectedCalendars( * 401: * description: Authorization information is missing or invalid. */ - const safe = schemaSelectedCalendarBodyParams.safeParse(req.body); + const safe = schemaSelectedCalendarBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); // Create new selectedCalendar connecting it to current userId const data = await prisma.selectedCalendar.create({ diff --git a/pages/api/teams/[id].ts b/pages/api/teams/[id].ts index d3e971d487..e49277a143 100644 --- a/pages/api/teams/[id].ts +++ b/pages/api/teams/[id].ts @@ -68,12 +68,13 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * 401: * description: Authorization information is missing or invalid. */ -export async function teamById(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body } = req; +export async function teamById( + { method, query, body, userId }: NextApiRequest, + res: NextApiResponse +) { const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaTeamBodyParams.safeParse(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userId = req.userId; const userWithMemberships = await prisma.membership.findMany({ where: { userId: userId }, }); diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index e5ae852dd8..75aabd47b9 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -7,36 +7,26 @@ import { TeamResponse, TeamsResponse } from "@lib/types"; import { schemaMembershipPublic } from "@lib/validations/membership"; import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; -/** - * @swagger - * /teams: - * get: - * summary: Find all teams - * tags: - * - teams - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No teams were found - * post: - * summary: Creates a new team - * tags: - * - teams - * responses: - * 201: - * description: OK, team created - * 400: - * description: Bad request. Team body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createOrlistAllTeams(req: NextApiRequest, res: NextApiResponse) { - const { method } = req; - const userId = req.userId; +async function createOrlistAllTeams( + { method, body, userId }: NextApiRequest, + res: NextApiResponse +) { if (method === "GET") { + /** + * @swagger + * /teams: + * get: + * summary: Find all teams + * tags: + * - teams + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No teams were found + */ const userWithMemberships = await prisma.membership.findMany({ where: { userId: userId }, }); @@ -50,7 +40,22 @@ async function createOrlistAllTeams(req: NextApiRequest, res: NextApiResponse) { - const { method, query, body, userId } = req; +export async function userById({ method, query, body, userId }: NextApiRequest, res: NextApiResponse) { const safeQuery = schemaQueryIdParseInt.safeParse(query); console.log(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 5f6c64d604..046d456de9 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -22,8 +22,7 @@ import { schemaUserReadPublic } from "@lib/validations/user"; * 404: * description: No users were found */ -async function allUsers(req: NextApiRequest, res: NextApiResponse) { - const userId = req.userId; +async function allUsers({ userId }: NextApiRequest, res: NextApiResponse) { const data = await prisma.user.findMany({ where: { id: userId, diff --git a/templates/endpoints/[id]/delete.ts b/templates/endpoints/[id]/delete.ts index 908e74b7d5..133554ac25 100644 --- a/templates/endpoints/[id]/delete.ts +++ b/templates/endpoints/[id]/delete.ts @@ -32,9 +32,9 @@ import { * 401: * description: Authorization information is missing or invalid. */ -export async function deleteResource(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaQueryIdParseInt.safeParse(req.query); - if (!safe.success) throw new Error("Invalid request query", safe.error); +export async function deleteResource({query}: NextApiRequest, res: NextApiResponse) { + const safe = schemaQueryIdParseInt.safeParse(query); + if (!safe.success) throw new Error("Invalid request query"); const data = await prisma.resource.delete({ where: { id: safe.data.id } }); diff --git a/templates/endpoints/[id]/edit.ts b/templates/endpoints/[id]/edit.ts index 43cb6c8f8e..e72198d82e 100644 --- a/templates/endpoints/[id]/edit.ts +++ b/templates/endpoints/[id]/edit.ts @@ -33,9 +33,9 @@ import { * 401: * description: Authorization information is missing or invalid. */ -export async function editResource(req: NextApiRequest, res: NextApiResponse) { - const safeQuery = schemaQueryIdParseInt.safeParse(req.query); - const safeBody = schemaResourceBodyParams.safeParse(req.body); +export async function editResource({query, body}: NextApiRequest, res: NextApiResponse) { + const safeQuery = schemaQueryIdParseInt.safeParse(query); + const safeBody = schemaResourceBodyParams.safeParse(body); if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); const resource = await prisma.resource.update({ diff --git a/templates/endpoints/[id]/index.ts b/templates/endpoints/[id]/index.ts index c9b1d85152..4a0656d3b5 100644 --- a/templates/endpoints/[id]/index.ts +++ b/templates/endpoints/[id]/index.ts @@ -33,8 +33,8 @@ import { * 404: * description: Resource was not found */ -export async function resourceById(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaQueryIdParseInt.safeParse(req.query); +export async function resourceById({query}: NextApiRequest, res: NextApiResponse) { + const safe = schemaQueryIdParseInt.safeParse(query); if (!safe.success) throw new Error("Invalid request query"); const resource = await prisma.resource.findUnique({ where: { id: safe.data.id } }); diff --git a/templates/endpoints/get_all_and_post.ts b/templates/endpoints/get_all_and_post.ts index d20075e52c..e21dc8bb9d 100644 --- a/templates/endpoints/get_all_and_post.ts +++ b/templates/endpoints/get_all_and_post.ts @@ -6,6 +6,12 @@ import { withMiddleware } from "@lib/helpers/withMiddleware"; import { PaymentResponse, PaymentsResponse } from "@lib/types"; import { schemaPaymentBodyParams, schemaPaymentPublic } from "@lib/validations/payment"; +async function createOrlistAllPayments( + {method, body}: NextApiRequest, + res: NextApiResponse +) { + if (method === "GET") { + /** * @swagger * /v1/payments: @@ -21,6 +27,21 @@ import { schemaPaymentBodyParams, schemaPaymentPublic } from "@lib/validations/p * description: Authorization information is missing or invalid. * 404: * description: No payments were found + */ + const payments = await prisma.payment.findMany(); + const data = payments.map((payment) => schemaPaymentPublic.parse(payment)); + if (data) res.status(200).json({ data }); + else + (error: Error) => + res.status(404).json({ + message: "No Payments were found", + error, + }); + } else if (method === "POST") { + +/** + * @swagger + * /v1/payments: * post: * summary: Creates a new payment @@ -34,23 +55,7 @@ import { schemaPaymentBodyParams, schemaPaymentPublic } from "@lib/validations/p * 401: * description: Authorization information is missing or invalid. */ -async function createOrlistAllPayments( - req: NextApiRequest, - res: NextApiResponse -) { - const { method } = req; - if (method === "GET") { - const payments = await prisma.payment.findMany(); - const data = payments.map((payment) => schemaPaymentPublic.parse(payment)); - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "No Payments were found", - error, - }); - } else if (method === "POST") { - const safe = schemaPaymentBodyParams.safeParse(req.body); + const safe = schemaPaymentBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); const payment = await prisma.payment.create({ data: safe.data }); diff --git a/templates/endpoints/post.ts b/templates/endpoints/post.ts index 3f5b7403d7..896c09e691 100644 --- a/templates/endpoints/post.ts +++ b/templates/endpoints/post.ts @@ -29,9 +29,9 @@ import { schemaResourceBodyParams, schemaResourcePublic, withValidResource } fro * 401: * description: Authorization information is missing or invalid. */ -async function createResource(req: NextApiRequest, res: NextApiResponse) { - const safe = schemaResourceBodyParams.safeParse(req.body); - if (!safe.success) throw new Error("Invalid request body", safe.error); +async function createResource({body}: NextApiRequest, res: NextApiResponse) { + const safe = schemaResourceBodyParams.safeParse(body); + if (!safe.success) throw new Error("Invalid request body"); const resource = await prisma.resource.create({ data: safe.data }); const data = schemaResourcePublic.parse(resource); diff --git a/types.d.ts b/types.d.ts index 9a7af651d1..2abf07e4c1 100644 --- a/types.d.ts +++ b/types.d.ts @@ -1 +1,2 @@ declare module "modify-response-middleware"; + From a2d16800aafea29ce3e5c3b2ce4a88fb3350cea1 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 30 Apr 2022 23:07:21 +0200 Subject: [PATCH 173/658] Fixes: with hariom help for running api in prod for swagger even in dev --- lib/helpers/addRequestid.ts | 15 ++++++++++ lib/helpers/httpMethods.ts | 2 +- lib/helpers/verifyApiKey.ts | 18 ++++++------ next.config.js | 56 +++++++++++++++++-------------------- 4 files changed, 50 insertions(+), 41 deletions(-) diff --git a/lib/helpers/addRequestid.ts b/lib/helpers/addRequestid.ts index 263c7aacc1..6bdf1e546a 100644 --- a/lib/helpers/addRequestid.ts +++ b/lib/helpers/addRequestid.ts @@ -4,6 +4,21 @@ import { NextMiddleware } from "next-api-middleware"; export const addRequestId: NextMiddleware = async (_req, res, next) => { // Apply header with unique ID to every request res.setHeader("Calcom-Response-ID", nanoid()); + // Add all headers here instead of next.config.js as it is throwing error( Cannot set headers after they are sent to the client) for OPTIONS method + // It is known to happen only in Dev Mode. + res.setHeader("Access-Control-Allow-Credentials", "true"); + res.setHeader("Access-Control-Allow-Origin", "*"); + res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS, PATCH, DELETE, POST, PUT"); + res.setHeader( + "Access-Control-Allow-Headers", + "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version, Content-Type, api_key, Authorization" + ); + + // Ensure all OPTIONS request are automatically successful. Headers are already set above. + if (_req.method === "OPTIONS") { + res.status(200).end(); + return; + } // Let remaining middleware and API route execute await next(); }; diff --git a/lib/helpers/httpMethods.ts b/lib/helpers/httpMethods.ts index 0617208a90..0bf6243e0f 100644 --- a/lib/helpers/httpMethods.ts +++ b/lib/helpers/httpMethods.ts @@ -15,7 +15,7 @@ export const httpMethod = (allowedHttpMethod: "GET" | "POST" | "PATCH" | "DELETE // that checks if it's just a string or an array and apply the correct logic to both cases. export const httpMethods = (allowedHttpMethod: string[]): NextMiddleware => { return async function (req, res, next) { - if (allowedHttpMethod.map((method) => method === req.method)) { + if (allowedHttpMethod.some((method) => method === req.method || req.method == "OPTIONS")) { await next(); } else { res.status(405).json({ message: `Only ${allowedHttpMethod} Method allowed` }); diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index c4fabac652..cf5c4a8472 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -8,8 +8,6 @@ import prisma from "@calcom/prisma"; declare module "next" { export interface NextApiRequest extends IncomingMessage { userId: number; - body: any; - query: { [key: string]: string | string[] }; } } @@ -22,21 +20,21 @@ export const dateNotInPast = function (date: Date) { }; // This verifies the apiKey and sets the user if it is valid. -export const verifyApiKey: NextMiddleware = async ({ query: { apiKey }, ...req }, res, next) => { - if (!apiKey) return res.status(401).json({ message: "No apiKey provided" }); +export const verifyApiKey: NextMiddleware = async (req, res, next) => { + if (!req.query.apiKey) return res.status(401).json({ message: "No apiKey provided" }); // We remove the prefix from the user provided api_key. If no env set default to "cal_" - const strippedApiKey = `${apiKey}`.replace(process.env.API_KEY_PREFIX || " cal_", ""); + const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "cal_", ""); // Hash the key again before matching against the database records. const hashedKey = hashAPIKey(strippedApiKey); // Check if the hashed api key exists in database. - const validApiKey = await prisma.apiKey.findUnique({ where: { hashedKey } }); + const apiKey = await prisma.apiKey.findUnique({ where: { hashedKey } }); // If we cannot find any api key. Throw a 401 Unauthorized. - if (!validApiKey) return res.status(401).json({ error: "Your apiKey is not valid" }); - if (validApiKey.expiresAt && dateNotInPast(validApiKey.expiresAt)) { + if (!apiKey) return res.status(401).json({ error: "Your apiKey is not valid" }); + if (apiKey.expiresAt && dateNotInPast(apiKey.expiresAt)) { return res.status(401).json({ error: "This apiKey is expired" }); } - if (!validApiKey.userId) return res.status(404).json({ error: "No user found for this apiKey" }); + if (!apiKey.userId) return res.status(404).json({ error: "No user found for this apiKey" }); /* We save the user id in the request for later use */ - req.userId = validApiKey.userId; + req.userId = apiKey.userId; await next(); }; diff --git a/next.config.js b/next.config.js index 1542c7f0ff..6122951e9a 100644 --- a/next.config.js +++ b/next.config.js @@ -1,3 +1,5 @@ +// https://www.npmjs.com/package/next-transpile-modules +// This makes our @calcom/prisma package from the monorepo to be transpiled and usable by API const withTM = require("next-transpile-modules")([ "@calcom/app-store", "@calcom/prisma", @@ -5,37 +7,31 @@ const withTM = require("next-transpile-modules")([ "@calcom/ee", ]); +// use something like withPlugins([withTM], {}) if more plugins added later. + module.exports = withTM({ - async headers() { - return [ - { - // @note: disabling CORS matching all API routes as this will be a our Public API - source: "/api/:path*", - headers: [ - { key: "Access-Control-Allow-Credentials", value: "true" }, - { key: "Access-Control-Allow-Origin", value: "*" }, - { key: "Access-Control-Allow-Methods", value: "GET,OPTIONS,PATCH,DELETE,POST,PUT" }, - { - key: "Access-Control-Allow-Headers", - value: - "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version, Content-Type, api_key, Authorization", - }, - ], - }, - ]; - }, async rewrites() { - return [ - // @note: redirects requests from: "/:rest*" the root level to the "/api/:rest*" folder by default. - { - source: "/:rest*", - destination: "/api/:rest*", - }, - // @note: redirects requests from api/v*/:rest to /api/:rest?version=* passing version as a query parameter. - { - source: "/api/v:version/:rest*", - destination: "/api/:rest*?version=:version", - }, - ]; + return { + beforeFiles: [ + // This redirects requests recieved at / the root to the /api/ folder. + { + source: "/v:version/:rest*", + destination: "/api/v:version/:rest*", + }, + // This redirects requests to api/v*/ to /api/ passing version as a query parameter. + { + source: "/api/v:version/:rest*", + destination: "/api/:rest*?version=:version", + }, + ], + fallback: [ + // These rewrites are checked after both pages/public files + // and dynamic routes are checked + { + source: "/:path*", + destination: `/api/:path*`, + }, + ], + }; }, }); From 886b101887b1be6f17d746e270ed33e4c9da9edb Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 30 Apr 2022 23:57:57 +0200 Subject: [PATCH 174/658] fix: makes patch work by working around and faking production for yarn dev in api --- next.config.js | 52 +++++++++++++++++++++++++++++--------------------- package.json | 4 ++-- 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/next.config.js b/next.config.js index 6122951e9a..fa5bc84e10 100644 --- a/next.config.js +++ b/next.config.js @@ -10,28 +10,36 @@ const withTM = require("next-transpile-modules")([ // use something like withPlugins([withTM], {}) if more plugins added later. module.exports = withTM({ + async headers() { + return [ + { + // matching all API routes + source: "/api/:path*", + headers: [ + { key: "Access-Control-Allow-Credentials", value: "true" }, + { key: "Access-Control-Allow-Origin", value: "*" }, + { key: "Access-Control-Allow-Methods", value: "GET,OPTIONS,PATCH,DELETE,POST,PUT" }, + { + key: "Access-Control-Allow-Headers", + value: + "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version, Content-Type, api_key, Authorization", + }, + ], + }, + ]; + }, async rewrites() { - return { - beforeFiles: [ - // This redirects requests recieved at / the root to the /api/ folder. - { - source: "/v:version/:rest*", - destination: "/api/v:version/:rest*", - }, - // This redirects requests to api/v*/ to /api/ passing version as a query parameter. - { - source: "/api/v:version/:rest*", - destination: "/api/:rest*?version=:version", - }, - ], - fallback: [ - // These rewrites are checked after both pages/public files - // and dynamic routes are checked - { - source: "/:path*", - destination: `/api/:path*`, - }, - ], - }; + return [ + // This redirects requests recieved at / the root to the /api/ folder. + { + source: "/:rest*", + destination: "/api/:rest*", + }, + // This redirects requests to api/v*/ to /api/ passing version as a query parameter. + { + source: "/api/v:version/:rest*", + destination: "/api/:rest*?version=:version", + }, + ]; }, }); diff --git a/package.json b/package.json index 42f655236a..18d9081665 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,8 @@ "author": "Cal.com Inc.", "private": true, "scripts": { - "dev": "PORT=3002 next", - "start": "next start", + "dev": "next build && PORT=3002 next start", + "start": "PORT=3002 next start", "build": "next build", "lint": "next lint", "lint-fix": "next lint --fix && prettier --write .", From 8aa4852b875d37ec1dcf0a1b7dc8099bfe4163ff Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 1 May 2022 00:33:05 +0200 Subject: [PATCH 175/658] remove headers from next config, add rewrites from hariom pr --- next.config.js | 52 +++++++++++++++++++++----------------------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/next.config.js b/next.config.js index fa5bc84e10..6122951e9a 100644 --- a/next.config.js +++ b/next.config.js @@ -10,36 +10,28 @@ const withTM = require("next-transpile-modules")([ // use something like withPlugins([withTM], {}) if more plugins added later. module.exports = withTM({ - async headers() { - return [ - { - // matching all API routes - source: "/api/:path*", - headers: [ - { key: "Access-Control-Allow-Credentials", value: "true" }, - { key: "Access-Control-Allow-Origin", value: "*" }, - { key: "Access-Control-Allow-Methods", value: "GET,OPTIONS,PATCH,DELETE,POST,PUT" }, - { - key: "Access-Control-Allow-Headers", - value: - "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version, Content-Type, api_key, Authorization", - }, - ], - }, - ]; - }, async rewrites() { - return [ - // This redirects requests recieved at / the root to the /api/ folder. - { - source: "/:rest*", - destination: "/api/:rest*", - }, - // This redirects requests to api/v*/ to /api/ passing version as a query parameter. - { - source: "/api/v:version/:rest*", - destination: "/api/:rest*?version=:version", - }, - ]; + return { + beforeFiles: [ + // This redirects requests recieved at / the root to the /api/ folder. + { + source: "/v:version/:rest*", + destination: "/api/v:version/:rest*", + }, + // This redirects requests to api/v*/ to /api/ passing version as a query parameter. + { + source: "/api/v:version/:rest*", + destination: "/api/:rest*?version=:version", + }, + ], + fallback: [ + // These rewrites are checked after both pages/public files + // and dynamic routes are checked + { + source: "/:path*", + destination: `/api/:path*`, + }, + ], + }; }, }); From a41fc5732e8a837351c2917808520f4e0671f7da Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sun, 1 May 2022 00:36:59 +0200 Subject: [PATCH 176/658] fix: readme --- README.md | 6 ++++++ next.config.js | 2 -- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4bba94e69a..d210672e53 100644 --- a/README.md +++ b/README.md @@ -172,3 +172,9 @@ DATABASE_URL=DATABASE_URL="postgresql://postgres:@localhost:5450/calendso" API*KEY_PREFIX=cal*# This can be changed per envirorment so cal*test* for staging for example. > If you're self-hosting under our commercial license, you can use any prefix you want for api keys. either leave the default cal\_ (not providing any envirorment variable) or modify it + +**Ensure that while testing swagger, API project should be run in production mode** +We make sure of this by not using next in dev, but next build && next start, if you want hot module reloading and such when developing, please use yarn run next directly on apps/api. + +See . Here in dev mode OPTIONS method is hardcoded to return only GET and OPTIONS as allowed method. Running in Production mode would cause this file to be not used. This is hot-reloading logic only. +To remove this limitation, we need to ensure that on local endpoints are requested by swagger at /api/v1 and not /v1 diff --git a/next.config.js b/next.config.js index 6122951e9a..5e40353edf 100644 --- a/next.config.js +++ b/next.config.js @@ -7,8 +7,6 @@ const withTM = require("next-transpile-modules")([ "@calcom/ee", ]); -// use something like withPlugins([withTM], {}) if more plugins added later. - module.exports = withTM({ async rewrites() { return { From 1703976a4f5bf39191c06a86404775448fd7fb86 Mon Sep 17 00:00:00 2001 From: Hariom Balhara Date: Mon, 2 May 2022 11:30:08 +0530 Subject: [PATCH 177/658] Fix docs request --- package.json | 1 + pages/api/docs.ts | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 18d9081665..91eca0e3cc 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "private": true, "scripts": { "dev": "next build && PORT=3002 next start", + "dev-real":"PORT=3002 next dev", "start": "PORT=3002 next start", "build": "next build", "lint": "next lint", diff --git a/pages/api/docs.ts b/pages/api/docs.ts index dd544e89ae..943c6b9f25 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -29,7 +29,16 @@ const swaggerHandler = withSwagger({ }); export default use( - modifyRes((content: string, _req: NextApiRequest, _res: NextApiResponse) => { + modifyRes((content: string, _req: NextApiRequest, res: NextApiResponse) => { + // Add all headers here instead of next.config.js as it is throwing error( Cannot set headers after they are sent to the client) for OPTIONS method + // It is known to happen only in Dev Mode. + res.setHeader("Access-Control-Allow-Credentials", "true"); + res.setHeader("Access-Control-Allow-Origin", "*"); + res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS, PATCH, DELETE, POST, PUT"); + res.setHeader( + "Access-Control-Allow-Headers", + "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version, Content-Type, api_key, Authorization" + ); if (content) { const parsed = JSON.parse(content); delete parsed.channels; From 1f2b59c18d21d9dec9b8ef81edecc6cfda6f6dec Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 5 May 2022 05:02:59 +0200 Subject: [PATCH 178/658] feat: adds users post endpoint for admin only --- pages/api/users/[id].ts | 176 ++++++++++++++++++++++++--------------- pages/api/users/index.ts | 48 +++++++---- 2 files changed, 140 insertions(+), 84 deletions(-) diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index 3093b43cfc..ffaabcbf4f 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -10,68 +10,10 @@ import { } from "@lib/validations/shared/queryIdTransformParseInt"; import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations/user"; -/** - * @swagger - * /users/{id}: - * get: - * summary: Find a user, returns your user if regular user. - * operationId: getUserById - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the user to get - * tags: - * - users - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: User was not found - * patch: - * summary: Edit an existing user - * operationId: editUserById - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the user to edit - * tags: - * - users - * responses: - * 201: - * description: OK, user edited successfuly - * 400: - * description: Bad request. User body is invalid. - * 401: - * description: Authorization information is missing or invalid. - * delete: - * summary: Remove an existing user - * operationId: deleteUserById - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the user to delete - * tags: - * - users - * responses: - * 201: - * description: OK, user removed successfuly - * 400: - * description: Bad request. User id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function userById({ method, query, body, userId }: NextApiRequest, res: NextApiResponse) { +export async function userById( + { method, query, body, userId }: NextApiRequest, + res: NextApiResponse +) { const safeQuery = schemaQueryIdParseInt.safeParse(query); console.log(body); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); @@ -79,6 +21,31 @@ export async function userById({ method, query, body, userId }: NextApiRequest, else { switch (method) { case "GET": + /** + * @swagger + * /users/{id}: + * get: + * summary: Find a user, returns your user if regular user. + * operationId: getUserById + * parameters: + * - in: path + * name: id + * example: 4 + * schema: + * type: integer + * required: true + * description: ID of the user to get + * tags: + * - users + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: User was not found + */ + await prisma.user .findUnique({ where: { id: safeQuery.data.id } }) .then((data) => schemaUserReadPublic.parse(data)) @@ -87,24 +54,72 @@ export async function userById({ method, query, body, userId }: NextApiRequest, res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) ); break; - case "PATCH": + /** + * @swagger + * /users/{id}: + * patch: + * summary: Edit an existing user + * operationId: editUserById + * requestBody: + * description: Edit an existing attendee related to one of your bookings + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * weekStart: + * type: string + * enum: [Monday, Sunday, Saturday] + * example: Monday + * brandColor: + * type: string + * example: "#FF000F" + * darkBrandColor: + * type: string + * example: "#000000" + * timeZone: + * type: string + * example: Europe/London + * parameters: + * - in: path + * name: id + * example: 4 + * schema: + * type: integer + * required: true + * description: ID of the user to edit + * tags: + * - users + * responses: + * 201: + * description: OK, user edited successfuly + * 400: + * description: Bad request. User body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safeBody = schemaUserEditBodyParams.safeParse(body); if (!safeBody.success) { res.status(400).json({ message: "Bad request", error: safeBody.error }); - throw new Error("Invalid request body"); + // throw new Error("Invalid request body"); + return; } const userSchedules = await prisma.schedule.findMany({ where: { userId }, }); const userSchedulesIds = userSchedules.map((schedule) => schedule.id); // @note: here we make sure user can only make as default his own scheudles - if (!userSchedulesIds.includes(Number(safeBody?.data?.defaultScheduleId))) { + if ( + safeBody?.data?.defaultScheduleId && + !userSchedulesIds.includes(Number(safeBody?.data?.defaultScheduleId)) + ) { res.status(400).json({ - message: "Bad request", - error: "Invalid default schedule id", + message: "Bad request: Invalid default schedule id", }); - throw new Error("Invalid request body value: defaultScheduleId"); + return; } await prisma.user .update({ @@ -118,6 +133,31 @@ export async function userById({ method, query, body, userId }: NextApiRequest, ); break; + /** + * @swagger + * /users/{id}: + * delete: + * summary: Remove an existing user + * operationId: removeUserById + * parameters: + * - in: path + * name: id + * example: 1 + * schema: + * type: integer + * required: true + * description: ID of the user to delete + * tags: + * - users + * responses: + * 201: + * description: OK, user removed successfuly + * 400: + * description: Bad request. User id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + case "DELETE": await prisma.user .delete({ where: { id: safeQuery.data.id } }) diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 046d456de9..6eea24cb3b 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -3,17 +3,17 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { UsersResponse } from "@lib/types"; +import { UserResponse, UsersResponse } from "@lib/types"; import { schemaUserReadPublic } from "@lib/validations/user"; /** * @swagger * /users: * get: + * operationId: listUsers * summary: Find all users. * tags: * - users - * operationId: listUsers * responses: * 200: * description: OK @@ -22,21 +22,37 @@ import { schemaUserReadPublic } from "@lib/validations/user"; * 404: * description: No users were found */ -async function allUsers({ userId }: NextApiRequest, res: NextApiResponse) { - const data = await prisma.user.findMany({ - where: { - id: userId, - }, - }); - const users = data.map((user) => schemaUserReadPublic.parse(user)); - if (users) res.status(200).json({ users }); - else - (error: Error) => - res.status(404).json({ - message: "No Users were found", - error, +async function getAllorCreateUser( + { userId, method, body }: NextApiRequest, + res: NextApiResponse +) { + if (method === "GET") { + const data = await prisma.user.findMany({ + where: { + id: userId, + }, + }); + const users = data.map((user) => schemaUserReadPublic.parse(user)); + if (users) res.status(200).json({ users }); + else + (error: Error) => + res.status(404).json({ + message: "No Users were found", + error, + }); + } else if (method === "POST") { + const isAdmin = await prisma.user + .findUnique({ where: { id: userId } }) + .then((user) => user?.role === "ADMIN"); + if (!isAdmin) res.status(401).json({ message: "You are not authorized" }); + else { + const user = await prisma.user.create({ + data: schemaUserReadPublic.parse(body), }); + res.status(201).json({ user }); + } + } } // No POST endpoint for users for now as a regular user you're expected to signup. -export default withMiddleware("HTTP_GET")(allUsers); +export default withMiddleware("HTTP_GET_OR_POST")(getAllorCreateUser); From 08eeb36d47e51b73c250a13fe534f1e9e239a9c7 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 5 May 2022 18:18:00 +0200 Subject: [PATCH 179/658] feat: add operationId for autogenerated sdk --- lib/validations/booking-reference.ts | 4 +- lib/validations/shared/timeZone.ts | 4 +- lib/validations/user.ts | 3 +- package.json | 18 +- pages/api/attendees/[id].ts | 18 +- pages/api/attendees/index.ts | 20 +- pages/api/availabilities/[id].ts | 42 ++++- pages/api/availabilities/index.ts | 28 ++- pages/api/booking-references/[id].ts | 233 +++++++++++++----------- pages/api/booking-references/index.ts | 35 +++- pages/api/bookings/[id].ts | 6 +- pages/api/custom-inputs/[id].ts | 6 +- pages/api/destination-calendars/[id].ts | 10 +- pages/api/docs.ts | 23 ++- pages/api/event-references/[id].ts | 6 +- pages/api/event-types/[id].ts | 10 +- pages/api/payments/[id].ts | 2 +- pages/api/schedules/[id].ts | 9 +- pages/api/schedules/index.ts | 2 + pages/api/selected-calendars/[id].ts | 5 +- pages/api/selected-calendars/index.ts | 2 + pages/api/teams/[id].ts | 9 +- pages/api/teams/index.ts | 2 + templates/endpoints/[id]/delete.ts | 2 +- templates/endpoints/[id]/edit.ts | 2 +- templates/endpoints/[id]/index.ts | 2 +- 26 files changed, 323 insertions(+), 180 deletions(-) diff --git a/lib/validations/booking-reference.ts b/lib/validations/booking-reference.ts index 66aabc3d88..e6f90a0450 100644 --- a/lib/validations/booking-reference.ts +++ b/lib/validations/booking-reference.ts @@ -28,8 +28,8 @@ const schemaBookingReferenceCreateParams = z type: z.string(), uid: z.string(), meetingId: z.string(), - meetingPassword: z.string(), - meetingUrl: z.string(), + meetingPassword: z.string().optional(), + meetingUrl: z.string().optional(), deleted: z.boolean(), }) .strict(); diff --git a/lib/validations/shared/timeZone.ts b/lib/validations/shared/timeZone.ts index 9dfa98003d..13019690d0 100644 --- a/lib/validations/shared/timeZone.ts +++ b/lib/validations/shared/timeZone.ts @@ -1,5 +1,5 @@ -import * as tzdb from "tzdata"; +import tzdata from "tzdata"; import * as z from "zod"; // @note: This is a custom validation that checks if the timezone is valid and exists in the tzdb library -export const timeZone = z.string().refine((tz: string) => Object.keys(tzdb.zones).includes(tz)); +export const timeZone = z.string().refine((tz: string) => Object.keys(tzdata.zones).includes(tz)); diff --git a/lib/validations/user.ts b/lib/validations/user.ts index 9eb7b05094..b70d52f898 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -77,6 +77,7 @@ export const schemaUserBaseBodyParams = User.pick({ const schemaUserEditParams = z.object({ weekStart: z.nativeEnum(weekdays).optional(), brandColor: z.string().min(4).max(9).regex(/^#/).optional(), + darkBrandColor: z.string().min(4).max(9).regex(/^#/).optional(), timeZone: timeZone.optional(), bufferTime: z.number().min(0).max(86400).optional(), startTime: z.number().min(0).max(86400).optional(), @@ -87,7 +88,7 @@ const schemaUserEditParams = z.object({ .number() .refine((id: number) => id > 0) .optional(), - locale: z.nativeEnum(locales), + locale: z.nativeEnum(locales).optional(), }); // @note: These are the values that are editable via PATCH method on the user Model, diff --git a/package.json b/package.json index 91eca0e3cc..5677dc043f 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,4 @@ -{ + { "name": "@calcom/api", "version": "1.0.0", "description": "Public API for Cal.com", @@ -19,21 +19,21 @@ }, "devDependencies": { "@calcom/tsconfig": "*", - "@typescript-eslint/eslint-plugin": "^5.16.0", - "babel-jest": "^27.5.1", - "jest": "^27.5.1", + "@typescript-eslint/eslint-plugin": "^5.22.0", + "babel-jest": "^28.0.3", + "jest": "^28.0.3", "node-mocks-http": "^1.11.0" }, "dependencies": { "@calcom/prisma": "*", - "@sentry/nextjs": "^6.19.3", + "@sentry/nextjs": "^6.19.7", "modify-response-middleware": "^1.1.0", - "next": "^12.1.4", + "next": "^12.1.6", "next-api-middleware": "^1.0.1", - "next-swagger-doc": "^0.2.1", + "next-swagger-doc": "^0.3.4", "next-transpile-modules": "^9.0.0", - "next-validations": "^0.1.11", - "typescript": "^4.6.3", + "next-validations": "^0.2.0", + "typescript": "^4.6.4", "tzdata": "^1.0.30" } } diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index 9a2e40f106..a1674d87a4 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -17,7 +17,7 @@ export async function attendeeById( const safeQuery = schemaQueryIdParseInt.safeParse(query); if (!safeQuery.success) { res.status(400).json({ error: safeQuery.error }); - throw new Error("Invalid request query", safeQuery.error); + return; } const userBookingsAttendeeIds = await prisma.booking // Find all user bookings, including attendees @@ -41,6 +41,7 @@ export async function attendeeById( * @swagger * /attendees/{id}: * get: + * operationId: getAttendeeById * summary: Find an attendee * parameters: * - in: path @@ -48,7 +49,7 @@ export async function attendeeById( * schema: * type: integer * required: true - * description: Numeric ID of the attendee to get + * description: ID of the attendee to get * example: 3 * tags: * - attendees @@ -77,6 +78,7 @@ export async function attendeeById( * /attendees/{id}: * patch: * summary: Edit an existing attendee + * operationId: editAttendeeById * requestBody: * description: Edit an existing attendee related to one of your bookings * required: true @@ -84,11 +86,6 @@ export async function attendeeById( * application/json: * schema: * type: object - * required: - * - bookingId - * - name - * - email - * - timeZone * properties: * email: * type: string @@ -106,7 +103,7 @@ export async function attendeeById( * type: integer * example: 3 * required: true - * description: Numeric ID of the attendee to edit + * description: ID of the attendee to edit * tags: * - attendees * responses: @@ -121,7 +118,7 @@ export async function attendeeById( const safeBody = schemaAttendeeEditBodyParams.safeParse(body); if (!safeBody.success) { res.status(400).json({ message: "Bad request", error: safeBody.error }); - throw new Error("Invalid request body"); + return; } await prisma.attendee .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) @@ -138,6 +135,7 @@ export async function attendeeById( * @swagger * /attendees/{id}: * delete: + * operationId: removeAttendeeById * summary: Remove an existing attendee * parameters: * - in: path @@ -145,7 +143,7 @@ export async function attendeeById( * schema: * type: integer * required: true - * description: Numeric ID of the attendee to delete + * description: ID of the attendee to delete * tags: * - attendees * responses: diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index 18bbce51d7..eaae0b28ff 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -1,6 +1,6 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; +import db from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { AttendeeResponse, AttendeesResponse } from "@lib/types"; @@ -10,7 +10,7 @@ async function createOrlistAllAttendees( { method, userId, body }: NextApiRequest, res: NextApiResponse ) { - const userBookings = await prisma.booking.findMany({ + const userBookings = await db.booking.findMany({ where: { userId, }, @@ -24,6 +24,7 @@ async function createOrlistAllAttendees( * @swagger * /attendees: * get: + * operationId: listAttendees * summary: Find all attendees * tags: * - attendees @@ -47,6 +48,7 @@ async function createOrlistAllAttendees( * @swagger * /attendees: * post: + * operationId: addAttendee * summary: Creates a new attendee * requestBody: * description: Create a new attendee related to one of your bookings @@ -85,21 +87,19 @@ async function createOrlistAllAttendees( */ const safePost = schemaAttendeeCreateBodyParams.safeParse(body); if (!safePost.success) { - res.status(400).json({ error: safePost.error }); - throw new Error("Invalid request body", safePost.error); + res.status(400).json({ message: "Invalid request body", error: safePost.error }); + return; } - const userWithBookings = await prisma.user.findUnique({ - where: { id: userId }, - include: { bookings: true }, - }); + const userWithBookings = await db.user.findUnique({ where: { id: userId }, include: { bookings: true } }); if (!userWithBookings) { - throw new Error("User not found"); + res.status(404).json({ message: "User not found" }); + return; } const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); // Here we make sure to only return attendee's of the user's own bookings. if (!userBookingIds.includes(safePost.data.bookingId)) res.status(401).json({ message: "Unauthorized" }); else { - const data = await prisma.attendee.create({ + const data = await db.attendee.create({ data: { email: safePost.data.email, name: safePost.data.name, diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index 139e36e22f..0b6a58c338 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -18,7 +18,10 @@ export async function availabilityById( res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); - if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + if (!safeQuery.success) { + res.status(400).json({ message: "Your query is invalid", error: safeQuery.error }); + return; + } const data = await prisma.availability.findMany({ where: { userId } }); const availabiltiesIds = data.map((availability) => availability.id); if (!availabiltiesIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); @@ -28,6 +31,7 @@ export async function availabilityById( * @swagger * /availabilities/{id}: * get: + * operationId: getAvailabilityById * summary: Find an availability * parameters: * - in: path @@ -35,7 +39,7 @@ export async function availabilityById( * schema: * type: integer * required: true - * description: Numeric ID of the availability to get + * description: ID of the availability to get * tags: * - availabilities * externalDocs: @@ -44,9 +48,7 @@ export async function availabilityById( * 200: * description: OK * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Availability was not found + * description: Unathorized */ case "GET": await prisma.availability @@ -61,14 +63,32 @@ export async function availabilityById( * @swagger * /availabilities/{id}: * patch: + * operationId: editAvailabilityById * summary: Edit an existing availability + * requestBody: + * description: Edit an existing availability related to one of your bookings + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * days: + * type: array + * example: email@example.com + * startTime: + * type: string + * example: 1970-01-01T17:00:00.000Z + * endTime: + * type: string + * example: 1970-01-01T17:00:00.000Z * parameters: * - in: path * name: id * schema: * type: integer * required: true - * description: Numeric ID of the availability to edit + * description: ID of the availability to edit * tags: * - availabilities * externalDocs: @@ -82,8 +102,13 @@ export async function availabilityById( * description: Authorization information is missing or invalid. */ case "PATCH": + console.log(body); const safeBody = schemaAvailabilityEditBodyParams.safeParse(body); - if (!safeBody.success) throw new Error("Invalid request body"); + if (!safeBody.success) { + console.log(safeBody.error); + res.status(400).json({ message: "Bad request" + safeBody.error, error: safeBody.error }); + return; + } const userEventTypes = await prisma.eventType.findMany({ where: { userId } }); const userEventTypesIds = userEventTypes.map((event) => event.id); if (safeBody.data.eventTypeId && !userEventTypesIds.includes(safeBody.data.eventTypeId)) { @@ -109,6 +134,7 @@ export async function availabilityById( * @swagger * /availabilities/{id}: * delete: + * operationId: removeAvailabilityById * summary: Remove an existing availability * parameters: * - in: path @@ -116,7 +142,7 @@ export async function availabilityById( * schema: * type: integer * required: true - * description: Numeric ID of the availability to delete + * description: ID of the availability to delete * tags: * - availabilities * externalDocs: diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index c7b53c211d..bf17bd1ede 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -18,6 +18,7 @@ async function createOrlistAllAvailabilities( * @swagger * /availabilities: * get: + * operationId: listAvailabilities * summary: Find all availabilities * tags: * - availabilities @@ -45,7 +46,28 @@ async function createOrlistAllAvailabilities( * @swagger * /availabilities: * post: + * operationId: addAvailability * summary: Creates a new availability + * requestBody: + * description: Edit an existing availability related to one of your bookings + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - startTime + * - endTime + * properties: + * days: + * type: array + * example: email@example.com + * startTime: + * type: string + * example: 1970-01-01T17:00:00.000Z + * endTime: + * type: string + * example: 1970-01-01T17:00:00.000Z * tags: * - availabilities * externalDocs: @@ -59,7 +81,11 @@ async function createOrlistAllAvailabilities( * description: Authorization information is missing or invalid. */ const safe = schemaAvailabilityCreateBodyParams.safeParse(body); - if (!safe.success) throw new Error("Invalid request body"); + if (!safe.success) { + res.status(400).json({ message: "Your request is invalid", error: safe.error }); + return; + } + // FIXME: check for eventTypeId ad scheduleId ownership if passed const data = await prisma.availability.create({ data: { ...safe.data, userId } }); const availability = schemaAvailabilityReadPublic.parse(data); diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index 03bc87fafb..d86d0154dc 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -1,4 +1,3 @@ -import { BookingModel } from "@/../../packages/prisma/zod"; import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; @@ -20,95 +19,120 @@ export async function bookingReferenceById( ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); - const userWithBookings = await prisma.user.findUnique({ - where: { id: userId }, - include: { bookings: true }, - }); - if (!userWithBookings) throw new Error("User not found"); - const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); - const bookingReference = await prisma.bookingReference.findUnique({ where: { id: safeQuery.data.id } }); - if (!bookingReference?.bookingId) throw new Error("BookingReference: bookingId not found"); - if (userBookingIds.includes(bookingReference.bookingId)) { - switch (method) { - case "GET": - /** - * @swagger - * /booking-references/{id}: - * get: - * summary: Find a booking reference - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the booking reference to get - * tags: - * - booking-references - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: BookingReference was not found - */ + // const userWithBookings = await prisma.user.findUnique({ + // where: { id: userId }, + // include: { bookings: true }, + // }); + // if (!userWithBookings) throw new Error("User not found"); + // const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); + // console.log(userBookingIds); + // const bookingReferences = await prisma.bookingReference + // .findMany({ where: { id: { in: userBookingIds } } }) + // .then((bookingReferences) => { + // console.log(bookingReferences); + // return bookingReferences.map((bookingReference) => bookingReference.id); + // }); - await prisma.bookingReference - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaBookingReferenceReadPublic.parse(data)) - .then((booking_reference) => res.status(200).json({ booking_reference })) - .catch((error: Error) => - res.status(404).json({ - message: `BookingReference with id: ${safeQuery.data.id} not found`, - error, - }) - ); + // res.status(400).json({ message: "Booking reference not found" }); + // return; + // } + // if (userBookingIds.includes(safeQuery.data.id)) { + // if (!bookingReferences?.includes(safeQuery.data.id)) { + // throw new Error("BookingReference: bookingId not found"); + switch (method) { + case "GET": + /** + * @swagger + * /booking-references/{id}: + * get: + * operationId: getBookingReferenceById + * summary: Find a booking reference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the booking reference to get + * tags: + * - booking-references + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: BookingReference was not found + */ + console.log(safeQuery.data.id); + const bookingReference = await prisma.bookingReference.findFirst().catch((error: Error) => { + console.log("hoerr:", error); + }); + console.log(bookingReference); + if (!bookingReference) res.status(404).json({ message: "Booking reference not found" }); + else res.status(200).json({ booking_reference: bookingReference }); - break; - case "PATCH": - /** - * @swagger - * /booking-references/{id}: - * patch: - * summary: Edit an existing booking reference - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the booking reference to edit - * tags: - * - booking-references - * responses: - * 201: - * description: OK, bookingReference edited successfuly - * 400: - * description: Bad request. BookingReference body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ + // .then((data) => { + // console.log(data); + // return schemaBookingReferenceReadPublic.parse(data); + // }) + // .then((booking_reference) => res.status(200).json({ booking_reference })) + // .catch((error: Error) => { + // console.log(error); + // res.status(404).json({ + // message: `BookingReference with id: ${safeQuery.data.id} not found`, + // error, + // }); + // }); + break; + case "PATCH": + /** + * @swagger + * /booking-references/{id}: + * patch: + * operationId: editBookingReferenceById + * summary: Edit an existing booking reference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the booking reference to edit + * tags: + * - booking-references + * responses: + * 201: + * description: OK, safeBody.data edited successfuly + * 400: + * description: Bad request. BookingReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ - const safeBody = schemaBookingEditBodyParams.safeParse(body); - if (!safeBody.success) { - throw new Error("Invalid request body"); - } - await prisma.bookingReference - .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) - .then((data) => schemaBookingReferenceReadPublic.parse(data)) - .then((booking_reference) => res.status(200).json({ booking_reference })) - .catch((error: Error) => - res.status(404).json({ - message: `BookingReference with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; + const safeBody = schemaBookingEditBodyParams.safeParse(body); + if (!safeBody.success) { + res.status(401).json({ message: "Invalid request body", error: safeBody.error }); + return; + // throw new Error("Invalid request body"); + } + await prisma.bookingReference + .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) + .then((data) => schemaBookingReferenceReadPublic.parse(data)) + .then((booking_reference) => res.status(200).json({ booking_reference })) + .catch((error: Error) => + res.status(404).json({ + message: `BookingReference with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; + case "DELETE": /** * @swagger * /booking-references/{id}: * delete: + * operationId: removeBookingReferenceById * summary: Remove an existing booking reference * parameters: * - in: path @@ -116,7 +140,7 @@ export async function bookingReferenceById( * schema: * type: integer * required: true - * description: Numeric ID of the booking reference to delete + * description: ID of the booking reference to delete * tags: * - booking-references * responses: @@ -127,29 +151,28 @@ export async function bookingReferenceById( * 401: * description: Authorization information is missing or invalid. */ - case "DELETE": - await prisma.bookingReference - .delete({ - where: { id: safeQuery.data.id }, + await prisma.bookingReference + .delete({ + where: { id: safeQuery.data.id }, + }) + .then(() => + res.status(200).json({ + message: `BookingReference with id: ${safeQuery.data.id} deleted`, }) - .then(() => - res.status(200).json({ - message: `BookingReference with id: ${safeQuery.data.id} deleted`, - }) - ) - .catch((error: Error) => - res.status(404).json({ - message: `BookingReference with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; + ) + .catch((error: Error) => + res.status(404).json({ + message: `BookingReference with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } - } else res.status(401).json({ message: "Unauthorized" }); + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } + // } else res.status(401).json({ message: "Unauthorized" }); } export default withMiddleware("HTTP_GET_DELETE_PATCH")( diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index c228673240..3386d5e42d 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -24,6 +24,7 @@ async function createOrlistAllBookingReferences( * @swagger * /booking-references: * get: + * operationId: listBookingReferences * summary: Find all booking references * tags: * - booking-references @@ -51,7 +52,37 @@ async function createOrlistAllBookingReferences( * @swagger * /booking-references: * post: + * operationId: addBookingReference * summary: Creates a new booking reference + * requestBody: + * description: Create a new booking reference related to one of your bookings + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - type + * - uid + * - meetindId + * - bookingId + * - deleted + * properties: + * deleted: + * type: boolean + * example: false + * uid: + * type: string + * example: '123456789' + * type: + * type: string + * example: email@example.com + * bookingId: + * type: number + * example: 1 + * meetingId: + * type: string + * example: 'meeting-id' * tags: * - booking-references * responses: @@ -64,7 +95,9 @@ async function createOrlistAllBookingReferences( */ const safe = schemaBookingCreateBodyParams.safeParse(body); if (!safe.success) { - throw new Error("Invalid request body"); + res.status(400).json({ message: "Bad request. BookingReference body is invalid", error: safe.error }); + return; + // throw new Error("Invalid request body"); } const userWithBookings = await prisma.user.findUnique({ diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index 21fdd9a937..ff2f40671c 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -36,7 +36,7 @@ export async function bookingById( * schema: * type: integer * required: true - * description: Numeric ID of the booking to get + * description: ID of the booking to get * tags: * - bookings * responses: @@ -70,7 +70,7 @@ export async function bookingById( * schema: * type: integer * required: true - * description: Numeric ID of the booking to edit + * description: ID of the booking to edit * tags: * - bookings * responses: @@ -111,7 +111,7 @@ export async function bookingById( * schema: * type: integer * required: true - * description: Numeric ID of the booking to delete + * description: ID of the booking to delete * tags: * - bookings * responses: diff --git a/pages/api/custom-inputs/[id].ts b/pages/api/custom-inputs/[id].ts index 3339f31027..eb5493235f 100644 --- a/pages/api/custom-inputs/[id].ts +++ b/pages/api/custom-inputs/[id].ts @@ -24,7 +24,7 @@ import { * schema: * type: integer * required: true - * description: Numeric ID of the eventTypeCustomInput to get + * description: ID of the eventTypeCustomInput to get * tags: * - custom-inputs * responses: @@ -42,7 +42,7 @@ import { * schema: * type: integer * required: true - * description: Numeric ID of the eventTypeCustomInput to edit + * description: ID of the eventTypeCustomInput to edit * tags: * - custom-inputs * responses: @@ -60,7 +60,7 @@ import { * schema: * type: integer * required: true - * description: Numeric ID of the eventTypeCustomInput to delete + * description: ID of the eventTypeCustomInput to delete * tags: * - custom-inputs * responses: diff --git a/pages/api/destination-calendars/[id].ts b/pages/api/destination-calendars/[id].ts index f5d187eb25..60e8aae6b3 100644 --- a/pages/api/destination-calendars/[id].ts +++ b/pages/api/destination-calendars/[id].ts @@ -38,7 +38,7 @@ export async function destionationCalendarById( * schema: * type: integer * required: true - * description: Numeric ID of the destination calendar to get + * description: ID of the destination calendar to get * tags: * - destination-calendars * responses: @@ -56,7 +56,7 @@ export async function destionationCalendarById( * schema: * type: integer * required: true - * description: Numeric ID of the destination calendar to edit + * description: ID of the destination calendar to edit * tags: * - destination-calendars * responses: @@ -74,7 +74,7 @@ export async function destionationCalendarById( * schema: * type: integer * required: true - * description: Numeric ID of the destination calendar to delete + * description: ID of the destination calendar to delete * tags: * - destination-calendars * responses: @@ -108,7 +108,7 @@ export async function destionationCalendarById( * schema: * type: integer * required: true - * description: Numeric ID of the destination calendar to edit + * description: ID of the destination calendar to edit * tags: * - destination-calendars * responses: @@ -145,7 +145,7 @@ export async function destionationCalendarById( * schema: * type: integer * required: true - * description: Numeric ID of the destination calendar to delete + * description: ID of the destination calendar to delete * tags: * - destination-calendars * responses: diff --git a/pages/api/docs.ts b/pages/api/docs.ts index 943c6b9f25..d339043741 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -6,11 +6,11 @@ import { NextApiRequest, NextApiResponse } from "next/types"; const swaggerHandler = withSwagger({ definition: { - openapi: "3.0.0", + openapi: "3.0.3", servers: [ - { url: "https://api.cal.com/v1" }, - { url: "https://api.cal.dev/v1" }, { url: "http://localhost:3002/v1" }, + { url: "https://api.cal.dev/v1" }, + { url: "https://api.cal.com/v1" }, ], externalDocs: { url: "https://docs.cal.com", @@ -24,6 +24,22 @@ const swaggerHandler = withSwagger({ securitySchemes: { ApiKeyAuth: { type: "apiKey", in: "query", name: "apiKey" } }, }, security: [{ ApiKeyAuth: [] }], + tags: [ + { name: "users" }, + { name: "event-types" }, + { name: "bookings" }, + { name: "attendees" }, + { name: "payments" }, + { name: "schedules" }, + { name: "teams" }, + { name: "memberships" }, + { name: "availabilities" }, + { name: "custom-inputs" }, + { name: "event-references" }, + { name: "booking-references" }, + { name: "destination-calendars" }, + { name: "selected-calendars" }, + ], }, apiFolder: "pages/api", }); @@ -41,6 +57,7 @@ export default use( ); if (content) { const parsed = JSON.parse(content); + // HACK: This is a hack to fix the swagger-ui issue with the extra channels property. delete parsed.channels; return Buffer.from(JSON.stringify(parsed)); } diff --git a/pages/api/event-references/[id].ts b/pages/api/event-references/[id].ts index a98d5f74e9..a6a15b9e19 100644 --- a/pages/api/event-references/[id].ts +++ b/pages/api/event-references/[id].ts @@ -43,7 +43,7 @@ export async function dailyEventReferenceById( * schema: * type: integer * required: true - * description: Numeric ID of the event reference to get + * description: ID of the event reference to get * tags: * - event-references * responses: @@ -78,7 +78,7 @@ export async function dailyEventReferenceById( * schema: * type: integer * required: true - * description: Numeric ID of the event reference to edit + * description: ID of the event reference to edit * tags: * - event-references * responses: @@ -116,7 +116,7 @@ export async function dailyEventReferenceById( * schema: * type: integer * required: true - * description: Numeric ID of the event reference to delete + * description: ID of the event reference to delete * tags: * - event-references * responses: diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 0ece116d17..a6900b1d27 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -25,14 +25,16 @@ export async function eventTypeById( * @swagger * /event-types/{id}: * get: + * operationId: getEventTypeById * summary: Find a eventType * parameters: * - in: path * name: id + * example: 4 * schema: * type: integer * required: true - * description: Numeric ID of the eventType to get + * description: ID of the eventType to get * security: * - ApiKeyAuth: [] * tags: @@ -63,6 +65,7 @@ export async function eventTypeById( * @swagger * /event-types/{id}: * patch: + * operationId: editEventTypeById * summary: Edit an existing eventType * parameters: * - in: path @@ -70,7 +73,7 @@ export async function eventTypeById( * schema: * type: integer * required: true - * description: Numeric ID of the eventType to edit + * description: ID of the eventType to edit * security: * - ApiKeyAuth: [] * tags: @@ -105,6 +108,7 @@ export async function eventTypeById( * @swagger * /event-types/{id}: * delete: + * operationId: removeEventTypeById * summary: Remove an existing eventType * parameters: * - in: path @@ -112,7 +116,7 @@ export async function eventTypeById( * schema: * type: integer * required: true - * description: Numeric ID of the eventType to delete + * description: ID of the eventType to delete * security: * - ApiKeyAuth: [] * tags: diff --git a/pages/api/payments/[id].ts b/pages/api/payments/[id].ts index ebcaa0c504..99d515fe45 100644 --- a/pages/api/payments/[id].ts +++ b/pages/api/payments/[id].ts @@ -21,7 +21,7 @@ import { * schema: * type: integer * required: true - * description: Numeric ID of the payment to get + * description: ID of the payment to get * tags: * - payments * responses: diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index 38066c4ab8..5b90027ac3 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -26,6 +26,7 @@ export async function scheduleById( * @swagger * /schedules/{id}: * get: + * operationId: getScheduleById * summary: Find a schedule * parameters: * - in: path @@ -33,7 +34,7 @@ export async function scheduleById( * schema: * type: integer * required: true - * description: Numeric ID of the schedule to get + * description: ID of the schedule to get * tags: * - schedules * responses: @@ -61,6 +62,7 @@ export async function scheduleById( * @swagger * /schedules/{id}: * patch: + * operationId: editScheduleById * summary: Edit an existing schedule * parameters: * - in: path @@ -68,7 +70,7 @@ export async function scheduleById( * schema: * type: integer * required: true - * description: Numeric ID of the schedule to edit + * description: ID of the schedule to edit * tags: * - schedules * responses: @@ -99,6 +101,7 @@ export async function scheduleById( * @swagger * /schedules/{id}: * delete: + * operationId: removeScheduleById * summary: Remove an existing schedule * parameters: * - in: path @@ -106,7 +109,7 @@ export async function scheduleById( * schema: * type: integer * required: true - * description: Numeric ID of the schedule to delete + * description: ID of the schedule to delete * tags: * - schedules * responses: diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index 04dbc6b1a1..ac002345a3 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -15,6 +15,7 @@ async function createOrlistAllSchedules( * @swagger * /schedules: * get: + * operationId: listSchedules * summary: Find all schedules * tags: * - schedules @@ -40,6 +41,7 @@ async function createOrlistAllSchedules( * @swagger * /schedules: * post: + * operationId: addSchedule * summary: Creates a new schedule * tags: * - schedules diff --git a/pages/api/selected-calendars/[id].ts b/pages/api/selected-calendars/[id].ts index de4d7a5570..3915332412 100644 --- a/pages/api/selected-calendars/[id].ts +++ b/pages/api/selected-calendars/[id].ts @@ -26,7 +26,8 @@ export async function selectedCalendarById( * @swagger * /selected-calendars/{userId}_{integration}_{externalId}: * get: - * summary: Find a selected calendar + * operationId: getSelectedCalendarById + * summary: Find a selected calendar by providing the compoundId(userId_integration_externalId) separated by `_` * parameters: * - in: path * name: userId @@ -81,6 +82,7 @@ export async function selectedCalendarById( * @swagger * /selected-calendars/{userId}_{integration}_{externalId}: * patch: + * operationId: editSelectedCalendarById * summary: Edit a selected calendar * parameters: * - in: path @@ -139,6 +141,7 @@ export async function selectedCalendarById( * @swagger * /selected-calendars/{userId}_{integration}_{externalId}: * delete: + * operationId: removeSelectedCalendarById * summary: Remove a selected calendar * parameters: * - in: path diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index cbf2e94b81..e7ccd9d101 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -18,6 +18,7 @@ async function createOrlistAllSelectedCalendars( * @swagger * /selected-calendars: * get: + * operationId: listSelectedCalendars * summary: Find all selected calendars * tags: * - selected-calendars @@ -45,6 +46,7 @@ async function createOrlistAllSelectedCalendars( * @swagger * /selected-calendars: * get: + * operationId: addSelectedCalendars * summary: Find all selected calendars * tags: * - selected-calendars diff --git a/pages/api/teams/[id].ts b/pages/api/teams/[id].ts index e49277a143..adbc5e0c12 100644 --- a/pages/api/teams/[id].ts +++ b/pages/api/teams/[id].ts @@ -14,6 +14,7 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * @swagger * /teams/{id}: * get: + * operationId: getTeamById * summary: Find a team * parameters: * - in: path @@ -21,7 +22,7 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * schema: * type: integer * required: true - * description: Numeric ID of the team to get + * description: ID of the team to get * tags: * - teams * responses: @@ -32,6 +33,7 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * 404: * description: Team was not found * patch: + * operationId: editTeamById * summary: Edit an existing team * parameters: * - in: path @@ -39,7 +41,7 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * schema: * type: integer * required: true - * description: Numeric ID of the team to edit + * description: ID of the team to edit * tags: * - teams * responses: @@ -50,6 +52,7 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * 401: * description: Authorization information is missing or invalid. * delete: + * operationId: removeTeamById * summary: Remove an existing team * parameters: * - in: path @@ -57,7 +60,7 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * schema: * type: integer * required: true - * description: Numeric ID of the team to delete + * description: ID of the team to delete * tags: * - teams * responses: diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index 75aabd47b9..5ab45bc21d 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -16,6 +16,7 @@ async function createOrlistAllTeams( * @swagger * /teams: * get: + * operationId: listTeams * summary: Find all teams * tags: * - teams @@ -44,6 +45,7 @@ async function createOrlistAllTeams( * @swagger * /teams: * post: + * operationId: addTeam * summary: Creates a new team * tags: * - teams diff --git a/templates/endpoints/[id]/delete.ts b/templates/endpoints/[id]/delete.ts index 133554ac25..79645cbdfd 100644 --- a/templates/endpoints/[id]/delete.ts +++ b/templates/endpoints/[id]/delete.ts @@ -20,7 +20,7 @@ import { * schema: * type: integer * required: true - * description: Numeric ID of the resource to delete + * description: ID of the resource to delete * tags: * - resources diff --git a/templates/endpoints/[id]/edit.ts b/templates/endpoints/[id]/edit.ts index e72198d82e..8346840ec3 100644 --- a/templates/endpoints/[id]/edit.ts +++ b/templates/endpoints/[id]/edit.ts @@ -21,7 +21,7 @@ import { * schema: * type: integer * required: true - * description: Numeric ID of the resource to edit + * description: ID of the resource to edit * tags: * - resources diff --git a/templates/endpoints/[id]/index.ts b/templates/endpoints/[id]/index.ts index 4a0656d3b5..7933c5cab1 100644 --- a/templates/endpoints/[id]/index.ts +++ b/templates/endpoints/[id]/index.ts @@ -21,7 +21,7 @@ import { * schema: * type: integer * required: true - * description: Numeric ID of the resource to get + * description: ID of the resource to get * tags: * - resources From 17d8551442591698baf0d05724489714fe9091ce Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Tue, 10 May 2022 13:26:38 +0530 Subject: [PATCH 180/658] added webhook endpoint --- pages/api/hooks/[id].ts | 153 +++++++++++++++++++++++++++++++++++++++ pages/api/hooks/index.ts | 74 +++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 pages/api/hooks/[id].ts create mode 100644 pages/api/hooks/index.ts diff --git a/pages/api/hooks/[id].ts b/pages/api/hooks/[id].ts new file mode 100644 index 0000000000..c9fcdf346d --- /dev/null +++ b/pages/api/hooks/[id].ts @@ -0,0 +1,153 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { WebhookResponse } from "@lib/types"; +import { schemaWebhookBodyParams, schemaWebhookPublic } from "@lib/validations/webhook"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; + +export async function WebhookById( + { method, query, body, userId }: NextApiRequest, + res: NextApiResponse +) { + const safeQuery = schemaQueryIdParseInt.safeParse(query); + if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + const data = await prisma.webhook.findMany({ where: { userId } }); + const userWebhooks = data.map((webhook) => webhook.id); + if (!userWebhooks.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); + else { + switch (method) { + /** + * @swagger + * /hooks/{id}: + * get: + * summary: Find a webhook + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the webhook to get + * security: + * - ApiKeyAuth: [] + * tags: + * - hooks + * externalDocs: + * url: https://docs.cal.com/hooks + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Webhook was not found + */ + case "GET": + await prisma.webhook + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data) => schemaWebhookPublic.parse(data)) + .then((hook) => res.status(200).json({ hook })) + .catch((error: Error) => + res.status(404).json({ + message: `Webhook with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; + /** + * @swagger + * /hooks/{id}: + * patch: + * summary: Edit an existing webhook + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the webhook to edit + * security: + * - ApiKeyAuth: [] + * tags: + * - hooks + * externalDocs: + * url: https://docs.cal.com/hooks + * responses: + * 201: + * description: OK, webhook edited successfuly + * 400: + * description: Bad request. Webhook body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + case "PATCH": + const safeBody = schemaWebhookBodyParams.safeParse(body); + if (!safeBody.success) { + throw new Error("Invalid request body"); + } + await prisma.webhook + .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) + .then((data) => schemaWebhookPublic.parse(data)) + .then((hook) => res.status(200).json({ hook })) + .catch((error: Error) => + res.status(404).json({ + message: `Webhook with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; + /** + * @swagger + * /hooks/{id}: + * delete: + * summary: Remove an existing hook + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the hooks to delete + * security: + * - ApiKeyAuth: [] + * tags: + * - hooks + * externalDocs: + * url: https://docs.cal.com/hooks + * responses: + * 201: + * description: OK, hook removed successfuly + * 400: + * description: Bad request. hook id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + case "DELETE": + await prisma.webhook + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ + message: `Webhook with id: ${safeQuery.data.id} deleted`, + }) + ) + .catch((error: Error) => + res.status(404).json({ + message: `Webhook with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; + + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } + } +} + +export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(WebhookById)); diff --git a/pages/api/hooks/index.ts b/pages/api/hooks/index.ts new file mode 100644 index 0000000000..9ff4f441af --- /dev/null +++ b/pages/api/hooks/index.ts @@ -0,0 +1,74 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { WebhookResponse, WebhooksResponse } from "@lib/types"; +import { schemaWebhookBodyParams, schemaWebhookPublic } from "@lib/validations/webhook"; + +async function createOrlistAllWebhooks( + { method, body, userId }: NextApiRequest, + res: NextApiResponse +) { + if (method === "GET") { + /** + * @swagger + * /hooks: + * get: + * summary: Find all webhooks + * tags: + * - hooks + * externalDocs: + * url: https://docs.cal.com/webhooks + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No webhooks were found + */ + const data = await prisma.webhooks.findMany({ where: { userId } }); + const webhooks = data.map((webhook) => schemaWebhookPublic.parse(webhook)); + if (webhooks) res.status(200).json({ webhooks }); + else + (error: Error) => + res.status(404).json({ + message: "No Webhooks were found", + error, + }); + } else if (method === "POST") { + /** + * @swagger + * /hooks: + * post: + * summary: Creates a new webhook + * tags: + * - webhooks + * externalDocs: + * url: https://docs.cal.com/webhooks + * responses: + * 201: + * description: OK, webhook created + * 400: + * description: Bad request. webhook body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safe = schemaWebhookBodyParams.safeParse(body); + if (!safe.success) throw new Error("Invalid request body"); + + const data = await prisma.webhook.create({ data: { ...safe.data, userId } }); + const webhook = schemaWebhookPublic.parse(data); + + if (data) res.status(201).json({ webhook, message: "Webhook created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new webhook", + error, + }); + } else res.status(405).json({ message: `Method ${method} not allowed` }); +} + +export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllWebhooks); From 4c131fbcdda83950b5e8561e66780262f6767cb0 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 10 May 2022 19:52:59 +0200 Subject: [PATCH 181/658] feat: adds auth/signup for ee customers --- .gitignore | 8 +- auth/README.md | 15 +++ auth/signup.tsx | 182 +++++++++++++++++++++++++++ package.json | 2 +- pages/api/booking-references/[id].ts | 24 +++- pages/api/bookings/[id].ts | 27 +++- pages/api/bookings/index.ts | 30 ++++- tsconfig.json | 2 +- 8 files changed, 280 insertions(+), 10 deletions(-) create mode 100644 auth/README.md create mode 100644 auth/signup.tsx diff --git a/.gitignore b/.gitignore index b93b0f6248..a2c49f1abb 100644 --- a/.gitignore +++ b/.gitignore @@ -72,4 +72,10 @@ dist lint-results # Yarn -yarn-error.log \ No newline at end of file +yarn-error.log + +.turbo +.next +.husky +.vscode +.env \ No newline at end of file diff --git a/auth/README.md b/auth/README.md new file mode 100644 index 0000000000..5b10e7d32a --- /dev/null +++ b/auth/README.md @@ -0,0 +1,15 @@ +# Signup for self-hosted EE + +In order to open the signup, please replace the contents of the file in + +`calcom/apps/web/pages/auth/signup.tsx` + +with the contents of the new file provided here in the @calcom/api repo at the folder: +`/auth/signup.tsx` + +Once you do, if you run your cal.com self-hosted instance and go to: +`http://localhost:3000/auth/signup` + +You should see the signup page, and your users should be able to create new accounts. + +Please, keep in mind this will create git conflict resolutions if you try to git pull from main, where the signup.tsx file will still be different. We will find a better workaround for this soon in order to make it pain free. diff --git a/auth/signup.tsx b/auth/signup.tsx new file mode 100644 index 0000000000..8dc735ddab --- /dev/null +++ b/auth/signup.tsx @@ -0,0 +1,182 @@ +import { GetServerSidePropsContext } from "next"; +import { signIn } from "next-auth/react"; +import { useRouter } from "next/router"; +import { FormProvider, SubmitHandler, useForm } from "react-hook-form"; + +import { useLocale } from "@calcom/lib/hooks/useLocale"; +import { Alert } from "@calcom/ui/Alert"; +import Button from "@calcom/ui/Button"; +import { EmailField, PasswordField, TextField } from "@calcom/ui/form/fields"; +import { HeadSeo } from "@calcom/web/components/seo/head-seo"; +import { asStringOrNull } from "@calcom/web/lib/asStringOrNull"; +import { WEBSITE_URL, WEBAPP_URL } from "@calcom/web/lib/config/constants"; +import prisma from "@calcom/web/lib/prisma"; +import { isSAMLLoginEnabled } from "@calcom/web/lib/saml"; +import { IS_GOOGLE_LOGIN_ENABLED } from "@calcom/web/server/lib/constants"; +import { ssrInit } from "@calcom/web/server/lib/ssr"; + +type FormValues = { + username: string; + email: string; + password: string; + passwordcheck: string; + apiError: string; +}; + +export default function Signup() { + const { t } = useLocale(); + const router = useRouter(); + const methods = useForm(); + const { + register, + formState: { errors, isSubmitting }, + } = methods; + + const handleErrors = async (resp: Response) => { + if (!resp.ok) { + const err = await resp.json(); + throw new Error(err.message); + } + }; + + const signUp: SubmitHandler = async (data) => { + await fetch("/api/auth/signup", { + body: JSON.stringify({ + ...data, + }), + headers: { + "Content-Type": "application/json", + }, + method: "POST", + }) + .then(handleErrors) + .then( + async () => + await signIn("Cal.com", { + callbackUrl: (`${WEBSITE_URL}/${router.query.callbackUrl}` || "") as string, + }) + ) + .catch((err) => { + methods.setError("apiError", { message: err.message }); + }); + }; + + return ( +
+ +
+

+ {t("create_your_account")} +

+
+
+
+ +
+ {errors.apiError && } +
+ + {process.env.NEXT_PUBLIC_WEBSITE_URL}/ + + } + labelProps={{ className: "block text-sm font-medium text-gray-700" }} + className="block w-full min-w-0 flex-grow rounded-none rounded-r-sm border-gray-300 lowercase focus:border-black focus:ring-black sm:text-sm" + {...register("username")} + required + /> + + + + value === methods.watch("password") || (t("error_password_mismatch") as string), + })} + className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-black focus:outline-none focus:ring-black sm:text-sm" + /> +
+
+ + +
+ +
+
+
+
+ ); +} + +export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { + const ssr = await ssrInit(ctx); + const token = asStringOrNull(ctx.query.token); + if (token) { + const verificationToken = await prisma.verificationToken.findUnique({ + where: { + token, + }, + }); + if (verificationToken) { + const existingUser = await prisma.user.findFirst({ + where: { + AND: [ + { + email: verificationToken?.identifier, + }, + { + emailVerified: { + not: null, + }, + }, + ], + }, + }); + + if (existingUser) { + return { + redirect: { + permanent: false, + destination: "/auth/login?callbackUrl=" + `${WEBAPP_URL}/${ctx.query.callbackUrl}`, + }, + }; + } + } + } + + return { + props: { + isGoogleLoginEnabled: IS_GOOGLE_LOGIN_ENABLED, + isSAMLLoginEnabled, + trpcState: ssr.dehydrate(), + }, + }; +}; diff --git a/package.json b/package.json index 5677dc043f..14c34d18af 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "build": "next build", "lint": "next lint", "lint-fix": "next lint --fix && prettier --write .", - "test": "jest --detectOpenHandles", + "test": "jest --detectOpenHandles --passWithNoTests", "type-check": "tsc --pretty --noEmit", "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist" }, diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index d86d0154dc..d1c28b8d04 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -64,11 +64,11 @@ export async function bookingReferenceById( * 404: * description: BookingReference was not found */ - console.log(safeQuery.data.id); + // console.log(safeQuery.data.id); const bookingReference = await prisma.bookingReference.findFirst().catch((error: Error) => { console.log("hoerr:", error); }); - console.log(bookingReference); + // console.log(bookingReference); if (!bookingReference) res.status(404).json({ message: "Booking reference not found" }); else res.status(200).json({ booking_reference: bookingReference }); @@ -92,6 +92,23 @@ export async function bookingReferenceById( * patch: * operationId: editBookingReferenceById * summary: Edit an existing booking reference + * requestBody: + * description: Edit an existing booking reference related to one of your bookings + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * days: + * type: array + * example: email@example.com + * startTime: + * type: string + * example: 1970-01-01T17:00:00.000Z + * endTime: + * type: string + * example: 1970-01-01T17:00:00.000Z * parameters: * - in: path * name: id @@ -112,7 +129,8 @@ export async function bookingReferenceById( const safeBody = schemaBookingEditBodyParams.safeParse(body); if (!safeBody.success) { - res.status(401).json({ message: "Invalid request body", error: safeBody.error }); + console.log(safeBody.error); + res.status(400).json({ message: "Invalid request body", error: safeBody.error }); return; // throw new Error("Invalid request body"); } diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index ff2f40671c..b094df73e9 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -30,6 +30,7 @@ export async function bookingById( * /bookings/{id}: * get: * summary: Find a booking + * operationId: getBookingById * parameters: * - in: path * name: id @@ -64,6 +65,24 @@ export async function bookingById( * /bookings/{id}: * patch: * summary: Edit an existing booking + * operationId: editBookingById + * requestBody: + * description: Edit an existing booking related to one of your event-types + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * title: + * type: string + * example: 15min + * startTime: + * type: string + * example: 1970-01-01T17:00:00.000Z + * endTime: + * type: string + * example: 1970-01-01T17:00:00.000Z * parameters: * - in: path * name: id @@ -84,14 +103,17 @@ export async function bookingById( case "PATCH": const safeBody = schemaBookingEditBodyParams.safeParse(body); if (!safeBody.success) { - throw new Error("Invalid request body"); + console.log(safeBody.error); + res.status(400).json({ message: "Bad request", error: safeBody.error }); + return; + // throw new Error("Invalid request body"); } await prisma.booking .update({ where: { id: safeQuery.data.id }, data: safeBody.data, }) - .then((data) => schemaBookingReadPublic.parse(data)) + // .then((data) => schemaBookingReadPublic.parse(data)) .then((booking) => res.status(200).json({ booking })) .catch((error: Error) => res.status(404).json({ @@ -105,6 +127,7 @@ export async function bookingById( * /bookings/{id}: * delete: * summary: Remove an existing booking + * operationId: removeBookingById * parameters: * - in: path * name: id diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index bd1595ff6c..1ee689b195 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -16,6 +16,7 @@ async function createOrlistAllBookings( * /bookings: * get: * summary: Find all bookings + * operationId: listBookings * tags: * - bookings * responses: @@ -41,6 +42,24 @@ async function createOrlistAllBookings( * /bookings: * post: * summary: Creates a new booking + * operationId: addBooking + * requestBody: + * description: Edit an existing booking related to one of your event-types + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * title: + * type: string + * example: 15min + * startTime: + * type: string + * example: 1970-01-01T17:00:00.000Z + * endTime: + * type: string + * example: 1970-01-01T17:00:00.000Z * tags: * - bookings * responses: @@ -52,18 +71,25 @@ async function createOrlistAllBookings( * description: Authorization information is missing or invalid. */ const safe = schemaBookingCreateBodyParams.safeParse(body); - if (!safe.success) throw new Error("Invalid request body"); + if (!safe.success) { + console.log(safe.error); + res.status(400).json({ message: "Bad request. Booking body is invalid." }); + return; + // throw new Error("Invalid request body"); + } const data = await prisma.booking.create({ data: { ...safe.data, userId } }); const booking = schemaBookingReadPublic.parse(data); if (booking) res.status(201).json({ booking, message: "Booking created successfully" }); else - (error: Error) => + (error: Error) => { + console.log(error); res.status(400).json({ message: "Could not create new booking", error, }); + }; } else res.status(405).json({ message: `Method ${method} not allowed` }); } diff --git a/tsconfig.json b/tsconfig.json index 4943d154a6..5622a85041 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,5 +15,5 @@ "**/*.ts", "**/*.tsx" ], - "exclude": ["node_modules", "templates"] + "exclude": ["node_modules", "templates", "auth"] } From d4086e21b52a2f1f9a0d43df1e6faef2fd6e7e09 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 10 May 2022 19:58:48 +0200 Subject: [PATCH 182/658] Update README.md --- auth/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/auth/README.md b/auth/README.md index 5b10e7d32a..c4c0e5a19d 100644 --- a/auth/README.md +++ b/auth/README.md @@ -2,7 +2,7 @@ In order to open the signup, please replace the contents of the file in -`calcom/apps/web/pages/auth/signup.tsx` +`cal.com/apps/web/pages/auth/signup.tsx` with the contents of the new file provided here in the @calcom/api repo at the folder: `/auth/signup.tsx` From 7deb5f8e1f09f22f39c59aec23981b031cfd662c Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 11 May 2022 15:57:00 +0200 Subject: [PATCH 183/658] fix: webhooks upgraded to new version, need to update templates --- lib/validations/booking.ts | 5 +-- ...-event-reference.ts => event-reference.ts} | 0 lib/validations/webhook.ts | 42 ++++++++++++++++++- pages/api/bookings/index.ts | 5 ++- pages/api/event-references/[id].ts | 5 ++- pages/api/event-references/index.ts | 14 ++++--- pages/api/hooks/[id].ts | 21 ++++------ pages/api/hooks/index.ts | 10 ++--- 8 files changed, 71 insertions(+), 31 deletions(-) rename lib/validations/{daily-event-reference.ts => event-reference.ts} (100%) diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index 60c231efa5..67b4f1b35a 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -14,11 +14,10 @@ const schemaBookingBaseBodyParams = Booking.pick({ const schemaBookingCreateParams = z .object({ uid: z.string(), - userId: z.number(), eventTypeId: z.number(), title: z.string(), - startTime: z.date(), - endTime: z.date(), + startTime: z.date().or(z.string()), + endTime: z.date().or(z.string()), }) .strict(); diff --git a/lib/validations/daily-event-reference.ts b/lib/validations/event-reference.ts similarity index 100% rename from lib/validations/daily-event-reference.ts rename to lib/validations/event-reference.ts diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 40b0731507..0340f8d707 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -1,5 +1,43 @@ +import { z } from "zod"; + import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; -export const schemaWebhookBodyParams = Webhook.omit({ id: true }).partial(); +const schemaWebhookBaseBodyParams = Webhook.pick({ + id: true, + userId: true, + eventTypeId: true, + eventTriggers: true, + active: true, + subscriberUrl: true, + payloadTemplate: true, +}).partial(); -export const schemaWebhookPublic = Webhook.omit({}); +const schemaWebhookCreateParams = z + .object({ + id: z.string(), + subscriberUrl: z.string(), + }) + .strict(); + +export const schemaWebhookCreateBodyParams = schemaWebhookBaseBodyParams.merge(schemaWebhookCreateParams); + +const schemaWebhookEditParams = z + .object({ + uid: z.string().optional(), + title: z.string().optional(), + startTime: z.date().optional(), + endTime: z.date().optional(), + }) + .strict(); + +export const schemaWebhookEditBodyParams = schemaWebhookBaseBodyParams.merge(schemaWebhookEditParams); + +export const schemaWebhookReadPublic = Webhook.pick({ + id: true, + userId: true, + eventTypeId: true, + uid: true, + title: true, + startTime: true, + endTime: true, +}); diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 1ee689b195..00b92932a7 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -10,6 +10,7 @@ async function createOrlistAllBookings( { method, body, userId }: NextApiRequest, res: NextApiResponse ) { + console.log("userIduserId", userId); if (method === "GET") { /** * @swagger @@ -77,8 +78,8 @@ async function createOrlistAllBookings( return; // throw new Error("Invalid request body"); } - - const data = await prisma.booking.create({ data: { ...safe.data, userId } }); + safe.data.userId = userId; + const data = await prisma.booking.create({ data: { ...safe.data } }); const booking = schemaBookingReadPublic.parse(data); if (booking) res.status(201).json({ booking, message: "Booking created successfully" }); diff --git a/pages/api/event-references/[id].ts b/pages/api/event-references/[id].ts index a6a15b9e19..03ee39f49e 100644 --- a/pages/api/event-references/[id].ts +++ b/pages/api/event-references/[id].ts @@ -7,7 +7,7 @@ import type { DailyEventReferenceResponse } from "@lib/types"; import { schemaDailyEventReferenceEditBodyParams, schemaDailyEventReferenceReadPublic, -} from "@lib/validations/daily-event-reference"; +} from "@lib/validations/event-reference"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, @@ -37,6 +37,7 @@ export async function dailyEventReferenceById( * /event-references/{id}: * get: * summary: Find a event reference + * operationId: getEventReferenceById * parameters: * - in: path * name: id @@ -72,6 +73,7 @@ export async function dailyEventReferenceById( * /event-references/{id}: * patch: * summary: Edit an existing event reference + * operationId: editEventReferenceById * parameters: * - in: path * name: id @@ -110,6 +112,7 @@ export async function dailyEventReferenceById( * /event-references/{id}: * delete: * summary: Remove an existing event reference + * operationId: removeEventReferenceById * parameters: * - in: path * name: id diff --git a/pages/api/event-references/index.ts b/pages/api/event-references/index.ts index bc19171de8..e0b18a7919 100644 --- a/pages/api/event-references/index.ts +++ b/pages/api/event-references/index.ts @@ -7,7 +7,7 @@ import { DailyEventReferenceResponse, DailyEventReferencesResponse } from "@lib/ import { schemaDailyEventReferenceCreateBodyParams, schemaDailyEventReferenceReadPublic, -} from "@lib/validations/daily-event-reference"; +} from "@lib/validations/event-reference"; async function createOrlistAllDailyEventReferences( { method, body, userId }: NextApiRequest, @@ -21,7 +21,8 @@ async function createOrlistAllDailyEventReferences( * @swagger * /event-references: * get: - * summary: Find all daily event reference + * summary: Find all event reference + * operationId: listEventReferences * tags: * - event-references * responses: @@ -30,7 +31,7 @@ async function createOrlistAllDailyEventReferences( * 401: * description: Authorization information is missing or invalid. * 404: - * description: No daily event references were found + * description: No event references were found */ const data = await prisma.dailyEventReference.findMany({ where: { bookingId: { in: userBookingIds } }, @@ -50,12 +51,13 @@ async function createOrlistAllDailyEventReferences( * @swagger * /event-references: * post: - * summary: Creates a new daily event reference + * summary: Creates a new event reference + * operationId: addEventReference * tags: * - event-references * responses: * 201: - * description: OK, daily event reference created + * description: OK, event reference created * 400: * description: Bad request. DailyEventReference body is invalid. * 401: @@ -72,7 +74,7 @@ async function createOrlistAllDailyEventReferences( else (error: Error) => res.status(400).json({ - message: "Could not create new daily event reference", + message: "Could not create new event reference", error, }); } else res.status(405).json({ message: `Method ${method} not allowed` }); diff --git a/pages/api/hooks/[id].ts b/pages/api/hooks/[id].ts index c9fcdf346d..59ae3e3516 100644 --- a/pages/api/hooks/[id].ts +++ b/pages/api/hooks/[id].ts @@ -4,17 +4,14 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { WebhookResponse } from "@lib/types"; -import { schemaWebhookBodyParams, schemaWebhookPublic } from "@lib/validations/webhook"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; +import { schemaWebhookEditBodyParams, schemaWebhookReadPublic } from "@lib/validations/webhook"; export async function WebhookById( { method, query, body, userId }: NextApiRequest, res: NextApiResponse ) { - const safeQuery = schemaQueryIdParseInt.safeParse(query); + const safeQuery = schemaQueryIdAsString.safeParse(query); if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); const data = await prisma.webhook.findMany({ where: { userId } }); const userWebhooks = data.map((webhook) => webhook.id); @@ -50,8 +47,8 @@ export async function WebhookById( case "GET": await prisma.webhook .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaWebhookPublic.parse(data)) - .then((hook) => res.status(200).json({ hook })) + .then((data) => schemaWebhookReadPublic.parse(data)) + .then((webhook) => res.status(200).json({ webhook })) .catch((error: Error) => res.status(404).json({ message: `Webhook with id: ${safeQuery.data.id} not found`, @@ -86,14 +83,14 @@ export async function WebhookById( * description: Authorization information is missing or invalid. */ case "PATCH": - const safeBody = schemaWebhookBodyParams.safeParse(body); + const safeBody = schemaWebhookEditBodyParams.safeParse(body); if (!safeBody.success) { throw new Error("Invalid request body"); } await prisma.webhook .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) - .then((data) => schemaWebhookPublic.parse(data)) - .then((hook) => res.status(200).json({ hook })) + .then((data) => schemaWebhookReadPublic.parse(data)) + .then((webhook) => res.status(200).json({ webhook })) .catch((error: Error) => res.status(404).json({ message: `Webhook with id: ${safeQuery.data.id} not found`, @@ -150,4 +147,4 @@ export async function WebhookById( } } -export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(WebhookById)); +export default withMiddleware("HTTP_GET_DELETE_PATCH")(WebhookById); diff --git a/pages/api/hooks/index.ts b/pages/api/hooks/index.ts index 9ff4f441af..9ce8615ea7 100644 --- a/pages/api/hooks/index.ts +++ b/pages/api/hooks/index.ts @@ -4,7 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { WebhookResponse, WebhooksResponse } from "@lib/types"; -import { schemaWebhookBodyParams, schemaWebhookPublic } from "@lib/validations/webhook"; +import { schemaWebhookCreateBodyParams, schemaWebhookReadPublic } from "@lib/validations/webhook"; async function createOrlistAllWebhooks( { method, body, userId }: NextApiRequest, @@ -28,8 +28,8 @@ async function createOrlistAllWebhooks( * 404: * description: No webhooks were found */ - const data = await prisma.webhooks.findMany({ where: { userId } }); - const webhooks = data.map((webhook) => schemaWebhookPublic.parse(webhook)); + const data = await prisma.webhook.findMany({ where: { userId } }); + const webhooks = data.map((webhook) => schemaWebhookReadPublic.parse(webhook)); if (webhooks) res.status(200).json({ webhooks }); else (error: Error) => @@ -55,11 +55,11 @@ async function createOrlistAllWebhooks( * 401: * description: Authorization information is missing or invalid. */ - const safe = schemaWebhookBodyParams.safeParse(body); + const safe = schemaWebhookCreateBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.webhook.create({ data: { ...safe.data, userId } }); - const webhook = schemaWebhookPublic.parse(data); + const webhook = schemaWebhookReadPublic.parse(data); if (data) res.status(201).json({ webhook, message: "Webhook created successfully" }); else From 72444792bc101c45b18a96fda74fe6043a0095d4 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 11 May 2022 16:01:35 +0200 Subject: [PATCH 184/658] fix: disable admin only post endpoint for users as makes build fail until impersonate PR merged into web main/prod --- pages/api/users/index.ts | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 6eea24cb3b..9f80a421d2 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -40,18 +40,19 @@ async function getAllorCreateUser( message: "No Users were found", error, }); - } else if (method === "POST") { - const isAdmin = await prisma.user - .findUnique({ where: { id: userId } }) - .then((user) => user?.role === "ADMIN"); - if (!isAdmin) res.status(401).json({ message: "You are not authorized" }); - else { - const user = await prisma.user.create({ - data: schemaUserReadPublic.parse(body), - }); - res.status(201).json({ user }); - } } + // else if (method === "POST") { + // const isAdmin = await prisma.user + // .findUnique({ where: { id: userId } }) + // .then((user) => user?.role === "ADMIN"); + // if (!isAdmin) res.status(401).json({ message: "You are not authorized" }); + // else { + // const user = await prisma.user.create({ + // data: schemaUserReadPublic.parse(body), + // }); + // res.status(201).json({ user }); + // } + // } } // No POST endpoint for users for now as a regular user you're expected to signup. From 9afbb3d12789122dda820b38dd465a19527aa923 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 16 May 2022 21:59:22 +0200 Subject: [PATCH 185/658] fix: event-type validations move to pick not omit and separate create/edit --- lib/validations/event-type.ts | 51 ++++++++++++++++++++++++++++------ pages/api/event-types/[id].ts | 8 +++--- pages/api/event-types/index.ts | 8 +++--- 3 files changed, 51 insertions(+), 16 deletions(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index e8665a9e3b..40411a7222 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -2,14 +2,49 @@ import { z } from "zod"; import { _EventTypeModel as EventType } from "@calcom/prisma/zod"; -export const schemaEventTypeBaseBodyParams = EventType.omit({ id: true }).partial(); +export const schemaEventTypeBaseBodyParams = EventType.pick({ + title: true, + slug: true, + length: true, +}).partial(); -const schemaEventTypeRequiredParams = z.object({ - title: z.string(), - slug: z.string(), - length: z.number(), +const schemaEventTypeCreateParams = z + .object({ + title: z.string(), + slug: z.string(), + length: z.number(), + }) + .strict(); + +export const schemaEventTypeCreateBodyParams = + schemaEventTypeBaseBodyParams.merge(schemaEventTypeCreateParams); + +const schemaEventTypeEditParams = z + .object({ + token: z.string().optional(), + url: z.string().optional(), + }) + .strict(); + +export const schemaEventTypeEditBodyParams = schemaEventTypeBaseBodyParams.merge(schemaEventTypeEditParams); +export const schemaEventTypeReadPublic = EventType.pick({ + title: true, + slug: true, + length: true, }); -export const schemaEventTypeBodyParams = schemaEventTypeBaseBodyParams.merge(schemaEventTypeRequiredParams); -// @NOTE: Removing locations and metadata properties before validation, add them later if required -export const schemaEventTypePublic = EventType.omit({ locations: true, metadata: true }); +// import { z } from "zod"; + +// import { _EventTypeModel as EventType } from "@calcom/prisma/zod"; + +// export const schemaEventTypeBaseBodyParams = EventType.omit({ id: true }).partial(); + +// const schemaEventTypeRequiredParams = z.object({ +// title: z.string(), +// slug: z.string(), +// length: z.number(), +// }); + +// export const schemaEventTypeBodyParams = schemaEventTypeBaseBodyParams.merge(schemaEventTypeRequiredParams); +// // @NOTE: Removing locations and metadata properties before validation, add them later if required +// export const schemaEventTypePublic = EventType.omit({ locations: true, metadata: true }); diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index a6900b1d27..328e101b28 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -4,7 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { EventTypeResponse } from "@lib/types"; -import { schemaEventTypeBodyParams, schemaEventTypePublic } from "@lib/validations/event-type"; +import { schemaEventTypeEditBodyParams, schemaEventTypeReadPublic } from "@lib/validations/event-type"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, @@ -52,7 +52,7 @@ export async function eventTypeById( case "GET": await prisma.eventType .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaEventTypePublic.parse(data)) + .then((data) => schemaEventTypeReadPublic.parse(data)) .then((event_type) => res.status(200).json({ event_type })) .catch((error: Error) => res.status(404).json({ @@ -89,13 +89,13 @@ export async function eventTypeById( * description: Authorization information is missing or invalid. */ case "PATCH": - const safeBody = schemaEventTypeBodyParams.safeParse(body); + const safeBody = schemaEventTypeEditBodyParams.safeParse(body); if (!safeBody.success) { throw new Error("Invalid request body"); } await prisma.eventType .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) - .then((data) => schemaEventTypePublic.parse(data)) + .then((data) => schemaEventTypeReadPublic.parse(data)) .then((event_type) => res.status(200).json({ event_type })) .catch((error: Error) => res.status(404).json({ diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index dad45eec42..1229785f50 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -4,7 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { EventTypeResponse, EventTypesResponse } from "@lib/types"; -import { schemaEventTypeBodyParams, schemaEventTypePublic } from "@lib/validations/event-type"; +import { schemaEventTypeCreateBodyParams, schemaEventTypeReadPublic } from "@lib/validations/event-type"; async function createOrlistAllEventTypes( { method, body, userId }: NextApiRequest, @@ -29,7 +29,7 @@ async function createOrlistAllEventTypes( * description: No event types were found */ const data = await prisma.eventType.findMany({ where: { userId } }); - const event_types = data.map((eventType) => schemaEventTypePublic.parse(eventType)); + const event_types = data.map((eventType) => schemaEventTypeReadPublic.parse(eventType)); if (event_types) res.status(200).json({ event_types }); else (error: Error) => @@ -55,11 +55,11 @@ async function createOrlistAllEventTypes( * 401: * description: Authorization information is missing or invalid. */ - const safe = schemaEventTypeBodyParams.safeParse(body); + const safe = schemaEventTypeCreateBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); const data = await prisma.eventType.create({ data: { ...safe.data, userId } }); - const event_type = schemaEventTypePublic.parse(data); + const event_type = schemaEventTypeReadPublic.parse(data); if (data) res.status(201).json({ event_type, message: "EventType created successfully" }); else From d8b9bbc4527493f5fa2e8c9a88f62a30073330b4 Mon Sep 17 00:00:00 2001 From: zomars Date: Mon, 16 May 2022 15:06:29 -0600 Subject: [PATCH 186/658] Linting --- README.md | 30 ++++++++++++------------- package.json | 2 +- templates/README.md | 9 ++++---- templates/endpoints/[id]/delete.ts | 2 +- templates/endpoints/[id]/edit.ts | 2 +- templates/endpoints/[id]/index.ts | 2 +- templates/endpoints/get_all_and_post.ts | 8 +++---- templates/endpoints/post.ts | 2 +- types.d.ts | 1 - 9 files changed, 28 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index d210672e53..8c39f8457f 100644 --- a/README.md +++ b/README.md @@ -120,21 +120,21 @@ We aim to provide a fully tested API for our peace of mind, this is accomplished ## Endpoints matrix -| resource | get [id] | get all | create | edit | delete | -| ------------------------ | -------- | ------- | ------ | ---- | ------ | -| attendees | ✅ | ✅ | ✅ | ✅ | ✅ | -| availabilities | ✅ | ✅ | ✅ | ✅ | ✅ | -| booking-references | ✅ | ✅ | ✅ | ✅ | ✅ | -| event-references | ✅ | ✅ | ✅ | ✅ | ✅ | -| destination-calendars | ✅ | ✅ | ✅ | ✅ | ✅ | -| custom-inputs | ✅ | ✅ | ✅ | ✅ | ✅ | -| event-types | ✅ | ✅ | ✅ | ✅ | ✅ | -| memberships | ✅ | ✅ | ✅ | ✅ | ✅ | -| payments | ✅ | ✅ | ❌ | ❌ | ❌ | -| schedules | ✅ | ✅ | ✅ | ✅ | ✅ | -| selected-calendars | ✅ | ✅ | ✅ | ✅ | ✅ | -| teams | ✅ | ✅ | ✅ | ✅ | ✅ | -| users | ✅ | 👤[1] | ✅ | ✅ | ✅ | +| resource | get [id] | get all | create | edit | delete | +| --------------------- | -------- | ------- | ------ | ---- | ------ | +| attendees | ✅ | ✅ | ✅ | ✅ | ✅ | +| availabilities | ✅ | ✅ | ✅ | ✅ | ✅ | +| booking-references | ✅ | ✅ | ✅ | ✅ | ✅ | +| event-references | ✅ | ✅ | ✅ | ✅ | ✅ | +| destination-calendars | ✅ | ✅ | ✅ | ✅ | ✅ | +| custom-inputs | ✅ | ✅ | ✅ | ✅ | ✅ | +| event-types | ✅ | ✅ | ✅ | ✅ | ✅ | +| memberships | ✅ | ✅ | ✅ | ✅ | ✅ | +| payments | ✅ | ✅ | ❌ | ❌ | ❌ | +| schedules | ✅ | ✅ | ✅ | ✅ | ✅ | +| selected-calendars | ✅ | ✅ | ✅ | ✅ | ✅ | +| teams | ✅ | ✅ | ✅ | ✅ | ✅ | +| users | ✅ | 👤[1] | ✅ | ✅ | ✅ | ## Models from database that are not exposed diff --git a/package.json b/package.json index 14c34d18af..555cc3efaf 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "private": true, "scripts": { "dev": "next build && PORT=3002 next start", - "dev-real":"PORT=3002 next dev", + "dev-real": "PORT=3002 next dev", "start": "PORT=3002 next start", "build": "next build", "lint": "next lint", diff --git a/templates/README.md b/templates/README.md index 588797c42a..3a171b9318 100644 --- a/templates/README.md +++ b/templates/README.md @@ -11,10 +11,11 @@ Basically there's three places of the codebase you need to think about for each ## The example resource -model- and it's endpoints ### `pages/api/endpoint/` -| Method | route | action | -| ------ | ----- | ----- | -| GET | pages/api/endpoint/index.ts | Read All of your resource | -| POST |pages/api/endpoint/new.ts | Create new resource | + +| Method | route | action | +| ------ | --------------------------- | ------------------------- | +| GET | pages/api/endpoint/index.ts | Read All of your resource | +| POST | pages/api/endpoint/new.ts | Create new resource | ### `pages/api/endpoint/[id]/` diff --git a/templates/endpoints/[id]/delete.ts b/templates/endpoints/[id]/delete.ts index 79645cbdfd..39e026f418 100644 --- a/templates/endpoints/[id]/delete.ts +++ b/templates/endpoints/[id]/delete.ts @@ -32,7 +32,7 @@ import { * 401: * description: Authorization information is missing or invalid. */ -export async function deleteResource({query}: NextApiRequest, res: NextApiResponse) { +export async function deleteResource({ query }: NextApiRequest, res: NextApiResponse) { const safe = schemaQueryIdParseInt.safeParse(query); if (!safe.success) throw new Error("Invalid request query"); diff --git a/templates/endpoints/[id]/edit.ts b/templates/endpoints/[id]/edit.ts index 8346840ec3..cb4b1f05c5 100644 --- a/templates/endpoints/[id]/edit.ts +++ b/templates/endpoints/[id]/edit.ts @@ -33,7 +33,7 @@ import { * 401: * description: Authorization information is missing or invalid. */ -export async function editResource({query, body}: NextApiRequest, res: NextApiResponse) { +export async function editResource({ query, body }: NextApiRequest, res: NextApiResponse) { const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaResourceBodyParams.safeParse(body); diff --git a/templates/endpoints/[id]/index.ts b/templates/endpoints/[id]/index.ts index 7933c5cab1..da3a2fd2dd 100644 --- a/templates/endpoints/[id]/index.ts +++ b/templates/endpoints/[id]/index.ts @@ -33,7 +33,7 @@ import { * 404: * description: Resource was not found */ -export async function resourceById({query}: NextApiRequest, res: NextApiResponse) { +export async function resourceById({ query }: NextApiRequest, res: NextApiResponse) { const safe = schemaQueryIdParseInt.safeParse(query); if (!safe.success) throw new Error("Invalid request query"); diff --git a/templates/endpoints/get_all_and_post.ts b/templates/endpoints/get_all_and_post.ts index e21dc8bb9d..ba35a7525b 100644 --- a/templates/endpoints/get_all_and_post.ts +++ b/templates/endpoints/get_all_and_post.ts @@ -7,12 +7,11 @@ import { PaymentResponse, PaymentsResponse } from "@lib/types"; import { schemaPaymentBodyParams, schemaPaymentPublic } from "@lib/validations/payment"; async function createOrlistAllPayments( - {method, body}: NextApiRequest, + { method, body }: NextApiRequest, res: NextApiResponse ) { if (method === "GET") { - -/** + /** * @swagger * /v1/payments: * get: @@ -38,8 +37,7 @@ async function createOrlistAllPayments( error, }); } else if (method === "POST") { - -/** + /** * @swagger * /v1/payments: * post: diff --git a/templates/endpoints/post.ts b/templates/endpoints/post.ts index 896c09e691..61cff72a15 100644 --- a/templates/endpoints/post.ts +++ b/templates/endpoints/post.ts @@ -29,7 +29,7 @@ import { schemaResourceBodyParams, schemaResourcePublic, withValidResource } fro * 401: * description: Authorization information is missing or invalid. */ -async function createResource({body}: NextApiRequest, res: NextApiResponse) { +async function createResource({ body }: NextApiRequest, res: NextApiResponse) { const safe = schemaResourceBodyParams.safeParse(body); if (!safe.success) throw new Error("Invalid request body"); diff --git a/types.d.ts b/types.d.ts index 2abf07e4c1..9a7af651d1 100644 --- a/types.d.ts +++ b/types.d.ts @@ -1,2 +1 @@ declare module "modify-response-middleware"; - From 3366627835bc30bd575f625ced5743878fd73b37 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 17 May 2022 14:40:19 +0200 Subject: [PATCH 187/658] fix: event-type params --- lib/validations/event-type.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 40411a7222..aa66cc63dd 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -21,8 +21,9 @@ export const schemaEventTypeCreateBodyParams = const schemaEventTypeEditParams = z .object({ - token: z.string().optional(), - url: z.string().optional(), + title: z.string().optional(), + slug: z.string().optional(), + length: z.number().optional(), }) .strict(); From 5aa0b3744373fc8cd208d2fc4199f3ad820bd91d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 17 May 2022 19:33:18 +0200 Subject: [PATCH 188/658] fix build and pass lint --- README.md | 30 ++++----- lib/validations/event-type.ts | 85 ++++++++++++++++++------ lib/validations/user.ts | 5 ++ package.json | 4 +- pages/api/booking-references/[id].ts | 1 - pages/api/booking-references/index.ts | 10 --- pages/api/bookings/[id].ts | 1 - pages/api/bookings/index.ts | 1 - pages/api/custom-inputs/[id].ts | 5 +- pages/api/custom-inputs/index.ts | 5 +- pages/api/destination-calendars/[id].ts | 5 +- pages/api/destination-calendars/index.ts | 5 +- pages/api/event-references/[id].ts | 5 +- pages/api/event-references/index.ts | 5 +- pages/api/event-types/[id].ts | 5 +- pages/api/event-types/index.ts | 32 ++++++++- pages/api/hooks/[id].ts | 5 +- pages/api/hooks/index.ts | 5 +- pages/api/memberships/[id].ts | 5 +- pages/api/memberships/index.ts | 5 +- pages/api/schedules/[id].ts | 5 +- pages/api/schedules/index.ts | 5 +- pages/api/selected-calendars/[id].ts | 5 +- pages/api/selected-calendars/index.ts | 5 +- pages/api/teams/[id].ts | 5 +- pages/api/teams/index.ts | 5 +- pages/api/users/[id].ts | 2 +- templates/endpoints/get_all_and_post.ts | 5 +- templates/endpoints/post.ts | 5 +- types.d.ts | 1 - 30 files changed, 193 insertions(+), 74 deletions(-) diff --git a/README.md b/README.md index d210672e53..8c39f8457f 100644 --- a/README.md +++ b/README.md @@ -120,21 +120,21 @@ We aim to provide a fully tested API for our peace of mind, this is accomplished ## Endpoints matrix -| resource | get [id] | get all | create | edit | delete | -| ------------------------ | -------- | ------- | ------ | ---- | ------ | -| attendees | ✅ | ✅ | ✅ | ✅ | ✅ | -| availabilities | ✅ | ✅ | ✅ | ✅ | ✅ | -| booking-references | ✅ | ✅ | ✅ | ✅ | ✅ | -| event-references | ✅ | ✅ | ✅ | ✅ | ✅ | -| destination-calendars | ✅ | ✅ | ✅ | ✅ | ✅ | -| custom-inputs | ✅ | ✅ | ✅ | ✅ | ✅ | -| event-types | ✅ | ✅ | ✅ | ✅ | ✅ | -| memberships | ✅ | ✅ | ✅ | ✅ | ✅ | -| payments | ✅ | ✅ | ❌ | ❌ | ❌ | -| schedules | ✅ | ✅ | ✅ | ✅ | ✅ | -| selected-calendars | ✅ | ✅ | ✅ | ✅ | ✅ | -| teams | ✅ | ✅ | ✅ | ✅ | ✅ | -| users | ✅ | 👤[1] | ✅ | ✅ | ✅ | +| resource | get [id] | get all | create | edit | delete | +| --------------------- | -------- | ------- | ------ | ---- | ------ | +| attendees | ✅ | ✅ | ✅ | ✅ | ✅ | +| availabilities | ✅ | ✅ | ✅ | ✅ | ✅ | +| booking-references | ✅ | ✅ | ✅ | ✅ | ✅ | +| event-references | ✅ | ✅ | ✅ | ✅ | ✅ | +| destination-calendars | ✅ | ✅ | ✅ | ✅ | ✅ | +| custom-inputs | ✅ | ✅ | ✅ | ✅ | ✅ | +| event-types | ✅ | ✅ | ✅ | ✅ | ✅ | +| memberships | ✅ | ✅ | ✅ | ✅ | ✅ | +| payments | ✅ | ✅ | ❌ | ❌ | ❌ | +| schedules | ✅ | ✅ | ✅ | ✅ | ✅ | +| selected-calendars | ✅ | ✅ | ✅ | ✅ | ✅ | +| teams | ✅ | ✅ | ✅ | ✅ | ✅ | +| users | ✅ | 👤[1] | ✅ | ✅ | ✅ | ## Models from database that are not exposed diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index aa66cc63dd..25bb87491d 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -1,51 +1,92 @@ import { z } from "zod"; import { _EventTypeModel as EventType } from "@calcom/prisma/zod"; +import { eventTypeLocations, recurringEvent } from "@calcom/prisma/zod-utils"; + +import { jsonSchema } from "./shared/jsonSchema"; export const schemaEventTypeBaseBodyParams = EventType.pick({ title: true, slug: true, length: true, + hidden: true, + position: true, + userId: true, + teamId: true, + eventName: true, + timeZone: true, + periodType: true, + periodStartDate: true, + periodEndDate: true, + periodDays: true, + periodCountCalendarDays: true, + requiresConfirmation: true, + disableGuests: true, + hideCalendarNotes: true, + minimumBookingNotice: true, + beforeEventBuffer: true, + afterEventBuffer: true, + schedulingType: true, + price: true, + currency: true, + slotInterval: true, + metadata: true, + successRedirectUrl: true, }).partial(); -const schemaEventTypeCreateParams = z +const schemaEventTypeBaseParams = z .object({ title: z.string(), slug: z.string(), - length: z.number(), + description: z.string().optional().nullable(), + length: z.number().int(), + locations: jsonSchema, + metadata: jsonSchema, + recurringEvent: jsonSchema, }) .strict(); -export const schemaEventTypeCreateBodyParams = - schemaEventTypeBaseBodyParams.merge(schemaEventTypeCreateParams); +export const schemaEventTypeCreateBodyParams = schemaEventTypeBaseBodyParams.merge(schemaEventTypeBaseParams); const schemaEventTypeEditParams = z .object({ title: z.string().optional(), slug: z.string().optional(), - length: z.number().optional(), + length: z.number().int().optional(), }) .strict(); export const schemaEventTypeEditBodyParams = schemaEventTypeBaseBodyParams.merge(schemaEventTypeEditParams); export const schemaEventTypeReadPublic = EventType.pick({ + id: true, title: true, slug: true, length: true, -}); - -// import { z } from "zod"; - -// import { _EventTypeModel as EventType } from "@calcom/prisma/zod"; - -// export const schemaEventTypeBaseBodyParams = EventType.omit({ id: true }).partial(); - -// const schemaEventTypeRequiredParams = z.object({ -// title: z.string(), -// slug: z.string(), -// length: z.number(), -// }); - -// export const schemaEventTypeBodyParams = schemaEventTypeBaseBodyParams.merge(schemaEventTypeRequiredParams); -// // @NOTE: Removing locations and metadata properties before validation, add them later if required -// export const schemaEventTypePublic = EventType.omit({ locations: true, metadata: true }); + locations: true, + hidden: true, + position: true, + userId: true, + teamId: true, + eventName: true, + timeZone: true, + periodType: true, + periodStartDate: true, + periodEndDate: true, + periodDays: true, + periodCountCalendarDays: true, + requiresConfirmation: true, + recurringEvent: true, + disableGuests: true, + hideCalendarNotes: true, + minimumBookingNotice: true, + beforeEventBuffer: true, + afterEventBuffer: true, + schedulingType: true, + price: true, + currency: true, + slotInterval: true, + metadata: true, + successRedirectUrl: true, +}) + .merge(schemaEventTypeBaseParams) + .partial(); diff --git a/lib/validations/user.ts b/lib/validations/user.ts index b70d52f898..d78d8e23b2 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -4,6 +4,8 @@ import { _UserModel as User } from "@calcom/prisma/zod"; import { timeZone } from "@lib/validations/shared/timeZone"; +import { jsonSchema } from "./shared/jsonSchema"; + // @note: These are the ONLY values allowed as weekStart. So user don't introduce bad data. enum weekdays { MONDAY = "Monday", @@ -57,6 +59,7 @@ export const schemaUserBaseBodyParams = User.pick({ timeZone: true, weekStart: true, endTime: true, + metadata: true, bufferTime: true, theme: true, defaultScheduleId: true, @@ -89,6 +92,7 @@ const schemaUserEditParams = z.object({ .refine((id: number) => id > 0) .optional(), locale: z.nativeEnum(locales).optional(), + metadata: jsonSchema, }); // @note: These are the values that are editable via PATCH method on the user Model, @@ -104,6 +108,7 @@ export const schemaUserReadPublic = User.pick({ emailVerified: true, bio: true, avatar: true, + metadata: true, timeZone: true, weekStart: true, endTime: true, diff --git a/package.json b/package.json index 14c34d18af..143065b933 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,4 @@ - { +{ "name": "@calcom/api", "version": "1.0.0", "description": "Public API for Cal.com", @@ -8,7 +8,7 @@ "private": true, "scripts": { "dev": "next build && PORT=3002 next start", - "dev-real":"PORT=3002 next dev", + "dev-real": "PORT=3002 next dev", "start": "PORT=3002 next start", "build": "next build", "lint": "next lint", diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index d1c28b8d04..8041617bb3 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -132,7 +132,6 @@ export async function bookingReferenceById( console.log(safeBody.error); res.status(400).json({ message: "Invalid request body", error: safeBody.error }); return; - // throw new Error("Invalid request body"); } await prisma.bookingReference .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index 3386d5e42d..58e45d5c9e 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -97,17 +97,7 @@ async function createOrlistAllBookingReferences( if (!safe.success) { res.status(400).json({ message: "Bad request. BookingReference body is invalid", error: safe.error }); return; - // throw new Error("Invalid request body"); } - - const userWithBookings = await prisma.user.findUnique({ - where: { id: userId }, - include: { bookings: true }, - }); - if (!userWithBookings) { - throw new Error("User not found"); - } - const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); if (!safe.data.bookingId) throw new Error("BookingReference: bookingId not found"); if (!userBookingIds.includes(safe.data.bookingId)) res.status(401).json({ message: "Unauthorized" }); else { diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index b094df73e9..b6a37122c1 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -106,7 +106,6 @@ export async function bookingById( console.log(safeBody.error); res.status(400).json({ message: "Bad request", error: safeBody.error }); return; - // throw new Error("Invalid request body"); } await prisma.booking .update({ diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 00b92932a7..40f24283ee 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -76,7 +76,6 @@ async function createOrlistAllBookings( console.log(safe.error); res.status(400).json({ message: "Bad request. Booking body is invalid." }); return; - // throw new Error("Invalid request body"); } safe.data.userId = userId; const data = await prisma.booking.create({ data: { ...safe.data } }); diff --git a/pages/api/custom-inputs/[id].ts b/pages/api/custom-inputs/[id].ts index eb5493235f..8c20771a45 100644 --- a/pages/api/custom-inputs/[id].ts +++ b/pages/api/custom-inputs/[id].ts @@ -105,7 +105,10 @@ async function eventTypeById( case "PATCH": if (!safeBody.success) { - throw new Error("Invalid request body"); + { + res.status(400).json({ message: "Invalid request body" }); + return; + } } await prisma.eventTypeCustomInput .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) diff --git a/pages/api/custom-inputs/index.ts b/pages/api/custom-inputs/index.ts index c7d5f9df90..e1c2d484ed 100644 --- a/pages/api/custom-inputs/index.ts +++ b/pages/api/custom-inputs/index.ts @@ -59,7 +59,10 @@ async function createOrlistAllEventTypeCustomInputs( * description: Authorization information is missing or invalid. */ const safe = schemaEventTypeCustomInputBodyParams.safeParse(body); - if (!safe.success) throw new Error("Invalid request body"); + if (!safe.success) { + res.status(400).json({ message: "Invalid request body" }); + return; + } // Since we're supporting a create or connect relation on eventType, we need to treat them differently // When using connect on event type, check if userId is the owner of the event if (safe.data.eventType.connect && !userEventTypes.includes(safe.data.eventType.connect.id as number)) { diff --git a/pages/api/destination-calendars/[id].ts b/pages/api/destination-calendars/[id].ts index 60e8aae6b3..675f8c2e28 100644 --- a/pages/api/destination-calendars/[id].ts +++ b/pages/api/destination-calendars/[id].ts @@ -121,7 +121,10 @@ export async function destionationCalendarById( */ case "PATCH": if (!safeBody.success) { - throw new Error("Invalid request body"); + { + res.status(400).json({ message: "Invalid request body" }); + return; + } } await prisma.destinationCalendar .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) diff --git a/pages/api/destination-calendars/index.ts b/pages/api/destination-calendars/index.ts index 4006a67c72..bfd7df6d89 100644 --- a/pages/api/destination-calendars/index.ts +++ b/pages/api/destination-calendars/index.ts @@ -57,7 +57,10 @@ async function createOrlistAllDestinationCalendars( * description: Authorization information is missing or invalid. */ const safe = schemaDestinationCalendarCreateBodyParams.safeParse(body); - if (!safe.success) throw new Error("Invalid request body"); + if (!safe.success) { + res.status(400).json({ message: "Invalid request body" }); + return; + } const data = await prisma.destinationCalendar.create({ data: { ...safe.data, userId } }); const destination_calendar = schemaDestinationCalendarReadPublic.parse(data); diff --git a/pages/api/event-references/[id].ts b/pages/api/event-references/[id].ts index 03ee39f49e..97bb53bc82 100644 --- a/pages/api/event-references/[id].ts +++ b/pages/api/event-references/[id].ts @@ -93,7 +93,10 @@ export async function dailyEventReferenceById( */ case "PATCH": if (!safeBody.success) { - throw new Error("Invalid request body"); + { + res.status(400).json({ message: "Invalid request body" }); + return; + } } await prisma.dailyEventReference .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) diff --git a/pages/api/event-references/index.ts b/pages/api/event-references/index.ts index e0b18a7919..48a438e321 100644 --- a/pages/api/event-references/index.ts +++ b/pages/api/event-references/index.ts @@ -64,7 +64,10 @@ async function createOrlistAllDailyEventReferences( * description: Authorization information is missing or invalid. */ const safe = schemaDailyEventReferenceCreateBodyParams.safeParse(body); - if (!safe.success) throw new Error("Invalid request body"); + if (!safe.success) { + res.status(400).json({ message: "Invalid request body" }); + return; + } const data = await prisma.dailyEventReference.create({ data: safe.data }); const daily_event_reference = schemaDailyEventReferenceReadPublic.parse(data); diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 328e101b28..224a7c9995 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -91,7 +91,10 @@ export async function eventTypeById( case "PATCH": const safeBody = schemaEventTypeEditBodyParams.safeParse(body); if (!safeBody.success) { - throw new Error("Invalid request body"); + { + res.status(400).json({ message: "Invalid request body" }); + return; + } } await prisma.eventType .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 1229785f50..163fa501fb 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -16,6 +16,7 @@ async function createOrlistAllEventTypes( * /event-types: * get: * summary: Find all event types + * operationId: listEventTypes * tags: * - event-types * externalDocs: @@ -43,6 +44,32 @@ async function createOrlistAllEventTypes( * /event-types: * post: * summary: Creates a new event type + * operationId: addEventType + * requestBody: + * description: Create a new event-type related to your user or team + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - title + * - slug + * - length + * - metadata + * properties: + * length: + * type: number + * example: 30 + * metadata: + * type: object + * example: {"smartContractAddress": "0x1234567890123456789012345678901234567890"} + * title: + * type: string + * example: My Event + * slug: + * type: string + * example: my-event * tags: * - event-types * externalDocs: @@ -56,7 +83,10 @@ async function createOrlistAllEventTypes( * description: Authorization information is missing or invalid. */ const safe = schemaEventTypeCreateBodyParams.safeParse(body); - if (!safe.success) throw new Error("Invalid request body"); + if (!safe.success) { + res.status(400).json({ message: "Invalid request body", error: safe.error }); + return; + } const data = await prisma.eventType.create({ data: { ...safe.data, userId } }); const event_type = schemaEventTypeReadPublic.parse(data); diff --git a/pages/api/hooks/[id].ts b/pages/api/hooks/[id].ts index 59ae3e3516..cc017d8e8f 100644 --- a/pages/api/hooks/[id].ts +++ b/pages/api/hooks/[id].ts @@ -85,7 +85,10 @@ export async function WebhookById( case "PATCH": const safeBody = schemaWebhookEditBodyParams.safeParse(body); if (!safeBody.success) { - throw new Error("Invalid request body"); + { + res.status(400).json({ message: "Invalid request body" }); + return; + } } await prisma.webhook .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) diff --git a/pages/api/hooks/index.ts b/pages/api/hooks/index.ts index 9ce8615ea7..ccda5dcd76 100644 --- a/pages/api/hooks/index.ts +++ b/pages/api/hooks/index.ts @@ -56,7 +56,10 @@ async function createOrlistAllWebhooks( * description: Authorization information is missing or invalid. */ const safe = schemaWebhookCreateBodyParams.safeParse(body); - if (!safe.success) throw new Error("Invalid request body"); + if (!safe.success) { + res.status(400).json({ message: "Invalid request body" }); + return; + } const data = await prisma.webhook.create({ data: { ...safe.data, userId } }); const webhook = schemaWebhookReadPublic.parse(data); diff --git a/pages/api/memberships/[id].ts b/pages/api/memberships/[id].ts index 0681a629a9..1b9ceaada8 100644 --- a/pages/api/memberships/[id].ts +++ b/pages/api/memberships/[id].ts @@ -97,7 +97,10 @@ export async function membershipById( case "PATCH": const safeBody = schemaMembershipBodyParams.safeParse(body); if (!safeBody.success) { - throw new Error("Invalid request body"); + { + res.status(400).json({ message: "Invalid request body" }); + return; + } } await prisma.membership .update({ diff --git a/pages/api/memberships/index.ts b/pages/api/memberships/index.ts index 2000ed84e3..efd3fb278c 100644 --- a/pages/api/memberships/index.ts +++ b/pages/api/memberships/index.ts @@ -52,7 +52,10 @@ async function createOrlistAllMemberships( * description: Authorization information is missing or invalid. */ const safe = schemaMembershipBodyParams.safeParse(body); - if (!safe.success) throw new Error("Invalid request body"); + if (!safe.success) { + res.status(400).json({ message: "Invalid request body" }); + return; + } const data = await prisma.membership.create({ data: { ...safe.data, userId } }); const membership = schemaMembershipPublic.parse(data); diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index 5b90027ac3..a6e65a87a3 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -83,7 +83,10 @@ export async function scheduleById( */ case "PATCH": if (!safeBody.success) { - throw new Error("Invalid request body"); + { + res.status(400).json({ message: "Invalid request body" }); + return; + } } await prisma.schedule .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index ac002345a3..4421844047 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -54,7 +54,10 @@ async function createOrlistAllSchedules( * description: Authorization information is missing or invalid. */ const safe = schemaScheduleBodyParams.safeParse(body); - if (!safe.success) throw new Error("Invalid request body"); + if (!safe.success) { + res.status(400).json({ message: "Invalid request body" }); + return; + } const data = await prisma.schedule.create({ data: { ...safe.data, userId } }); const schedule = schemaSchedulePublic.parse(data); diff --git a/pages/api/selected-calendars/[id].ts b/pages/api/selected-calendars/[id].ts index 3915332412..5081da3d87 100644 --- a/pages/api/selected-calendars/[id].ts +++ b/pages/api/selected-calendars/[id].ts @@ -115,7 +115,10 @@ export async function selectedCalendarById( */ case "PATCH": if (!safeBody.success) { - throw new Error("Invalid request body"); + { + res.status(400).json({ message: "Invalid request body" }); + return; + } } await prisma.selectedCalendar .update({ diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index e7ccd9d101..f0021f9f0e 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -70,7 +70,10 @@ async function createOrlistAllSelectedCalendars( * description: Authorization information is missing or invalid. */ const safe = schemaSelectedCalendarBodyParams.safeParse(body); - if (!safe.success) throw new Error("Invalid request body"); + if (!safe.success) { + res.status(400).json({ message: "Invalid request body" }); + return; + } // Create new selectedCalendar connecting it to current userId const data = await prisma.selectedCalendar.create({ data: { ...safe.data, user: { connect: { id: userId } } }, diff --git a/pages/api/teams/[id].ts b/pages/api/teams/[id].ts index adbc5e0c12..4c8262efdc 100644 --- a/pages/api/teams/[id].ts +++ b/pages/api/teams/[id].ts @@ -102,7 +102,10 @@ export async function teamById( case "PATCH": if (!safeBody.success) { - throw new Error("Invalid request body"); + { + res.status(400).json({ message: "Invalid request body" }); + return; + } } await prisma.team .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index 5ab45bc21d..e5f870cef6 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -58,7 +58,10 @@ async function createOrlistAllTeams( * description: Authorization information is missing or invalid. */ const safe = schemaTeamBodyParams.safeParse(body); - if (!safe.success) throw new Error("Invalid request body"); + if (!safe.success) { + res.status(400).json({ message: "Invalid request body" }); + return; + } const team = await prisma.team.create({ data: safe.data }); // We're also creating the relation membership of team ownership in this call. const membership = await prisma.membership diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index ffaabcbf4f..b73abaf520 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -104,7 +104,7 @@ export async function userById( const safeBody = schemaUserEditBodyParams.safeParse(body); if (!safeBody.success) { res.status(400).json({ message: "Bad request", error: safeBody.error }); - // throw new Error("Invalid request body"); + return; } const userSchedules = await prisma.schedule.findMany({ diff --git a/templates/endpoints/get_all_and_post.ts b/templates/endpoints/get_all_and_post.ts index e21dc8bb9d..ae099c63ab 100644 --- a/templates/endpoints/get_all_and_post.ts +++ b/templates/endpoints/get_all_and_post.ts @@ -56,7 +56,10 @@ async function createOrlistAllPayments( * description: Authorization information is missing or invalid. */ const safe = schemaPaymentBodyParams.safeParse(body); - if (!safe.success) throw new Error("Invalid request body"); + if (!safe.success) { + res.status(400).json({ message: "Invalid request body" }); + return; + } const payment = await prisma.payment.create({ data: safe.data }); const data = schemaPaymentPublic.parse(payment); diff --git a/templates/endpoints/post.ts b/templates/endpoints/post.ts index 896c09e691..35b3b013eb 100644 --- a/templates/endpoints/post.ts +++ b/templates/endpoints/post.ts @@ -31,7 +31,10 @@ import { schemaResourceBodyParams, schemaResourcePublic, withValidResource } fro */ async function createResource({body}: NextApiRequest, res: NextApiResponse) { const safe = schemaResourceBodyParams.safeParse(body); - if (!safe.success) throw new Error("Invalid request body"); + if (!safe.success) { + res.status(400).json({ message: "Invalid request body" }); + return; + } const resource = await prisma.resource.create({ data: safe.data }); const data = schemaResourcePublic.parse(resource); diff --git a/types.d.ts b/types.d.ts index 2abf07e4c1..9a7af651d1 100644 --- a/types.d.ts +++ b/types.d.ts @@ -1,2 +1 @@ declare module "modify-response-middleware"; - From 29166f1585ad676ccef5a2139a84287ae57a4952 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 17 May 2022 19:43:19 +0200 Subject: [PATCH 189/658] fix: removes unused import in event type validation --- lib/validations/event-type.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 25bb87491d..a23967be76 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -1,7 +1,6 @@ import { z } from "zod"; import { _EventTypeModel as EventType } from "@calcom/prisma/zod"; -import { eventTypeLocations, recurringEvent } from "@calcom/prisma/zod-utils"; import { jsonSchema } from "./shared/jsonSchema"; From 64f5ac5723c0a1d48bb7b29957ea0fc01c837ca8 Mon Sep 17 00:00:00 2001 From: zomars Date: Tue, 17 May 2022 13:17:59 -0600 Subject: [PATCH 190/658] Removed yarn.lock in favor of monorepo --- yarn.lock | 137 ------------------------------------------------------ 1 file changed, 137 deletions(-) delete mode 100644 yarn.lock diff --git a/yarn.lock b/yarn.lock deleted file mode 100644 index bc4aae706e..0000000000 --- a/yarn.lock +++ /dev/null @@ -1,137 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@next/env@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/env/-/env-12.1.0.tgz#73713399399b34aa5a01771fb73272b55b22c314" - integrity sha512-nrIgY6t17FQ9xxwH3jj0a6EOiQ/WDHUos35Hghtr+SWN/ntHIQ7UpuvSi0vaLzZVHQWaDupKI+liO5vANcDeTQ== - -"@next/swc-android-arm64@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-android-arm64/-/swc-android-arm64-12.1.0.tgz#865ba3a9afc204ff2bdeea49dd64d58705007a39" - integrity sha512-/280MLdZe0W03stA69iL+v6I+J1ascrQ6FrXBlXGCsGzrfMaGr7fskMa0T5AhQIVQD4nA/46QQWxG//DYuFBcA== - -"@next/swc-darwin-arm64@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.1.0.tgz#08e8b411b8accd095009ed12efbc2f1d4d547135" - integrity sha512-R8vcXE2/iONJ1Unf5Ptqjk6LRW3bggH+8drNkkzH4FLEQkHtELhvcmJwkXcuipyQCsIakldAXhRbZmm3YN1vXg== - -"@next/swc-darwin-x64@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-12.1.0.tgz#fcd684497a76e8feaca88db3c394480ff0b007cd" - integrity sha512-ieAz0/J0PhmbZBB8+EA/JGdhRHBogF8BWaeqR7hwveb6SYEIJaDNQy0I+ZN8gF8hLj63bEDxJAs/cEhdnTq+ug== - -"@next/swc-linux-arm-gnueabihf@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.1.0.tgz#9ec6380a27938a5799aaa6035c205b3c478468a7" - integrity sha512-njUd9hpl6o6A5d08dC0cKAgXKCzm5fFtgGe6i0eko8IAdtAPbtHxtpre3VeSxdZvuGFh+hb0REySQP9T1ttkog== - -"@next/swc-linux-arm64-gnu@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.1.0.tgz#7f4196dff1049cea479607c75b81033ae2dbd093" - integrity sha512-OqangJLkRxVxMhDtcb7Qn1xjzFA3s50EIxY7mljbSCLybU+sByPaWAHY4px97ieOlr2y4S0xdPKkQ3BCAwyo6Q== - -"@next/swc-linux-arm64-musl@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.1.0.tgz#b445f767569cdc2dddee785ca495e1a88c025566" - integrity sha512-hB8cLSt4GdmOpcwRe2UzI5UWn6HHO/vLkr5OTuNvCJ5xGDwpPXelVkYW/0+C3g5axbDW2Tym4S+MQCkkH9QfWA== - -"@next/swc-linux-x64-gnu@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.1.0.tgz#67610e9be4fbc987de7535f1bcb17e45fe12f90e" - integrity sha512-OKO4R/digvrVuweSw/uBM4nSdyzsBV5EwkUeeG4KVpkIZEe64ZwRpnFB65bC6hGwxIBnTv5NMSnJ+0K/WmG78A== - -"@next/swc-linux-x64-musl@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.1.0.tgz#ea19a23db08a9f2e34ac30401f774cf7d1669d31" - integrity sha512-JohhgAHZvOD3rQY7tlp7NlmvtvYHBYgY0x5ZCecUT6eCCcl9lv6iV3nfu82ErkxNk1H893fqH0FUpznZ/H3pSw== - -"@next/swc-win32-arm64-msvc@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.1.0.tgz#eadf054fc412085659b98e145435bbba200b5283" - integrity sha512-T/3gIE6QEfKIJ4dmJk75v9hhNiYZhQYAoYm4iVo1TgcsuaKLFa+zMPh4056AHiG6n9tn2UQ1CFE8EoybEsqsSw== - -"@next/swc-win32-ia32-msvc@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.1.0.tgz#68faeae10c89f698bf9d28759172b74c9c21bda1" - integrity sha512-iwnKgHJdqhIW19H9PRPM9j55V6RdcOo6rX+5imx832BCWzkDbyomWnlzBfr6ByUYfhohb8QuH4hSGEikpPqI0Q== - -"@next/swc-win32-x64-msvc@12.1.0": - version "12.1.0" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.1.0.tgz#d27e7e76c87a460a4da99c5bfdb1618dcd6cd064" - integrity sha512-aBvcbMwuanDH4EMrL2TthNJy+4nP59Bimn8egqv6GHMVj0a44cU6Au4PjOhLNqEh9l+IpRGBqMTzec94UdC5xg== - -"@types/node@^17.0.21": - version "17.0.21" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.21.tgz#864b987c0c68d07b4345845c3e63b75edd143644" - integrity sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ== - -caniuse-lite@^1.0.30001283: - version "1.0.30001317" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001317.tgz#0548fb28fd5bc259a70b8c1ffdbe598037666a1b" - integrity sha512-xIZLh8gBm4dqNX0gkzrBeyI86J2eCjWzYAs40q88smG844YIrN4tVQl/RhquHvKEKImWWFIVh1Lxe5n1G/N+GQ== - -nanoid@^3.1.30: - version "3.3.1" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" - integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== - -next@^12.1.0: - version "12.1.0" - resolved "https://registry.yarnpkg.com/next/-/next-12.1.0.tgz#c33d753b644be92fc58e06e5a214f143da61dd5d" - integrity sha512-s885kWvnIlxsUFHq9UGyIyLiuD0G3BUC/xrH0CEnH5lHEWkwQcHOORgbDF0hbrW9vr/7am4ETfX4A7M6DjrE7Q== - dependencies: - "@next/env" "12.1.0" - caniuse-lite "^1.0.30001283" - postcss "8.4.5" - styled-jsx "5.0.0" - use-subscription "1.5.1" - optionalDependencies: - "@next/swc-android-arm64" "12.1.0" - "@next/swc-darwin-arm64" "12.1.0" - "@next/swc-darwin-x64" "12.1.0" - "@next/swc-linux-arm-gnueabihf" "12.1.0" - "@next/swc-linux-arm64-gnu" "12.1.0" - "@next/swc-linux-arm64-musl" "12.1.0" - "@next/swc-linux-x64-gnu" "12.1.0" - "@next/swc-linux-x64-musl" "12.1.0" - "@next/swc-win32-arm64-msvc" "12.1.0" - "@next/swc-win32-ia32-msvc" "12.1.0" - "@next/swc-win32-x64-msvc" "12.1.0" - -object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= - -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== - -postcss@8.4.5: - version "8.4.5" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.5.tgz#bae665764dfd4c6fcc24dc0fdf7e7aa00cc77f95" - integrity sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg== - dependencies: - nanoid "^3.1.30" - picocolors "^1.0.0" - source-map-js "^1.0.1" - -source-map-js@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" - integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== - -styled-jsx@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.0.0.tgz#816b4b92e07b1786c6b7111821750e0ba4d26e77" - integrity sha512-qUqsWoBquEdERe10EW8vLp3jT25s/ssG1/qX5gZ4wu15OZpmSMFI2v+fWlRhLfykA5rFtlJ1ME8A8pm/peV4WA== - -use-subscription@1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/use-subscription/-/use-subscription-1.5.1.tgz#73501107f02fad84c6dd57965beb0b75c68c42d1" - integrity sha512-Xv2a1P/yReAjAbhylMfFplFKj9GssgTwN7RlcTxBujFQcloStWNDQdc4g4NRWH9xS4i/FDk04vQBptAXoF3VcA== - dependencies: - object-assign "^4.1.1" From c5fa861d41031674093ba878aea8c17c4adc7ba0 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 17 May 2022 21:45:16 +0200 Subject: [PATCH 191/658] Fix: metadata nullish --- lib/validations/event-type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index a23967be76..85f2500bbc 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -40,7 +40,7 @@ const schemaEventTypeBaseParams = z description: z.string().optional().nullable(), length: z.number().int(), locations: jsonSchema, - metadata: jsonSchema, + metadata: jsonSchema.optional().nullable().or(z.null()), recurringEvent: jsonSchema, }) .strict(); From f55aaf3eaaa29bf881e3e86cacb6ca1e3a7d7bd2 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 17 May 2022 21:51:26 +0200 Subject: [PATCH 192/658] fix: event type make locations metadata and recurringEvent nullable and optional --- lib/validations/event-type.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 85f2500bbc..a5eefab6ca 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -39,9 +39,9 @@ const schemaEventTypeBaseParams = z slug: z.string(), description: z.string().optional().nullable(), length: z.number().int(), - locations: jsonSchema, + locations: jsonSchema.optional().nullable().or(z.null()), metadata: jsonSchema.optional().nullable().or(z.null()), - recurringEvent: jsonSchema, + recurringEvent: jsonSchema.optional().nullable().or(z.null()), }) .strict(); From ad8bfd544e57600aa908af90e58686512840fc43 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 17 May 2022 21:52:55 +0200 Subject: [PATCH 193/658] fix: removes metadata from pick so they dont clash --- lib/validations/event-type.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index a5eefab6ca..be92082cb2 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -29,7 +29,6 @@ export const schemaEventTypeBaseBodyParams = EventType.pick({ price: true, currency: true, slotInterval: true, - metadata: true, successRedirectUrl: true, }).partial(); From a70f80ff6d2c2a3456b772279203c68c1a0499ef Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 17 May 2022 21:57:47 +0200 Subject: [PATCH 194/658] Fix: removes metadata from pick on readPublic for event-type --- lib/validations/event-type.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index be92082cb2..e0ec45dcf2 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -83,7 +83,6 @@ export const schemaEventTypeReadPublic = EventType.pick({ price: true, currency: true, slotInterval: true, - metadata: true, successRedirectUrl: true, }) .merge(schemaEventTypeBaseParams) From f3271f77247c6da91672e30f6b9f0556150711e9 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 17 May 2022 22:03:26 +0200 Subject: [PATCH 195/658] fix: metadata nullish --- lib/validations/event-type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index e0ec45dcf2..6b03597f2a 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -39,7 +39,7 @@ const schemaEventTypeBaseParams = z description: z.string().optional().nullable(), length: z.number().int(), locations: jsonSchema.optional().nullable().or(z.null()), - metadata: jsonSchema.optional().nullable().or(z.null()), + metadata: jsonSchema.optional().nullish(), recurringEvent: jsonSchema.optional().nullable().or(z.null()), }) .strict(); From 8a62c3948d7444c89ed2e5a4325abe8395d023e2 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 17 May 2022 22:09:44 +0200 Subject: [PATCH 196/658] fix: metadata null or json schema --- lib/validations/event-type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 6b03597f2a..eb1a5cc984 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -39,7 +39,7 @@ const schemaEventTypeBaseParams = z description: z.string().optional().nullable(), length: z.number().int(), locations: jsonSchema.optional().nullable().or(z.null()), - metadata: jsonSchema.optional().nullish(), + metadata: z.null().or(jsonSchema), recurringEvent: jsonSchema.optional().nullable().or(z.null()), }) .strict(); From 5072ac7d5218d5e2c2ac8831f58c69c1c1bb77fa Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 17 May 2022 22:13:33 +0200 Subject: [PATCH 197/658] fix: any or null --- lib/validations/event-type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index eb1a5cc984..e5d96ce636 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -39,7 +39,7 @@ const schemaEventTypeBaseParams = z description: z.string().optional().nullable(), length: z.number().int(), locations: jsonSchema.optional().nullable().or(z.null()), - metadata: z.null().or(jsonSchema), + metadata: z.any().optional().nullable().or(z.null()), recurringEvent: jsonSchema.optional().nullable().or(z.null()), }) .strict(); From 4d6dbd39cd1c658e11ce97c1292eacbbf5e9b4b2 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 17 May 2022 22:17:05 +0200 Subject: [PATCH 198/658] fix: dont merge base params --- lib/validations/event-type.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index e5d96ce636..0773368eb0 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -32,7 +32,7 @@ export const schemaEventTypeBaseBodyParams = EventType.pick({ successRedirectUrl: true, }).partial(); -const schemaEventTypeBaseParams = z +// const schemaEventTypeBaseParams = z .object({ title: z.string(), slug: z.string(), @@ -83,7 +83,6 @@ export const schemaEventTypeReadPublic = EventType.pick({ price: true, currency: true, slotInterval: true, + metadata: true, successRedirectUrl: true, -}) - .merge(schemaEventTypeBaseParams) - .partial(); +}).partial(); From b49df1a7aa3c906e69b68f13ddf4ba266e2b3bcf Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 17 May 2022 22:21:00 +0200 Subject: [PATCH 199/658] fix: dont read metadata for now --- lib/validations/event-type.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 0773368eb0..309ab048dc 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -83,6 +83,5 @@ export const schemaEventTypeReadPublic = EventType.pick({ price: true, currency: true, slotInterval: true, - metadata: true, successRedirectUrl: true, }).partial(); From a39d396c8e555d655b1f0c087ab54a6a931002ae Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 17 May 2022 22:25:38 +0200 Subject: [PATCH 200/658] fix: add back commented out base params --- lib/validations/event-type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 309ab048dc..cd4392ce32 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -32,7 +32,7 @@ export const schemaEventTypeBaseBodyParams = EventType.pick({ successRedirectUrl: true, }).partial(); -// const schemaEventTypeBaseParams = z +const schemaEventTypeBaseParams = z .object({ title: z.string(), slug: z.string(), From fa157961bea6aff90647408b7b8ae7d2026a586b Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 17 May 2022 22:32:49 +0200 Subject: [PATCH 201/658] fix: dont parse on read event-type --- lib/validations/event-type.ts | 1 - pages/api/event-types/index.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index cd4392ce32..d341a49f5e 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -39,7 +39,6 @@ const schemaEventTypeBaseParams = z description: z.string().optional().nullable(), length: z.number().int(), locations: jsonSchema.optional().nullable().or(z.null()), - metadata: z.any().optional().nullable().or(z.null()), recurringEvent: jsonSchema.optional().nullable().or(z.null()), }) .strict(); diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 163fa501fb..726895fe6c 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -30,7 +30,7 @@ async function createOrlistAllEventTypes( * description: No event types were found */ const data = await prisma.eventType.findMany({ where: { userId } }); - const event_types = data.map((eventType) => schemaEventTypeReadPublic.parse(eventType)); + const event_types = data.map((eventType) => eventType); if (event_types) res.status(200).json({ event_types }); else (error: Error) => From f2ea38b44008c6faf5be4bcec8fc2d73dffab898 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 17 May 2022 22:37:43 +0200 Subject: [PATCH 202/658] fix: parse metadata --- pages/api/event-types/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 726895fe6c..932a10a11c 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -30,7 +30,7 @@ async function createOrlistAllEventTypes( * description: No event types were found */ const data = await prisma.eventType.findMany({ where: { userId } }); - const event_types = data.map((eventType) => eventType); + const event_types = data.map(({ metadata }) => (metadata = JSON.parse(`${metadata}`))); if (event_types) res.status(200).json({ event_types }); else (error: Error) => From f8554031aecc26c1a8a2280ab9ad0ae794bc8812 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 17 May 2022 22:41:54 +0200 Subject: [PATCH 203/658] fix: pass data directly --- pages/api/event-types/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 932a10a11c..2b97a3b5fc 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -30,8 +30,8 @@ async function createOrlistAllEventTypes( * description: No event types were found */ const data = await prisma.eventType.findMany({ where: { userId } }); - const event_types = data.map(({ metadata }) => (metadata = JSON.parse(`${metadata}`))); - if (event_types) res.status(200).json({ event_types }); + // const event_types = data.map(({ metadata }) => (metadata = JSON.parse(`${metadata}`))); + if (data) res.status(200).json({ event_types: data }); else (error: Error) => res.status(404).json({ From 47ce92714b085b005748a86ccb485e8b91d61d8f Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 17 May 2022 22:49:12 +0200 Subject: [PATCH 204/658] fix rewrite metadata --- pages/api/event-types/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 2b97a3b5fc..cd5e97fc92 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -30,8 +30,8 @@ async function createOrlistAllEventTypes( * description: No event types were found */ const data = await prisma.eventType.findMany({ where: { userId } }); - // const event_types = data.map(({ metadata }) => (metadata = JSON.parse(`${metadata}`))); - if (data) res.status(200).json({ event_types: data }); + const event_types = data.map((eventType) => (eventType.metadata = {})); + if (event_types) res.status(200).json({ event_types }); else (error: Error) => res.status(404).json({ From 075808ce404529dea681344d9f84d8892cbc2e29 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 13:55:05 +0200 Subject: [PATCH 205/658] fix event types --- lib/validations/event-type.ts | 4 +++- pages/api/event-types/index.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index d341a49f5e..34ca8e0a14 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -39,6 +39,7 @@ const schemaEventTypeBaseParams = z description: z.string().optional().nullable(), length: z.number().int(), locations: jsonSchema.optional().nullable().or(z.null()), + metadata: jsonSchema.optional().nullable().or(z.null()), recurringEvent: jsonSchema.optional().nullable().or(z.null()), }) .strict(); @@ -79,8 +80,9 @@ export const schemaEventTypeReadPublic = EventType.pick({ beforeEventBuffer: true, afterEventBuffer: true, schedulingType: true, + metadata: true, price: true, currency: true, slotInterval: true, successRedirectUrl: true, -}).partial(); +}).merge(schemaEventTypeBaseParams); diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index cd5e97fc92..163fa501fb 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -30,7 +30,7 @@ async function createOrlistAllEventTypes( * description: No event types were found */ const data = await prisma.eventType.findMany({ where: { userId } }); - const event_types = data.map((eventType) => (eventType.metadata = {})); + const event_types = data.map((eventType) => schemaEventTypeReadPublic.parse(eventType)); if (event_types) res.status(200).json({ event_types }); else (error: Error) => From a2c7eed853aeaddfcccf331c83e0735ca9fd4240 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 14:03:38 +0200 Subject: [PATCH 206/658] fix: add back metadata true --- lib/validations/event-type.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 34ca8e0a14..3665681dff 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -29,6 +29,7 @@ export const schemaEventTypeBaseBodyParams = EventType.pick({ price: true, currency: true, slotInterval: true, + metadata: true, successRedirectUrl: true, }).partial(); From f04f5d8ca89f2519ba19551f5c414339ed8d6f0d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 14:08:52 +0200 Subject: [PATCH 207/658] fix: add partial() --- lib/validations/event-type.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 3665681dff..2f22c333bb 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -86,4 +86,6 @@ export const schemaEventTypeReadPublic = EventType.pick({ currency: true, slotInterval: true, successRedirectUrl: true, -}).merge(schemaEventTypeBaseParams); +}) + .merge(schemaEventTypeBaseParams) + .partial(); From e183df1a1b45fd7e9891e29eeb43938bfe0757db Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 14:13:29 +0200 Subject: [PATCH 208/658] fix: add back metadata to pick --- lib/validations/event-type.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 2f22c333bb..595217a37a 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -81,7 +81,6 @@ export const schemaEventTypeReadPublic = EventType.pick({ beforeEventBuffer: true, afterEventBuffer: true, schedulingType: true, - metadata: true, price: true, currency: true, slotInterval: true, From 0ca974867497ee062eb9696dc61d494b8d995e00 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 14:27:30 +0200 Subject: [PATCH 209/658] fix: dont throw err on bad query --- pages/api/booking-references/[id].ts | 5 ++++- pages/api/bookings/[id].ts | 5 ++++- pages/api/custom-inputs/[id].ts | 5 ++++- pages/api/destination-calendars/[id].ts | 5 ++++- pages/api/event-references/[id].ts | 5 ++++- pages/api/event-types/[id].ts | 5 ++++- pages/api/hooks/[id].ts | 5 ++++- pages/api/memberships/[id].ts | 5 ++++- pages/api/schedules/[id].ts | 5 ++++- pages/api/selected-calendars/[id].ts | 5 ++++- pages/api/teams/[id].ts | 5 ++++- pages/api/users/[id].ts | 5 ++++- 12 files changed, 48 insertions(+), 12 deletions(-) diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index 8041617bb3..702b77c1a5 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -18,7 +18,10 @@ export async function bookingReferenceById( res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); - if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + if (!safeQuery.success) { + res.status(400).json({ message: "Your query was invalid" }); + return; + } // const userWithBookings = await prisma.user.findUnique({ // where: { id: userId }, // include: { bookings: true }, diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index b6a37122c1..7e17c9613a 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -15,7 +15,10 @@ export async function bookingById( res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); - if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + if (!safeQuery.success) { + res.status(400).json({ message: "Your query was invalid" }); + return; + } const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, diff --git a/pages/api/custom-inputs/[id].ts b/pages/api/custom-inputs/[id].ts index 8c20771a45..7423a10b99 100644 --- a/pages/api/custom-inputs/[id].ts +++ b/pages/api/custom-inputs/[id].ts @@ -77,7 +77,10 @@ async function eventTypeById( ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaEventTypeCustomInputBodyParams.safeParse(body); - if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + if (!safeQuery.success) { + res.status(400).json({ message: "Your query was invalid" }); + return; + } const data = await prisma.eventType.findMany({ where: { userId } }); const userEventTypes = data.map((eventType) => eventType.id); const userEventTypeCustomInputs = await prisma.eventTypeCustomInput.findMany({ diff --git a/pages/api/destination-calendars/[id].ts b/pages/api/destination-calendars/[id].ts index 675f8c2e28..528b9e5f2d 100644 --- a/pages/api/destination-calendars/[id].ts +++ b/pages/api/destination-calendars/[id].ts @@ -19,7 +19,10 @@ export async function destionationCalendarById( ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaDestinationCalendarEditBodyParams.safeParse(body); - if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + if (!safeQuery.success) { + res.status(400).json({ message: "Your query was invalid" }); + return; + } const data = await prisma.destinationCalendar.findMany({ where: { userId } }); const userDestinationCalendars = data.map((destinationCalendar) => destinationCalendar.id); // FIXME: Should we also check ownership of bokingId and eventTypeId to avoid users cross-pollinating other users calendars. diff --git a/pages/api/event-references/[id].ts b/pages/api/event-references/[id].ts index 97bb53bc82..7a72fea4c7 100644 --- a/pages/api/event-references/[id].ts +++ b/pages/api/event-references/[id].ts @@ -19,7 +19,10 @@ export async function dailyEventReferenceById( ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaDailyEventReferenceEditBodyParams.safeParse(body); - if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + if (!safeQuery.success) { + res.status(400).json({ message: "Your query was invalid" }); + return; + } const userBookings = await prisma.booking.findMany({ where: { userId } }); const userBookingIds: number[] = userBookings.map((booking) => booking.id); const userBookingDailyEventReferences = await prisma.dailyEventReference.findMany({ diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 224a7c9995..6319b48b9e 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -15,7 +15,10 @@ export async function eventTypeById( res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); - if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + if (!safeQuery.success) { + res.status(400).json({ message: "Your query was invalid" }); + return; + } const data = await prisma.eventType.findMany({ where: { userId } }); const userEventTypes = data.map((eventType) => eventType.id); if (!userEventTypes.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); diff --git a/pages/api/hooks/[id].ts b/pages/api/hooks/[id].ts index cc017d8e8f..dbdfc1a17e 100644 --- a/pages/api/hooks/[id].ts +++ b/pages/api/hooks/[id].ts @@ -12,7 +12,10 @@ export async function WebhookById( res: NextApiResponse ) { const safeQuery = schemaQueryIdAsString.safeParse(query); - if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + if (!safeQuery.success) { + res.status(400).json({ message: "Your query was invalid" }); + return; + } const data = await prisma.webhook.findMany({ where: { userId } }); const userWebhooks = data.map((webhook) => webhook.id); if (!userWebhooks.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); diff --git a/pages/api/memberships/[id].ts b/pages/api/memberships/[id].ts index 1b9ceaada8..ea99860d14 100644 --- a/pages/api/memberships/[id].ts +++ b/pages/api/memberships/[id].ts @@ -12,7 +12,10 @@ export async function membershipById( res: NextApiResponse ) { const safeQuery = schemaQueryIdAsString.safeParse(query); - if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + if (!safeQuery.success) { + res.status(400).json({ message: "Your query was invalid" }); + return; + } // This is how we set the userId and teamId in the query for managing compoundId. const [paramUserId, teamId] = safeQuery.data.id.split("_"); if (parseInt(paramUserId) !== userId) res.status(401).json({ message: "Unauthorized" }); diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index a6e65a87a3..305cc5c51b 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -16,7 +16,10 @@ export async function scheduleById( ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaScheduleBodyParams.safeParse(body); - if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + if (!safeQuery.success) { + res.status(400).json({ message: "Your query was invalid" }); + return; + } const userSchedules = await prisma.schedule.findMany({ where: { userId } }); const userScheduleIds = userSchedules.map((schedule) => schedule.id); if (!userScheduleIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); diff --git a/pages/api/selected-calendars/[id].ts b/pages/api/selected-calendars/[id].ts index 5081da3d87..88dca61806 100644 --- a/pages/api/selected-calendars/[id].ts +++ b/pages/api/selected-calendars/[id].ts @@ -16,7 +16,10 @@ export async function selectedCalendarById( ) { const safeQuery = schemaQueryIdAsString.safeParse(query); const safeBody = schemaSelectedCalendarBodyParams.safeParse(body); - if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + if (!safeQuery.success) { + res.status(400).json({ message: "Your query was invalid" }); + return; + } // This is how we set the userId and externalId in the query for managing compoundId. const [paramUserId, integration, externalId] = safeQuery.data.id.split("_"); if (userId !== parseInt(paramUserId)) res.status(401).json({ message: "Unauthorized" }); diff --git a/pages/api/teams/[id].ts b/pages/api/teams/[id].ts index 4c8262efdc..2cfd371749 100644 --- a/pages/api/teams/[id].ts +++ b/pages/api/teams/[id].ts @@ -77,7 +77,10 @@ export async function teamById( ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaTeamBodyParams.safeParse(body); - if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + if (!safeQuery.success) { + res.status(400).json({ message: "Your query was invalid" }); + return; + } const userWithMemberships = await prisma.membership.findMany({ where: { userId: userId }, }); diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index b73abaf520..7539d513b8 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -16,7 +16,10 @@ export async function userById( ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); console.log(body); - if (!safeQuery.success) throw new Error("Invalid request query", safeQuery.error); + if (!safeQuery.success) { + res.status(400).json({ message: "Your query was invalid" }); + return; + } if (safeQuery.data.id !== userId) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { From 8481a96829dad81fa0fab32c3b04c2f35f3ff811 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 14:41:55 +0200 Subject: [PATCH 210/658] fix: null or --- lib/validations/event-type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 595217a37a..28dd76cf11 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -40,7 +40,7 @@ const schemaEventTypeBaseParams = z description: z.string().optional().nullable(), length: z.number().int(), locations: jsonSchema.optional().nullable().or(z.null()), - metadata: jsonSchema.optional().nullable().or(z.null()), + metadata: z.null().or(jsonSchema).optional().nullable(), recurringEvent: jsonSchema.optional().nullable().or(z.null()), }) .strict(); From 91f9405fa0f1b11e32c95871a8d5c1654e3fe230 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 14:48:11 +0200 Subject: [PATCH 211/658] fix: metadata --- lib/validations/event-type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 28dd76cf11..10e3e85fb3 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -40,7 +40,7 @@ const schemaEventTypeBaseParams = z description: z.string().optional().nullable(), length: z.number().int(), locations: jsonSchema.optional().nullable().or(z.null()), - metadata: z.null().or(jsonSchema).optional().nullable(), + metadata: jsonSchema.optional().nullable().nullish(), recurringEvent: jsonSchema.optional().nullable().or(z.null()), }) .strict(); From 8add68c668ff0e8a21087bb0ea2cedb74ea8475f Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 14:55:05 +0200 Subject: [PATCH 212/658] fix: no metadata-true --- lib/validations/event-type.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 10e3e85fb3..72af352afe 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -29,11 +29,10 @@ export const schemaEventTypeBaseBodyParams = EventType.pick({ price: true, currency: true, slotInterval: true, - metadata: true, successRedirectUrl: true, }).partial(); -const schemaEventTypeBaseParams = z +const schemaEventTypeCreateParams = z .object({ title: z.string(), slug: z.string(), @@ -45,7 +44,8 @@ const schemaEventTypeBaseParams = z }) .strict(); -export const schemaEventTypeCreateBodyParams = schemaEventTypeBaseBodyParams.merge(schemaEventTypeBaseParams); +export const schemaEventTypeCreateBodyParams = + schemaEventTypeBaseBodyParams.merge(schemaEventTypeCreateParams); const schemaEventTypeEditParams = z .object({ @@ -86,5 +86,5 @@ export const schemaEventTypeReadPublic = EventType.pick({ slotInterval: true, successRedirectUrl: true, }) - .merge(schemaEventTypeBaseParams) + .merge(schemaEventTypeCreateParams) .partial(); From db09aeb50ad5530aeb929777f5cecc714b261b59 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 15:00:09 +0200 Subject: [PATCH 213/658] fix: dont merge on read --- lib/validations/event-type.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 72af352afe..4404390a43 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -85,6 +85,4 @@ export const schemaEventTypeReadPublic = EventType.pick({ currency: true, slotInterval: true, successRedirectUrl: true, -}) - .merge(schemaEventTypeCreateParams) - .partial(); +}).partial(); From e25d0d79a07ec7f002c94a41bc44721b3ac6f5bb Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 15:04:44 +0200 Subject: [PATCH 214/658] fix: merge metadata jsonSchema nullable nullish --- lib/validations/event-type.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 4404390a43..69fd0173ca 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -85,4 +85,6 @@ export const schemaEventTypeReadPublic = EventType.pick({ currency: true, slotInterval: true, successRedirectUrl: true, -}).partial(); +}) + .merge(z.object({ metadata: jsonSchema.nullable().nullish() })) + .partial(); From c5dcf428075556acb5438cbcc8a1c80f8a2e8a80 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 15:12:29 +0200 Subject: [PATCH 215/658] fix: any --- lib/validations/event-type.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 69fd0173ca..48382ecc3a 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -39,7 +39,7 @@ const schemaEventTypeCreateParams = z description: z.string().optional().nullable(), length: z.number().int(), locations: jsonSchema.optional().nullable().or(z.null()), - metadata: jsonSchema.optional().nullable().nullish(), + metadata: z.any().optional().nullable().nullish(), recurringEvent: jsonSchema.optional().nullable().or(z.null()), }) .strict(); @@ -86,5 +86,5 @@ export const schemaEventTypeReadPublic = EventType.pick({ slotInterval: true, successRedirectUrl: true, }) - .merge(z.object({ metadata: jsonSchema.nullable().nullish() })) + .merge(z.object({ metadata: z.any().nullable().nullish() })) .partial(); From d5ecb383b41cb29aa7f6a24855a3bfea73a91f32 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 15:16:16 +0200 Subject: [PATCH 216/658] fix: no metadata --- lib/validations/event-type.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 48382ecc3a..944ab837ae 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -85,6 +85,4 @@ export const schemaEventTypeReadPublic = EventType.pick({ currency: true, slotInterval: true, successRedirectUrl: true, -}) - .merge(z.object({ metadata: z.any().nullable().nullish() })) - .partial(); +}).partial(); From f29124866c58cca95e8219a5f2c495ca7e5935b7 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 15:23:18 +0200 Subject: [PATCH 217/658] fix: recurring and metadata as jsonSchema on read too --- lib/validations/event-type.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 944ab837ae..3357c53794 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -85,4 +85,12 @@ export const schemaEventTypeReadPublic = EventType.pick({ currency: true, slotInterval: true, successRedirectUrl: true, -}).partial(); + description: true, +}) + .merge( + z.object({ + recurringEvent: jsonSchema.nullable(), + metadata: jsonSchema.nullable(), + }) + ) + .strict(); From b237d71b2b53292028b123066a5a011547fefe5f Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 17:46:22 +0200 Subject: [PATCH 218/658] fix: event type jsonschema or znull --- lib/validations/shared/jsonSchema.ts | 2 +- pages/api/hooks/[id].ts | 3 +++ pages/api/hooks/index.ts | 2 ++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/validations/shared/jsonSchema.ts b/lib/validations/shared/jsonSchema.ts index bfc7ae1f2b..826f0b6250 100644 --- a/lib/validations/shared/jsonSchema.ts +++ b/lib/validations/shared/jsonSchema.ts @@ -5,5 +5,5 @@ type Literal = boolean | number | string; type Json = Literal | { [key: string]: Json } | Json[]; const literalSchema = z.union([z.string(), z.number(), z.boolean()]); export const jsonSchema: z.ZodSchema = z.lazy(() => - z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)]) + z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)]).or(z.null()) ); diff --git a/pages/api/hooks/[id].ts b/pages/api/hooks/[id].ts index dbdfc1a17e..32a81e7b12 100644 --- a/pages/api/hooks/[id].ts +++ b/pages/api/hooks/[id].ts @@ -26,6 +26,7 @@ export async function WebhookById( * /hooks/{id}: * get: * summary: Find a webhook + * operationId: getWebhookById * parameters: * - in: path * name: id @@ -64,6 +65,7 @@ export async function WebhookById( * /hooks/{id}: * patch: * summary: Edit an existing webhook + * operationId: editWebhookById * parameters: * - in: path * name: id @@ -109,6 +111,7 @@ export async function WebhookById( * /hooks/{id}: * delete: * summary: Remove an existing hook + * operationId: removeWebhookById * parameters: * - in: path * name: id diff --git a/pages/api/hooks/index.ts b/pages/api/hooks/index.ts index ccda5dcd76..0a81da7ec5 100644 --- a/pages/api/hooks/index.ts +++ b/pages/api/hooks/index.ts @@ -16,6 +16,7 @@ async function createOrlistAllWebhooks( * /hooks: * get: * summary: Find all webhooks + * operationId: listWebhooks * tags: * - hooks * externalDocs: @@ -43,6 +44,7 @@ async function createOrlistAllWebhooks( * /hooks: * post: * summary: Creates a new webhook + * operationId: addWebhook * tags: * - webhooks * externalDocs: From 93b2e961443f9f0c417efdd055a369a90026001a Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 18:51:19 +0200 Subject: [PATCH 219/658] fix: dont overdo validation on read event-type --- lib/validations/event-type.ts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 3357c53794..53fbcb620f 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -86,11 +86,4 @@ export const schemaEventTypeReadPublic = EventType.pick({ slotInterval: true, successRedirectUrl: true, description: true, -}) - .merge( - z.object({ - recurringEvent: jsonSchema.nullable(), - metadata: jsonSchema.nullable(), - }) - ) - .strict(); +}); From b95c0648286c46ba8c242aefe4bd30026a7c9352 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 18:58:37 +0200 Subject: [PATCH 220/658] fix: metadata zany --- lib/validations/event-type.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 53fbcb620f..92f7c42f56 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -86,4 +86,4 @@ export const schemaEventTypeReadPublic = EventType.pick({ slotInterval: true, successRedirectUrl: true, description: true, -}); +}).merge(z.object({ metadata: z.any() })); From b7f9791439bad77c31fe9855127f8fe3adde6d00 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 19:00:27 +0200 Subject: [PATCH 221/658] fix: add locations any too --- lib/validations/event-type.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 92f7c42f56..f436757ef2 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -61,7 +61,6 @@ export const schemaEventTypeReadPublic = EventType.pick({ title: true, slug: true, length: true, - locations: true, hidden: true, position: true, userId: true, @@ -86,4 +85,4 @@ export const schemaEventTypeReadPublic = EventType.pick({ slotInterval: true, successRedirectUrl: true, description: true, -}).merge(z.object({ metadata: z.any() })); +}).merge(z.object({ metadata: z.any(), locations: z.any() })); From 957d6d2375c092878be05a96fb0f8866bc916871 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 19:10:16 +0200 Subject: [PATCH 222/658] fix: locations or z null --- lib/validations/event-type.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index f436757ef2..53947aad5b 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -38,8 +38,8 @@ const schemaEventTypeCreateParams = z slug: z.string(), description: z.string().optional().nullable(), length: z.number().int(), - locations: jsonSchema.optional().nullable().or(z.null()), - metadata: z.any().optional().nullable().nullish(), + // locations: jsonSchema.optional().nullable().or(z.null()), + // metadata: z.any().optional().nullable().nullish(), recurringEvent: jsonSchema.optional().nullable().or(z.null()), }) .strict(); @@ -85,4 +85,4 @@ export const schemaEventTypeReadPublic = EventType.pick({ slotInterval: true, successRedirectUrl: true, description: true, -}).merge(z.object({ metadata: z.any(), locations: z.any() })); +}).merge(z.object({ metadata: z.any(), locations: jsonSchema.or(z.null()) })); From 35ebf53f19352e69cb25c2053cc9d8f14496e2c5 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 19:21:48 +0200 Subject: [PATCH 223/658] fix: json validation --- lib/validations/event-type.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 53947aad5b..770d570cfd 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -38,8 +38,8 @@ const schemaEventTypeCreateParams = z slug: z.string(), description: z.string().optional().nullable(), length: z.number().int(), - // locations: jsonSchema.optional().nullable().or(z.null()), - // metadata: z.any().optional().nullable().nullish(), + locations: jsonSchema.optional().nullable().or(z.null()), + metadata: z.any().optional().nullable().or(z.null()), recurringEvent: jsonSchema.optional().nullable().or(z.null()), }) .strict(); @@ -85,4 +85,10 @@ export const schemaEventTypeReadPublic = EventType.pick({ slotInterval: true, successRedirectUrl: true, description: true, -}).merge(z.object({ metadata: z.any(), locations: jsonSchema.or(z.null()) })); +}).merge( + z.object({ + locations: jsonSchema.optional().nullable().or(z.null()), + metadata: z.any().optional().nullable().or(z.null()), + recurringEvent: jsonSchema.optional().nullable().or(z.null()), + }) +); From eb03188d78fefdc42ac9be7ce17073d072be2754 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 19:25:50 +0200 Subject: [PATCH 224/658] fix: dont validate read event-type --- pages/api/event-types/[id].ts | 2 +- pages/api/event-types/index.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 6319b48b9e..19ca5e0cbb 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -55,7 +55,7 @@ export async function eventTypeById( case "GET": await prisma.eventType .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaEventTypeReadPublic.parse(data)) + // .then((data) => schemaEventTypeReadPublic.parse(data)) .then((event_type) => res.status(200).json({ event_type })) .catch((error: Error) => res.status(404).json({ diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 163fa501fb..4570934b17 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -30,8 +30,8 @@ async function createOrlistAllEventTypes( * description: No event types were found */ const data = await prisma.eventType.findMany({ where: { userId } }); - const event_types = data.map((eventType) => schemaEventTypeReadPublic.parse(eventType)); - if (event_types) res.status(200).json({ event_types }); + // const event_types = data.map((eventType) => schemaEventTypeReadPublic.parse(eventType)); + if (data) res.status(200).json({ event_types: data }); else (error: Error) => res.status(404).json({ From 5c97283aa188a050c20e12b37c52e4d6fa9f689a Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 19:39:31 +0200 Subject: [PATCH 225/658] fix: dont add locations/metadata on create event type --- lib/validations/event-type.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 770d570cfd..2eb3d88774 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -38,8 +38,8 @@ const schemaEventTypeCreateParams = z slug: z.string(), description: z.string().optional().nullable(), length: z.number().int(), - locations: jsonSchema.optional().nullable().or(z.null()), - metadata: z.any().optional().nullable().or(z.null()), + // locations: jsonSchema.optional().nullable().or(z.null()), + // metadata: z.any().optional().nullable().or(z.null()), recurringEvent: jsonSchema.optional().nullable().or(z.null()), }) .strict(); @@ -85,10 +85,4 @@ export const schemaEventTypeReadPublic = EventType.pick({ slotInterval: true, successRedirectUrl: true, description: true, -}).merge( - z.object({ - locations: jsonSchema.optional().nullable().or(z.null()), - metadata: z.any().optional().nullable().or(z.null()), - recurringEvent: jsonSchema.optional().nullable().or(z.null()), - }) -); +}); From 7b90ccb3bffb18161ea98ce27538b4ac0b0724c9 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 19:49:42 +0200 Subject: [PATCH 226/658] fix: add locations to event type in response types --- lib/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/types.ts b/lib/types.ts index cc3f95d7e8..526950d121 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -127,7 +127,7 @@ export type EventTypeCustomInputsResponse = BaseResponse & { // EventType export type EventTypeResponse = BaseResponse & { - event_type?: Partial; + event_type?: Partial; }; export type EventTypesResponse = BaseResponse & { event_types?: Partial[]; From e7a7c89071089878c6a43b693fa6272d593d5612 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 19:51:40 +0200 Subject: [PATCH 227/658] fix add locations metadata and recurring events to eventtype response --- lib/types.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/types.ts b/lib/types.ts index 526950d121..58d4b17a9c 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -124,13 +124,17 @@ export type EventTypeCustomInputResponse = BaseResponse & { export type EventTypeCustomInputsResponse = BaseResponse & { event_type_custom_inputs?: Partial[]; }; - +export type EventTypeWithMetadataLocations = EventType & { + locations?: object; + metadata?: object; + recurringEvent?: object; +}; // EventType export type EventTypeResponse = BaseResponse & { - event_type?: Partial; + event_type?: Partial; }; export type EventTypesResponse = BaseResponse & { - event_types?: Partial[]; + event_types?: Partial[]; }; // Payment From 37069e2d7b4d00046a351ad2a1cda999c03ec8df Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 20:22:43 +0200 Subject: [PATCH 228/658] fix: omit metadata/locations and rewrite as json --- lib/types.ts | 14 +++++++------- lib/validations/event-type.ts | 6 ++++-- pages/api/event-types/[id].ts | 2 +- pages/api/event-types/index.ts | 4 ++-- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/lib/types.ts b/lib/types.ts index 58d4b17a9c..574e164e29 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -124,17 +124,17 @@ export type EventTypeCustomInputResponse = BaseResponse & { export type EventTypeCustomInputsResponse = BaseResponse & { event_type_custom_inputs?: Partial[]; }; -export type EventTypeWithMetadataLocations = EventType & { - locations?: object; - metadata?: object; - recurringEvent?: object; -}; +export interface EventTypeMeta extends Omit { + locations?: JSON; + metadata?: JSON; + recurringEvent: JSON; +} // EventType export type EventTypeResponse = BaseResponse & { - event_type?: Partial; + event_type?: Partial; }; export type EventTypesResponse = BaseResponse & { - event_types?: Partial[]; + event_types?: Partial[]; }; // Payment diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 2eb3d88774..6b43a4474a 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -38,8 +38,8 @@ const schemaEventTypeCreateParams = z slug: z.string(), description: z.string().optional().nullable(), length: z.number().int(), - // locations: jsonSchema.optional().nullable().or(z.null()), - // metadata: z.any().optional().nullable().or(z.null()), + locations: jsonSchema.optional().nullable().or(z.null()), + metadata: z.any().optional().nullable().or(z.null()), recurringEvent: jsonSchema.optional().nullable().or(z.null()), }) .strict(); @@ -85,4 +85,6 @@ export const schemaEventTypeReadPublic = EventType.pick({ slotInterval: true, successRedirectUrl: true, description: true, + locations: true, + metadata: true, }); diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 19ca5e0cbb..6319b48b9e 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -55,7 +55,7 @@ export async function eventTypeById( case "GET": await prisma.eventType .findUnique({ where: { id: safeQuery.data.id } }) - // .then((data) => schemaEventTypeReadPublic.parse(data)) + .then((data) => schemaEventTypeReadPublic.parse(data)) .then((event_type) => res.status(200).json({ event_type })) .catch((error: Error) => res.status(404).json({ diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 4570934b17..163fa501fb 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -30,8 +30,8 @@ async function createOrlistAllEventTypes( * description: No event types were found */ const data = await prisma.eventType.findMany({ where: { userId } }); - // const event_types = data.map((eventType) => schemaEventTypeReadPublic.parse(eventType)); - if (data) res.status(200).json({ event_types: data }); + const event_types = data.map((eventType) => schemaEventTypeReadPublic.parse(eventType)); + if (event_types) res.status(200).json({ event_types }); else (error: Error) => res.status(404).json({ From 5bb2c54648860bd8864ae1398e4f51e9c19c6ffc Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 20:29:35 +0200 Subject: [PATCH 229/658] fix: add fallback for keys generated with cal_ instead of cal_live_ prefix --- lib/helpers/verifyApiKey.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index cf5c4a8472..6026106231 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -23,7 +23,10 @@ export const dateNotInPast = function (date: Date) { export const verifyApiKey: NextMiddleware = async (req, res, next) => { if (!req.query.apiKey) return res.status(401).json({ message: "No apiKey provided" }); // We remove the prefix from the user provided api_key. If no env set default to "cal_" - const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "cal_", ""); + let strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX, ""); + strippedApiKey = strippedApiKey.includes("cal_") + ? strippedApiKey.replace("cal_", "") + : strippedApiKey; // Hash the key again before matching against the database records. const hashedKey = hashAPIKey(strippedApiKey); // Check if the hashed api key exists in database. From 27053e7c8075c7ddea1cbd098357b2609d8894dd Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 21:48:13 +0200 Subject: [PATCH 230/658] fix: dont replace cal_ --- lib/helpers/verifyApiKey.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 6026106231..cf5c4a8472 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -23,10 +23,7 @@ export const dateNotInPast = function (date: Date) { export const verifyApiKey: NextMiddleware = async (req, res, next) => { if (!req.query.apiKey) return res.status(401).json({ message: "No apiKey provided" }); // We remove the prefix from the user provided api_key. If no env set default to "cal_" - let strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX, ""); - strippedApiKey = strippedApiKey.includes("cal_") - ? strippedApiKey.replace("cal_", "") - : strippedApiKey; + const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "cal_", ""); // Hash the key again before matching against the database records. const hashedKey = hashAPIKey(strippedApiKey); // Check if the hashed api key exists in database. From df16126a49ccd8af5ba92ba9978fbab59ede2e4b Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 21:50:34 +0200 Subject: [PATCH 231/658] fix: object or null instead of json for extends event-types --- lib/types.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/types.ts b/lib/types.ts index 574e164e29..13670a0408 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -125,9 +125,9 @@ export type EventTypeCustomInputsResponse = BaseResponse & { event_type_custom_inputs?: Partial[]; }; export interface EventTypeMeta extends Omit { - locations?: JSON; - metadata?: JSON; - recurringEvent: JSON; + locations: object | null; + metadata: object | null; + recurringEvent: object | null; } // EventType export type EventTypeResponse = BaseResponse & { From 26888a36301d91404a4ac4fa86836bee5e93f3c0 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 18 May 2022 22:03:36 +0200 Subject: [PATCH 232/658] fix typeof schemaEventTypeReadPublic --- lib/types.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/types.ts b/lib/types.ts index 13670a0408..edd5b9f6c9 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -1,10 +1,8 @@ import { User, - ApiKey, Team, Credential, SelectedCalendar, - EventType, EventTypeCustomInput, Attendee, Availability, @@ -19,6 +17,8 @@ import { ReminderMail, } from "@calcom/prisma/client"; +import { schemaEventTypeReadPublic } from "@lib/validations/event-type"; + // Base response, used for all responses export type BaseResponse = { message?: string; @@ -124,17 +124,13 @@ export type EventTypeCustomInputResponse = BaseResponse & { export type EventTypeCustomInputsResponse = BaseResponse & { event_type_custom_inputs?: Partial[]; }; -export interface EventTypeMeta extends Omit { - locations: object | null; - metadata: object | null; - recurringEvent: object | null; -} + // EventType export type EventTypeResponse = BaseResponse & { - event_type?: Partial; + event_type?: Partial; }; export type EventTypesResponse = BaseResponse & { - event_types?: Partial[]; + event_types?: Partial[]; }; // Payment From 74efa1f86ee259e6ca0e4f4535d10b57f32bab75 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 19 May 2022 16:35:25 +0530 Subject: [PATCH 233/658] Updates Webhook pick --- lib/validations/webhook.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 0340f8d707..fe9fe1533a 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -36,8 +36,9 @@ export const schemaWebhookReadPublic = Webhook.pick({ id: true, userId: true, eventTypeId: true, - uid: true, - title: true, - startTime: true, - endTime: true, + payloadTemplate: true, + eventTriggers: true, + eventType: true, + app: true, + appId: true, }); From bc844f29bacb09d817eed14d53f49773ec2e0850 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 19 May 2022 16:38:44 +0530 Subject: [PATCH 234/658] Updates Webhook edit params --- lib/validations/webhook.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index fe9fe1533a..a543fcfec1 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -23,10 +23,9 @@ export const schemaWebhookCreateBodyParams = schemaWebhookBaseBodyParams.merge(s const schemaWebhookEditParams = z .object({ - uid: z.string().optional(), - title: z.string().optional(), - startTime: z.date().optional(), - endTime: z.date().optional(), + payloadTemplate: z.string().optional(), + eventTriggers: z.string().optional(), + subscriberUrl: z.date().optional(), }) .strict(); From 95a1e32454fd728a826b36553af278f05c9d5f76 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 19 May 2022 16:40:27 +0530 Subject: [PATCH 235/658] Fixes subscriber URL z type --- lib/validations/webhook.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index a543fcfec1..dc8f8bb41f 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -25,7 +25,7 @@ const schemaWebhookEditParams = z .object({ payloadTemplate: z.string().optional(), eventTriggers: z.string().optional(), - subscriberUrl: z.date().optional(), + subscriberUrl: z.string().optional(), }) .strict(); From fdc46fac7d73e2271441b99fc4382f8fad7382ef Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 19 May 2022 22:00:22 +0200 Subject: [PATCH 236/658] fix: build issues, extend event-type in types, use @calcom/types --- lib/helpers/verifyApiKey.ts | 8 ------- lib/types.ts | 35 ++++++++++++++++++++++++---- lib/validations/event-type.ts | 6 ++--- lib/validations/shared/jsonSchema.ts | 2 +- package.json | 7 +++--- 5 files changed, 38 insertions(+), 20 deletions(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index cf5c4a8472..c467c6ce99 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -1,16 +1,8 @@ -import type { IncomingMessage } from "http"; import { NextMiddleware } from "next-api-middleware"; import { hashAPIKey } from "@calcom/ee/lib/api/apiKeys"; import prisma from "@calcom/prisma"; -/** @todo figure how to use the one from `@calcom/types`fi */ -declare module "next" { - export interface NextApiRequest extends IncomingMessage { - userId: number; - } -} - // Used to check if the apiKey is not expired, could be extracted if reused. but not for now. export const dateNotInPast = function (date: Date) { const now = new Date(); diff --git a/lib/types.ts b/lib/types.ts index edd5b9f6c9..a5c7d8ad21 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -1,3 +1,4 @@ +import { AppStoreLocationType, DefaultLocationType } from "@calcom/app-store/locations"; import { User, Team, @@ -15,10 +16,9 @@ import { Payment, Schedule, ReminderMail, + EventType, } from "@calcom/prisma/client"; -import { schemaEventTypeReadPublic } from "@lib/validations/event-type"; - // Base response, used for all responses export type BaseResponse = { message?: string; @@ -124,13 +124,38 @@ export type EventTypeCustomInputResponse = BaseResponse & { export type EventTypeCustomInputsResponse = BaseResponse & { event_type_custom_inputs?: Partial[]; }; - +// From rrule https://jakubroztocil.github.io/rrule freq +enum Frequency { + "YEARLY", + "MONTHLY", + "WEEKLY", + "DAILY", + "HOURLY", + "MINUTELY", + "SECONDLY", +} +interface EventTypeExtended extends Omit { + recurringEvent: { + dtstart?: Date | undefined; + interval?: number | undefined; + count?: number | undefined; + freq?: Frequency | undefined; + until?: Date | undefined; + tzid?: string | undefined; + }; + locations: { + link?: string | undefined; + address?: string | undefined; + hostPhoneNumber?: string | undefined; + type: DefaultLocationType | AppStoreLocationType; + }[]; +} // EventType export type EventTypeResponse = BaseResponse & { - event_type?: Partial; + event_type?: Partial; }; export type EventTypesResponse = BaseResponse & { - event_types?: Partial[]; + event_types?: Partial[]; }; // Payment diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 6b43a4474a..aee6002089 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -38,9 +38,9 @@ const schemaEventTypeCreateParams = z slug: z.string(), description: z.string().optional().nullable(), length: z.number().int(), - locations: jsonSchema.optional().nullable().or(z.null()), - metadata: z.any().optional().nullable().or(z.null()), - recurringEvent: jsonSchema.optional().nullable().or(z.null()), + locations: jsonSchema.optional(), + metadata: z.any().optional(), + recurringEvent: jsonSchema.optional(), }) .strict(); diff --git a/lib/validations/shared/jsonSchema.ts b/lib/validations/shared/jsonSchema.ts index 826f0b6250..bfc7ae1f2b 100644 --- a/lib/validations/shared/jsonSchema.ts +++ b/lib/validations/shared/jsonSchema.ts @@ -5,5 +5,5 @@ type Literal = boolean | number | string; type Json = Literal | { [key: string]: Json } | Json[]; const literalSchema = z.union([z.string(), z.number(), z.boolean()]); export const jsonSchema: z.ZodSchema = z.lazy(() => - z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)]).or(z.null()) + z.union([literalSchema, z.array(jsonSchema), z.record(jsonSchema)]) ); diff --git a/package.json b/package.json index 143065b933..8f025ebd54 100644 --- a/package.json +++ b/package.json @@ -19,11 +19,12 @@ }, "devDependencies": { "@calcom/tsconfig": "*", - "@typescript-eslint/eslint-plugin": "^5.22.0", - "babel-jest": "^28.0.3", + "@calcom/types": "*", + "@typescript-eslint/eslint-plugin": "^5.25.0", + "babel-jest": "^28.1.0", "jest": "^28.0.3", "node-mocks-http": "^1.11.0" - }, + }, "dependencies": { "@calcom/prisma": "*", "@sentry/nextjs": "^6.19.7", From d10377684653fbf3986215954f28807e8f5c7c61 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 19 May 2022 22:05:26 +0200 Subject: [PATCH 237/658] fix: add back types until merged into main --- lib/helpers/verifyApiKey.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index c467c6ce99..81bbb8db07 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -1,8 +1,20 @@ +import type { IncomingMessage } from "http"; import { NextMiddleware } from "next-api-middleware"; import { hashAPIKey } from "@calcom/ee/lib/api/apiKeys"; import prisma from "@calcom/prisma"; +/** @todo figure how to use the one from `@calcom/types`fi */ +/** @todo: remove once `@calcom/types` is updated with it.*/ +declare module "next" { + export interface NextApiRequest extends IncomingMessage { + userId: number; + query: { + apiKey: string; + }; + } +} + // Used to check if the apiKey is not expired, could be extracted if reused. but not for now. export const dateNotInPast = function (date: Date) { const now = new Date(); From f2ce2f324bcf4df5efdce164f6a7a2f734df324b Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 00:58:42 +0200 Subject: [PATCH 238/658] fix: build webhooks and event-types --- lib/helpers/verifyApiKey.ts | 24 +- lib/types.ts | 1 + lib/validations/webhook.ts | 2 +- package.json | 1 - pages/api/booking-references/[id].ts | 324 +++++++++++++-------------- pages/api/users/index.ts | 23 +- 6 files changed, 188 insertions(+), 187 deletions(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 81bbb8db07..2c58befc4d 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -1,19 +1,21 @@ -import type { IncomingMessage } from "http"; +// import type { NextApiRequest } from "next"; import { NextMiddleware } from "next-api-middleware"; import { hashAPIKey } from "@calcom/ee/lib/api/apiKeys"; import prisma from "@calcom/prisma"; -/** @todo figure how to use the one from `@calcom/types`fi */ -/** @todo: remove once `@calcom/types` is updated with it.*/ -declare module "next" { - export interface NextApiRequest extends IncomingMessage { - userId: number; - query: { - apiKey: string; - }; - } -} +// /** @todo figure how to use the one from `@calcom/types`fi */ +// /** @todo: remove once `@calcom/types` is updated with it.*/ +// declare module "next" { +// export interface NextApiRequest extends NextApiRequest { +// userId: number; +// body: any; +// method: string; +// query: { +// apiKey: string; +// }; +// } +// } // Used to check if the apiKey is not expired, could be extracted if reused. but not for now. export const dateNotInPast = function (date: Date) { diff --git a/lib/types.ts b/lib/types.ts index a5c7d8ad21..6018019abc 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -150,6 +150,7 @@ interface EventTypeExtended extends Omit; diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index dc8f8bb41f..5948db65eb 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -24,7 +24,7 @@ export const schemaWebhookCreateBodyParams = schemaWebhookBaseBodyParams.merge(s const schemaWebhookEditParams = z .object({ payloadTemplate: z.string().optional(), - eventTriggers: z.string().optional(), + eventTriggers: z.any(), subscriberUrl: z.string().optional(), }) .strict(); diff --git a/package.json b/package.json index 8f025ebd54..33dd0c54a7 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,6 @@ }, "devDependencies": { "@calcom/tsconfig": "*", - "@calcom/types": "*", "@typescript-eslint/eslint-plugin": "^5.25.0", "babel-jest": "^28.1.0", "jest": "^28.0.3", diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index 702b77c1a5..47a76ea85e 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -22,177 +22,177 @@ export async function bookingReferenceById( res.status(400).json({ message: "Your query was invalid" }); return; } - // const userWithBookings = await prisma.user.findUnique({ - // where: { id: userId }, - // include: { bookings: true }, - // }); - // if (!userWithBookings) throw new Error("User not found"); - // const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); + const userWithBookings = await prisma.user.findUnique({ + where: { id: userId }, + include: { bookings: true }, + }); + if (!userWithBookings) throw new Error("User not found"); + const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); // console.log(userBookingIds); - // const bookingReferences = await prisma.bookingReference - // .findMany({ where: { id: { in: userBookingIds } } }) - // .then((bookingReferences) => { - // console.log(bookingReferences); - // return bookingReferences.map((bookingReference) => bookingReference.id); - // }); + const bookingReferences = await prisma.bookingReference + .findMany({ where: { id: { in: userBookingIds } } }) + .then((bookingReferences) => { + console.log(bookingReferences); + return bookingReferences.map((bookingReference) => bookingReference.id); + }); // res.status(400).json({ message: "Booking reference not found" }); // return; // } - // if (userBookingIds.includes(safeQuery.data.id)) { - // if (!bookingReferences?.includes(safeQuery.data.id)) { - // throw new Error("BookingReference: bookingId not found"); - switch (method) { - case "GET": - /** - * @swagger - * /booking-references/{id}: - * get: - * operationId: getBookingReferenceById - * summary: Find a booking reference - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the booking reference to get - * tags: - * - booking-references - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: BookingReference was not found - */ - // console.log(safeQuery.data.id); - const bookingReference = await prisma.bookingReference.findFirst().catch((error: Error) => { - console.log("hoerr:", error); - }); - // console.log(bookingReference); - if (!bookingReference) res.status(404).json({ message: "Booking reference not found" }); - else res.status(200).json({ booking_reference: bookingReference }); + if (!bookingReferences?.includes(safeQuery.data.id)) { + // if (userBookingIds.includes(safeQuery.data.id)) { + // throw new Error("BookingReference: bookingId not found"); + switch (method) { + case "GET": + /** + * @swagger + * /booking-references/{id}: + * get: + * operationId: getBookingReferenceById + * summary: Find a booking reference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the booking reference to get + * tags: + * - booking-references + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: BookingReference was not found + */ + // console.log(safeQuery.data.id); + const bookingReference = await prisma.bookingReference.findFirst().catch((error: Error) => { + console.log("hoerr:", error); + }); + // console.log(bookingReference); + if (!bookingReference) res.status(404).json({ message: "Booking reference not found" }); + else res.status(200).json({ booking_reference: bookingReference }); - // .then((data) => { - // console.log(data); - // return schemaBookingReferenceReadPublic.parse(data); - // }) - // .then((booking_reference) => res.status(200).json({ booking_reference })) - // .catch((error: Error) => { - // console.log(error); - // res.status(404).json({ - // message: `BookingReference with id: ${safeQuery.data.id} not found`, - // error, - // }); - // }); - break; - case "PATCH": - /** - * @swagger - * /booking-references/{id}: - * patch: - * operationId: editBookingReferenceById - * summary: Edit an existing booking reference - * requestBody: - * description: Edit an existing booking reference related to one of your bookings - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * days: - * type: array - * example: email@example.com - * startTime: - * type: string - * example: 1970-01-01T17:00:00.000Z - * endTime: - * type: string - * example: 1970-01-01T17:00:00.000Z - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the booking reference to edit - * tags: - * - booking-references - * responses: - * 201: - * description: OK, safeBody.data edited successfuly - * 400: - * description: Bad request. BookingReference body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ + // .then((data) => { + // console.log(data); + // return schemaBookingReferenceReadPublic.parse(data); + // }) + // .then((booking_reference) => res.status(200).json({ booking_reference })) + // .catch((error: Error) => { + // console.log(error); + // res.status(404).json({ + // message: `BookingReference with id: ${safeQuery.data.id} not found`, + // error, + // }); + // }); + break; + case "PATCH": + /** + * @swagger + * /booking-references/{id}: + * patch: + * operationId: editBookingReferenceById + * summary: Edit an existing booking reference + * requestBody: + * description: Edit an existing booking reference related to one of your bookings + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * days: + * type: array + * example: email@example.com + * startTime: + * type: string + * example: 1970-01-01T17:00:00.000Z + * endTime: + * type: string + * example: 1970-01-01T17:00:00.000Z + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the booking reference to edit + * tags: + * - booking-references + * responses: + * 201: + * description: OK, safeBody.data edited successfuly + * 400: + * description: Bad request. BookingReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ - const safeBody = schemaBookingEditBodyParams.safeParse(body); - if (!safeBody.success) { - console.log(safeBody.error); - res.status(400).json({ message: "Invalid request body", error: safeBody.error }); - return; - } - await prisma.bookingReference - .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) - .then((data) => schemaBookingReferenceReadPublic.parse(data)) - .then((booking_reference) => res.status(200).json({ booking_reference })) - .catch((error: Error) => - res.status(404).json({ - message: `BookingReference with id: ${safeQuery.data.id} not found`, - error, + const safeBody = schemaBookingEditBodyParams.safeParse(body); + if (!safeBody.success) { + console.log(safeBody.error); + res.status(400).json({ message: "Invalid request body", error: safeBody.error }); + return; + } + await prisma.bookingReference + .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) + .then((data) => schemaBookingReferenceReadPublic.parse(data)) + .then((booking_reference) => res.status(200).json({ booking_reference })) + .catch((error: Error) => + res.status(404).json({ + message: `BookingReference with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; + case "DELETE": + /** + * @swagger + * /booking-references/{id}: + * delete: + * operationId: removeBookingReferenceById + * summary: Remove an existing booking reference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the booking reference to delete + * tags: + * - booking-references + * responses: + * 201: + * description: OK, bookingReference removed successfuly + * 400: + * description: Bad request. BookingReference id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + await prisma.bookingReference + .delete({ + where: { id: safeQuery.data.id }, }) - ); - break; - case "DELETE": - /** - * @swagger - * /booking-references/{id}: - * delete: - * operationId: removeBookingReferenceById - * summary: Remove an existing booking reference - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the booking reference to delete - * tags: - * - booking-references - * responses: - * 201: - * description: OK, bookingReference removed successfuly - * 400: - * description: Bad request. BookingReference id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - await prisma.bookingReference - .delete({ - where: { id: safeQuery.data.id }, - }) - .then(() => - res.status(200).json({ - message: `BookingReference with id: ${safeQuery.data.id} deleted`, - }) - ) - .catch((error: Error) => - res.status(404).json({ - message: `BookingReference with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; + .then(() => + res.status(200).json({ + message: `BookingReference with id: ${safeQuery.data.id} deleted`, + }) + ) + .catch((error: Error) => + res.status(404).json({ + message: `BookingReference with id: ${safeQuery.data.id} not found`, + error, + }) + ); + break; - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } - // } else res.status(401).json({ message: "Unauthorized" }); + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } + } else res.status(401).json({ message: "Unauthorized" }); } export default withMiddleware("HTTP_GET_DELETE_PATCH")( diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 9f80a421d2..6eea24cb3b 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -40,19 +40,18 @@ async function getAllorCreateUser( message: "No Users were found", error, }); + } else if (method === "POST") { + const isAdmin = await prisma.user + .findUnique({ where: { id: userId } }) + .then((user) => user?.role === "ADMIN"); + if (!isAdmin) res.status(401).json({ message: "You are not authorized" }); + else { + const user = await prisma.user.create({ + data: schemaUserReadPublic.parse(body), + }); + res.status(201).json({ user }); + } } - // else if (method === "POST") { - // const isAdmin = await prisma.user - // .findUnique({ where: { id: userId } }) - // .then((user) => user?.role === "ADMIN"); - // if (!isAdmin) res.status(401).json({ message: "You are not authorized" }); - // else { - // const user = await prisma.user.create({ - // data: schemaUserReadPublic.parse(body), - // }); - // res.status(201).json({ user }); - // } - // } } // No POST endpoint for users for now as a regular user you're expected to signup. From dc967b7d9ebc8ff310cbe634adcb80bbf0a15a8f Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 01:45:54 +0200 Subject: [PATCH 239/658] fix: hooks, event-types and booking references --- lib/helpers/verifyApiKey.ts | 14 --------- lib/validations/event-type.ts | 8 ++++- lib/validations/webhook.ts | 5 +-- pages/api/booking-references/[id].ts | 46 +++++++++------------------- 4 files changed, 25 insertions(+), 48 deletions(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 2c58befc4d..c467c6ce99 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -1,22 +1,8 @@ -// import type { NextApiRequest } from "next"; import { NextMiddleware } from "next-api-middleware"; import { hashAPIKey } from "@calcom/ee/lib/api/apiKeys"; import prisma from "@calcom/prisma"; -// /** @todo figure how to use the one from `@calcom/types`fi */ -// /** @todo: remove once `@calcom/types` is updated with it.*/ -// declare module "next" { -// export interface NextApiRequest extends NextApiRequest { -// userId: number; -// body: any; -// method: string; -// query: { -// apiKey: string; -// }; -// } -// } - // Used to check if the apiKey is not expired, could be extracted if reused. but not for now. export const dateNotInPast = function (date: Date) { const now = new Date(); diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index aee6002089..ff11d4fcd9 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -87,4 +87,10 @@ export const schemaEventTypeReadPublic = EventType.pick({ description: true, locations: true, metadata: true, -}); +}).merge( + z.object({ + recurringEvent: jsonSchema.nullable(), + locations: z.array(jsonSchema).nullable(), + metadata: jsonSchema.nullable(), + }) +); diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 5948db65eb..39b1a999a0 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -37,7 +37,8 @@ export const schemaWebhookReadPublic = Webhook.pick({ eventTypeId: true, payloadTemplate: true, eventTriggers: true, - eventType: true, - app: true, + /** @todo: find out why this breaks the api */ + // eventType: true, + // app: true, appId: true, }); diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index 47a76ea85e..f7a14056eb 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -28,20 +28,12 @@ export async function bookingReferenceById( }); if (!userWithBookings) throw new Error("User not found"); const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); - // console.log(userBookingIds); const bookingReferences = await prisma.bookingReference .findMany({ where: { id: { in: userBookingIds } } }) - .then((bookingReferences) => { - console.log(bookingReferences); - return bookingReferences.map((bookingReference) => bookingReference.id); - }); + .then((bookingReferences) => bookingReferences.map((bookingReference) => bookingReference.id)); - // res.status(400).json({ message: "Booking reference not found" }); - // return; - // } - if (!bookingReferences?.includes(safeQuery.data.id)) { - // if (userBookingIds.includes(safeQuery.data.id)) { - // throw new Error("BookingReference: bookingId not found"); + if (!bookingReferences?.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); + else { switch (method) { case "GET": /** @@ -67,26 +59,18 @@ export async function bookingReferenceById( * 404: * description: BookingReference was not found */ - // console.log(safeQuery.data.id); - const bookingReference = await prisma.bookingReference.findFirst().catch((error: Error) => { - console.log("hoerr:", error); - }); - // console.log(bookingReference); - if (!bookingReference) res.status(404).json({ message: "Booking reference not found" }); - else res.status(200).json({ booking_reference: bookingReference }); + await prisma.bookingReference + .findFirst({ where: { id: safeQuery.data.id } }) + .then((data) => schemaBookingReferenceReadPublic.parse(data)) + .then((booking_reference) => res.status(200).json({ booking_reference })) + .catch((error: Error) => { + console.log(error); + res.status(404).json({ + message: `BookingReference with id: ${safeQuery.data.id} not found`, + error, + }); + }); - // .then((data) => { - // console.log(data); - // return schemaBookingReferenceReadPublic.parse(data); - // }) - // .then((booking_reference) => res.status(200).json({ booking_reference })) - // .catch((error: Error) => { - // console.log(error); - // res.status(404).json({ - // message: `BookingReference with id: ${safeQuery.data.id} not found`, - // error, - // }); - // }); break; case "PATCH": /** @@ -192,7 +176,7 @@ export async function bookingReferenceById( res.status(405).json({ message: "Method not allowed" }); break; } - } else res.status(401).json({ message: "Unauthorized" }); + } } export default withMiddleware("HTTP_GET_DELETE_PATCH")( From d23fa4be4ed673c6d4256d7ee3dd8691e9e2a2aa Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 01:47:17 +0200 Subject: [PATCH 240/658] fix: add comment to fix later any --- lib/validations/webhook.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 39b1a999a0..e3ea709ec9 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -24,6 +24,7 @@ export const schemaWebhookCreateBodyParams = schemaWebhookBaseBodyParams.merge(s const schemaWebhookEditParams = z .object({ payloadTemplate: z.string().optional(), + /** @todo: don't use any here and validate eventTriggers proper */ eventTriggers: z.any(), subscriberUrl: z.string().optional(), }) From 29deb1fd3cd7afc239b91ee96fa0c2727f1279ed Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 02:19:33 +0200 Subject: [PATCH 241/658] fix: add back req extend types --- lib/helpers/verifyApiKey.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index c467c6ce99..feba710c5b 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -1,8 +1,22 @@ +import type { IncomingMessage } from "http"; import { NextMiddleware } from "next-api-middleware"; import { hashAPIKey } from "@calcom/ee/lib/api/apiKeys"; import prisma from "@calcom/prisma"; +/** @todo figure how to use the one from `@calcom/types`fi */ +/** @todo: remove once `@calcom/types` is updated with it.*/ +declare module "next" { + export interface NextApiRequest extends IncomingMessage { + userId: number; + body: Body; + method: string; + query: { + apiKey: string; + }; + } +} + // Used to check if the apiKey is not expired, could be extracted if reused. but not for now. export const dateNotInPast = function (date: Date) { const now = new Date(); From b755d2bd71c433441be3c30e17e78907c702cc6e Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 02:47:20 +0200 Subject: [PATCH 242/658] fix: build and validations for event-type, bring back req extension --- lib/helpers/verifyApiKey.ts | 2 +- lib/types.ts | 2 +- lib/validations/event-type.ts | 24 ++++++++++++++++++++++-- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index feba710c5b..67ad05c8ac 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -12,7 +12,7 @@ declare module "next" { body: Body; method: string; query: { - apiKey: string; + apiKey?: string; }; } } diff --git a/lib/types.ts b/lib/types.ts index 6018019abc..f61e5d7f1c 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -125,7 +125,7 @@ export type EventTypeCustomInputsResponse = BaseResponse & { event_type_custom_inputs?: Partial[]; }; // From rrule https://jakubroztocil.github.io/rrule freq -enum Frequency { +export enum Frequency { "YEARLY", "MONTHLY", "WEEKLY", diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index ff11d4fcd9..e3a6d83228 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -1,7 +1,11 @@ import { z } from "zod"; +import { AppStoreLocationType, DefaultLocationType } from "@calcom/app-store/locations"; import { _EventTypeModel as EventType } from "@calcom/prisma/zod"; +import { Frequency } from "@lib/types"; +import { timeZone } from "@lib/validations/shared/timeZone"; + import { jsonSchema } from "./shared/jsonSchema"; export const schemaEventTypeBaseBodyParams = EventType.pick({ @@ -89,8 +93,24 @@ export const schemaEventTypeReadPublic = EventType.pick({ metadata: true, }).merge( z.object({ - recurringEvent: jsonSchema.nullable(), - locations: z.array(jsonSchema).nullable(), + // { dtstart?: Date | undefined; interval?: number | undefined; count?: number | undefined; freq?: Frequency | undefined; until?: Date | undefined; tzid?: string | undefined; } | undefined' + // recurringEvent: jsonSchema.nullable(), + recurringEvent: z.object({ + dtstart: z.date().optional(), + interval: z.number().int().optional(), + count: z.number().int().optional(), + freq: z.nativeEnum(Frequency).optional(), + until: z.date().optional(), + tzid: timeZone, + }), + locations: z.array( + z.object({ + link: z.string().optional(), + address: z.string().optional(), + hostPhoneNumber: z.string().optional(), + type: z.nativeEnum(DefaultLocationType).or(z.nativeEnum(AppStoreLocationType)), + }) + ), metadata: jsonSchema.nullable(), }) ); From 4fb1c14d3d874554aa24ccabc7f11932ad9afa50 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 02:57:24 +0200 Subject: [PATCH 243/658] fix: body unknown --- lib/helpers/verifyApiKey.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 67ad05c8ac..12a92e35a5 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -9,7 +9,7 @@ import prisma from "@calcom/prisma"; declare module "next" { export interface NextApiRequest extends IncomingMessage { userId: number; - body: Body; + body: unknown; method: string; query: { apiKey?: string; From f22257977d915f4c49c96e577a1d1a2c172e9863 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 03:01:47 +0200 Subject: [PATCH 244/658] fix: body any --- lib/helpers/verifyApiKey.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 12a92e35a5..6d07d72d99 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -8,8 +8,9 @@ import prisma from "@calcom/prisma"; /** @todo: remove once `@calcom/types` is updated with it.*/ declare module "next" { export interface NextApiRequest extends IncomingMessage { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + body: any; userId: number; - body: unknown; method: string; query: { apiKey?: string; From f1cf8ba94bc3e544c95b3f1b85f1981080c881c3 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 03:06:05 +0200 Subject: [PATCH 245/658] fix: query { [key: string]: string | string[]; } --- lib/helpers/verifyApiKey.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 6d07d72d99..756fb26fe1 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -12,9 +12,7 @@ declare module "next" { body: any; userId: number; method: string; - query: { - apiKey?: string; - }; + query: { [key: string]: string | string[] }; } } From 9132bb51eb500d44dde6dd10d0668e8461e6bab4 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 03:10:28 +0200 Subject: [PATCH 246/658] fix: disable create user post no role admin yet --- pages/api/users/index.ts | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 6eea24cb3b..9f80a421d2 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -40,18 +40,19 @@ async function getAllorCreateUser( message: "No Users were found", error, }); - } else if (method === "POST") { - const isAdmin = await prisma.user - .findUnique({ where: { id: userId } }) - .then((user) => user?.role === "ADMIN"); - if (!isAdmin) res.status(401).json({ message: "You are not authorized" }); - else { - const user = await prisma.user.create({ - data: schemaUserReadPublic.parse(body), - }); - res.status(201).json({ user }); - } } + // else if (method === "POST") { + // const isAdmin = await prisma.user + // .findUnique({ where: { id: userId } }) + // .then((user) => user?.role === "ADMIN"); + // if (!isAdmin) res.status(401).json({ message: "You are not authorized" }); + // else { + // const user = await prisma.user.create({ + // data: schemaUserReadPublic.parse(body), + // }); + // res.status(201).json({ user }); + // } + // } } // No POST endpoint for users for now as a regular user you're expected to signup. From f6746c4cf97335aaee049372d172187f7e0e0fbe Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 03:15:04 +0200 Subject: [PATCH 247/658] fix: rmeove comment to fix build --- lib/helpers/verifyApiKey.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 756fb26fe1..38fa6b44c3 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -8,11 +8,10 @@ import prisma from "@calcom/prisma"; /** @todo: remove once `@calcom/types` is updated with it.*/ declare module "next" { export interface NextApiRequest extends IncomingMessage { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - body: any; userId: number; method: string; query: { [key: string]: string | string[] }; + body: any; } } From 1717f14e833c07be8a12da216df002c72e7674e2 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 03:40:14 +0200 Subject: [PATCH 248/658] fix: event type validations skip --- lib/types.ts | 4 ++-- pages/api/event-types/index.ts | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/types.ts b/lib/types.ts index f61e5d7f1c..681e88de65 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -153,10 +153,10 @@ interface EventTypeExtended extends Omit; + event_type?: Partial; }; export type EventTypesResponse = BaseResponse & { - event_types?: Partial[]; + event_types?: Partial[]; }; // Payment diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 163fa501fb..420983a162 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -30,8 +30,10 @@ async function createOrlistAllEventTypes( * description: No event types were found */ const data = await prisma.eventType.findMany({ where: { userId } }); - const event_types = data.map((eventType) => schemaEventTypeReadPublic.parse(eventType)); - if (event_types) res.status(200).json({ event_types }); + // const event_types = data.map( + // async (eventType) => await schemaEventTypeReadPublic.safeParseAsync(eventType) + // ); + if (data) res.status(200).json({ event_types: data }); else (error: Error) => res.status(404).json({ From 418a4271d936edbe5d51a9799e7e50e753c57e09 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 03:46:01 +0200 Subject: [PATCH 249/658] fix: adds console log to debug event-types --- pages/api/event-types/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 420983a162..a349cb3f92 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -29,7 +29,10 @@ async function createOrlistAllEventTypes( * 404: * description: No event types were found */ - const data = await prisma.eventType.findMany({ where: { userId } }); + const data = await prisma.eventType + .findMany({ where: { userId } }) + .catch((error) => res.status(404).json({ message: "No event types were found", error })); + console.log("eventTypes:", data); // const event_types = data.map( // async (eventType) => await schemaEventTypeReadPublic.safeParseAsync(eventType) // ); From 2413e30c6980bd79b80475b7a61343952b5ca3ea Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 19:25:38 +0200 Subject: [PATCH 250/658] fix: update jest, add zod as dep --- package.json | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 33dd0c54a7..e08d7881f9 100644 --- a/package.json +++ b/package.json @@ -21,9 +21,9 @@ "@calcom/tsconfig": "*", "@typescript-eslint/eslint-plugin": "^5.25.0", "babel-jest": "^28.1.0", - "jest": "^28.0.3", + "jest": "^28.1.0", "node-mocks-http": "^1.11.0" - }, + }, "dependencies": { "@calcom/prisma": "*", "@sentry/nextjs": "^6.19.7", @@ -34,6 +34,7 @@ "next-transpile-modules": "^9.0.0", "next-validations": "^0.2.0", "typescript": "^4.6.4", - "tzdata": "^1.0.30" + "tzdata": "^1.0.30", + "zod": "^3.16.0" } } From 2fdeb2fc5e21f0c642607283b56b0624b3825aac Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 19:43:23 +0200 Subject: [PATCH 251/658] fix: no strict in baseparams attendee --- lib/validations/attendee.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/attendee.ts b/lib/validations/attendee.ts index cf73bdb4d0..66ae50b2f1 100644 --- a/lib/validations/attendee.ts +++ b/lib/validations/attendee.ts @@ -9,7 +9,7 @@ export const schemaAttendeeBaseBodyParams = Attendee.pick({ email: true, name: true, timeZone: true, -}).partial(); +}); const schemaAttendeeCreateParams = z .object({ From 656ceefe252c351c0a44296de164554d06fdde3d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 20:31:15 +0200 Subject: [PATCH 252/658] fix: zod same version as webwebsite --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e08d7881f9..cc5455ed48 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,6 @@ "next-validations": "^0.2.0", "typescript": "^4.6.4", "tzdata": "^1.0.30", - "zod": "^3.16.0" + "zod": "^3.14.4" } } From 496328b03509b87e27ab428fcb3f57ada98d4bdc Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 20:48:30 +0200 Subject: [PATCH 253/658] fix: add strict true to tsconfig --- tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/tsconfig.json b/tsconfig.json index 5622a85041..26060017f9 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,7 @@ { "extends": "@calcom/tsconfig/nextjs.json", "compilerOptions": { + "strict": true, "baseUrl": ".", "paths": { "@api/*": ["pages/api/*"], From 8c8235c3c7c14e53437e28b5c94c69e27965e9d6 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 21:21:11 +0200 Subject: [PATCH 254/658] fix: dont parse hooks before read --- pages/api/hooks/[id].ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/hooks/[id].ts b/pages/api/hooks/[id].ts index 32a81e7b12..715c58cb73 100644 --- a/pages/api/hooks/[id].ts +++ b/pages/api/hooks/[id].ts @@ -97,7 +97,7 @@ export async function WebhookById( } await prisma.webhook .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) - .then((data) => schemaWebhookReadPublic.parse(data)) + // .then((data) => schemaWebhookReadPublic.parse(data)) .then((webhook) => res.status(200).json({ webhook })) .catch((error: Error) => res.status(404).json({ From f1175a06f64c753599efeedde515c9035e14111b Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 21:27:11 +0200 Subject: [PATCH 255/658] fix: hooks dont parse before read --- pages/api/hooks/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/api/hooks/index.ts b/pages/api/hooks/index.ts index 0a81da7ec5..12efc93a74 100644 --- a/pages/api/hooks/index.ts +++ b/pages/api/hooks/index.ts @@ -30,8 +30,8 @@ async function createOrlistAllWebhooks( * description: No webhooks were found */ const data = await prisma.webhook.findMany({ where: { userId } }); - const webhooks = data.map((webhook) => schemaWebhookReadPublic.parse(webhook)); - if (webhooks) res.status(200).json({ webhooks }); + // const webhooks = data.map((webhook) => schemaWebhookReadPublic.parse(webhook)); + if (data) res.status(200).json({ webhooks: data }); else (error: Error) => res.status(404).json({ From f9e98228c763ca4ed525596259c076d989d6c6e4 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 21:48:24 +0200 Subject: [PATCH 256/658] merge directly --- lib/validations/webhook.ts | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index e3ea709ec9..fd95d5ed8c 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -12,25 +12,37 @@ const schemaWebhookBaseBodyParams = Webhook.pick({ payloadTemplate: true, }).partial(); -const schemaWebhookCreateParams = z - .object({ +// const schemaWebhookCreateParams = z +// .object({ +// id: z.string(), +// subscriberUrl: z.string(), +// }) +// .strict(); + +export const schemaWebhookCreateBodyParams = schemaWebhookBaseBodyParams.merge( + z.object({ id: z.string(), subscriberUrl: z.string(), }) - .strict(); +); -export const schemaWebhookCreateBodyParams = schemaWebhookBaseBodyParams.merge(schemaWebhookCreateParams); +// const schemaWebhookEditParams = z +// .object({ +// payloadTemplate: z.string().optional(), +// /** @todo: don't use any here and validate eventTriggers proper */ +// eventTriggers: z.any(), +// subscriberUrl: z.string().optional(), +// }) +// .strict(); -const schemaWebhookEditParams = z - .object({ +export const schemaWebhookEditBodyParams = schemaWebhookBaseBodyParams.merge( + z.object({ payloadTemplate: z.string().optional(), /** @todo: don't use any here and validate eventTriggers proper */ eventTriggers: z.any(), subscriberUrl: z.string().optional(), }) - .strict(); - -export const schemaWebhookEditBodyParams = schemaWebhookBaseBodyParams.merge(schemaWebhookEditParams); +); export const schemaWebhookReadPublic = Webhook.pick({ id: true, From 1f8c8959000ceec4dd2c1f0b176a12a352d82430 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 21:52:41 +0200 Subject: [PATCH 257/658] fix: hooks --- lib/types.ts | 2 +- lib/validations/webhook.ts | 1 - pages/api/hooks/[id].ts | 2 +- pages/api/hooks/index.ts | 16 +++++++--------- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/lib/types.ts b/lib/types.ts index 681e88de65..257568d551 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -177,7 +177,7 @@ export type SchedulesResponse = BaseResponse & { // Webhook export type WebhookResponse = BaseResponse & { - webhook?: Partial; + webhook?: Partial | null; }; export type WebhooksResponse = BaseResponse & { webhooks?: Partial[]; diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index fd95d5ed8c..aab40dc502 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -50,7 +50,6 @@ export const schemaWebhookReadPublic = Webhook.pick({ eventTypeId: true, payloadTemplate: true, eventTriggers: true, - /** @todo: find out why this breaks the api */ // eventType: true, // app: true, appId: true, diff --git a/pages/api/hooks/[id].ts b/pages/api/hooks/[id].ts index 715c58cb73..dcf82aaa2d 100644 --- a/pages/api/hooks/[id].ts +++ b/pages/api/hooks/[id].ts @@ -51,7 +51,7 @@ export async function WebhookById( case "GET": await prisma.webhook .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaWebhookReadPublic.parse(data)) + // .then((data) => schemaWebhookReadPublic.parse(data)) .then((webhook) => res.status(200).json({ webhook })) .catch((error: Error) => res.status(404).json({ diff --git a/pages/api/hooks/index.ts b/pages/api/hooks/index.ts index 12efc93a74..3dc0076c9e 100644 --- a/pages/api/hooks/index.ts +++ b/pages/api/hooks/index.ts @@ -29,15 +29,13 @@ async function createOrlistAllWebhooks( * 404: * description: No webhooks were found */ - const data = await prisma.webhook.findMany({ where: { userId } }); - // const webhooks = data.map((webhook) => schemaWebhookReadPublic.parse(webhook)); - if (data) res.status(200).json({ webhooks: data }); - else - (error: Error) => - res.status(404).json({ - message: "No Webhooks were found", - error, - }); + await prisma.webhook + .findMany({ where: { userId } }) + .then((data) => res.status(200).json({ webhooks: data })) + .catch((error) => { + console.log(error); + res.status(404).json({ message: "No webhooks were found", error }); + }); } else if (method === "POST") { /** * @swagger From 1585b2d8f9daff4a3461e2a9d51f68edc6162d2c Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 22:10:13 +0200 Subject: [PATCH 258/658] fix: dont use schemareadpublic --- pages/api/hooks/index.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/pages/api/hooks/index.ts b/pages/api/hooks/index.ts index 3dc0076c9e..a67999037b 100644 --- a/pages/api/hooks/index.ts +++ b/pages/api/hooks/index.ts @@ -4,7 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { WebhookResponse, WebhooksResponse } from "@lib/types"; -import { schemaWebhookCreateBodyParams, schemaWebhookReadPublic } from "@lib/validations/webhook"; +import { schemaWebhookCreateBodyParams } from "@lib/validations/webhook"; async function createOrlistAllWebhooks( { method, body, userId }: NextApiRequest, @@ -29,13 +29,13 @@ async function createOrlistAllWebhooks( * 404: * description: No webhooks were found */ - await prisma.webhook + const webhooks = await prisma.webhook .findMany({ where: { userId } }) - .then((data) => res.status(200).json({ webhooks: data })) - .catch((error) => { - console.log(error); - res.status(404).json({ message: "No webhooks were found", error }); - }); + .catch((error) => console.log(error)); + if (!webhooks) { + console.log(); + res.status(404).json({ message: "No webhooks were found" }); + } else res.status(200).json({ webhooks }); } else if (method === "POST") { /** * @swagger @@ -62,9 +62,7 @@ async function createOrlistAllWebhooks( } const data = await prisma.webhook.create({ data: { ...safe.data, userId } }); - const webhook = schemaWebhookReadPublic.parse(data); - - if (data) res.status(201).json({ webhook, message: "Webhook created successfully" }); + if (data) res.status(201).json({ webhook: data, message: "Webhook created successfully" }); else (error: Error) => res.status(400).json({ From 93d9c4f6d06f55e7a568199b7878a61369010eff Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 22:15:25 +0200 Subject: [PATCH 259/658] fix: disable post --- pages/api/hooks/index.ts | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/pages/api/hooks/index.ts b/pages/api/hooks/index.ts index a67999037b..983fe3ecce 100644 --- a/pages/api/hooks/index.ts +++ b/pages/api/hooks/index.ts @@ -55,20 +55,19 @@ async function createOrlistAllWebhooks( * 401: * description: Authorization information is missing or invalid. */ - const safe = schemaWebhookCreateBodyParams.safeParse(body); - if (!safe.success) { - res.status(400).json({ message: "Invalid request body" }); - return; - } - - const data = await prisma.webhook.create({ data: { ...safe.data, userId } }); - if (data) res.status(201).json({ webhook: data, message: "Webhook created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new webhook", - error, - }); + // const safe = schemaWebhookCreateBodyParams.safeParse(body); + // if (!safe.success) { + // res.status(400).json({ message: "Invalid request body" }); + // return; + // } + // const data = await prisma.webhook.create({ data: { ...safe.data, userId } }); + // if (data) res.status(201).json({ webhook: data, message: "Webhook created successfully" }); + // else + // (error: Error) => + // res.status(400).json({ + // message: "Could not create new webhook", + // error, + // }); } else res.status(405).json({ message: `Method ${method} not allowed` }); } From 2340ed2876038c2f29c0a68e7fe9d434dbfaf480 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 22:39:42 +0200 Subject: [PATCH 260/658] fix: engines node 15 or greater --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index cc5455ed48..3eeca8f305 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,9 @@ "repository": "git@github.com:calcom/api.git", "author": "Cal.com Inc.", "private": true, + "engines": { + "node": ">=15.0.0" + }, "scripts": { "dev": "next build && PORT=3002 next start", "dev-real": "PORT=3002 next dev", From 6c0d4de8f398993bb5395ccce20716e5bbcc9648 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 22:59:15 +0200 Subject: [PATCH 261/658] fix: move clone from main to feat/v15x --- scripts/vercel-deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/vercel-deploy.sh b/scripts/vercel-deploy.sh index 2c801645a1..82a3044458 100755 --- a/scripts/vercel-deploy.sh +++ b/scripts/vercel-deploy.sh @@ -27,7 +27,7 @@ fi # stop execution on error - don't let it build if something goes wrong set -e -git config --global init.defaultBranch main +git config --global init.defaultBranch feat/node-v15x git config --global advice.detachedHead false # set up an empty temporary work directory From 4a1dff65965832827a278879a3fe75d5809e5694 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 20 May 2022 23:02:17 +0200 Subject: [PATCH 262/658] fix --- package.json | 2 +- scripts/vercel-deploy.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 3eeca8f305..af6ff39268 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "author": "Cal.com Inc.", "private": true, "engines": { - "node": ">=15.0.0" + "node": ">=14.19.x" }, "scripts": { "dev": "next build && PORT=3002 next start", diff --git a/scripts/vercel-deploy.sh b/scripts/vercel-deploy.sh index 82a3044458..2c801645a1 100755 --- a/scripts/vercel-deploy.sh +++ b/scripts/vercel-deploy.sh @@ -27,7 +27,7 @@ fi # stop execution on error - don't let it build if something goes wrong set -e -git config --global init.defaultBranch feat/node-v15x +git config --global init.defaultBranch main git config --global advice.detachedHead false # set up an empty temporary work directory From 40f1f9714ebebdece9a76008acf1e17e5cedba58 Mon Sep 17 00:00:00 2001 From: zomars Date: Mon, 23 May 2022 13:17:43 -0600 Subject: [PATCH 263/658] Build fixes --- package.json | 14 +++---- scripts/vercel-deploy.sh | 81 +++++++++++++--------------------------- tsconfig.json | 8 +--- 3 files changed, 34 insertions(+), 69 deletions(-) diff --git a/package.json b/package.json index af6ff39268..ede2ad9f15 100644 --- a/package.json +++ b/package.json @@ -10,19 +10,19 @@ "node": ">=14.19.x" }, "scripts": { - "dev": "next build && PORT=3002 next start", - "dev-real": "PORT=3002 next dev", - "start": "PORT=3002 next start", "build": "next build", - "lint": "next lint", + "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist", + "dev-real": "PORT=3002 next dev", + "dev": "next build && PORT=3002 next start", "lint-fix": "next lint --fix && prettier --write .", + "lint": "next lint", + "prebuild": "cd ../.. && yarn workspace @calcom/prisma generate-schemas", + "start": "PORT=3002 next start", "test": "jest --detectOpenHandles --passWithNoTests", - "type-check": "tsc --pretty --noEmit", - "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist" + "type-check": "tsc --pretty --noEmit" }, "devDependencies": { "@calcom/tsconfig": "*", - "@typescript-eslint/eslint-plugin": "^5.25.0", "babel-jest": "^28.1.0", "jest": "^28.1.0", "node-mocks-http": "^1.11.0" diff --git a/scripts/vercel-deploy.sh b/scripts/vercel-deploy.sh index 2c801645a1..0de5b672b4 100755 --- a/scripts/vercel-deploy.sh +++ b/scripts/vercel-deploy.sh @@ -1,27 +1,24 @@ # github submodule repo addresses without https:// prefix -BRANCH_TO_CLONE="-b feat/api-keys" - -# This didn't work ¯\_(ツ)_/¯ -# declare -A remotes=( -# ["apps/website"]="github.com/calcom/website" -# ["apps/api"]="github.com/calcom/api" -# ) +BRANCH_TO_CLONE="" +SUBMODULE_GITHUB=github.com/calcom/api +SUBMODULE_PATH=apps/api +COMMIT=$VERCEL_GIT_COMMIT_SHA if [ "$VERCEL_GIT_COMMIT_SHA" == "" ]; then - echo "Error: VERCEL_GIT_COMMIT_SHA is empty" - exit 0 + echo "Error: VERCEL_GIT_COMMIT_SHA is empty" + exit 0 fi # github access token is necessary # add it to Environment Variables on Vercel if [ "$GITHUB_ACCESS_TOKEN" == "" ]; then - echo "Error: GITHUB_ACCESS_TOKEN is empty" - exit 0 + echo "Error: GITHUB_ACCESS_TOKEN is empty" + exit 0 fi # We add an exception to test on staging if [ "$VERCEL_GIT_COMMIT_REF" == "staging" ]; then - BRANCH_TO_CLONE="-b $VERCEL_GIT_COMMIT_REF" + BRANCH_TO_CLONE="-b $VERCEL_GIT_COMMIT_REF" fi # stop execution on error - don't let it build if something goes wrong @@ -38,52 +35,26 @@ git clone $BRANCH_TO_CLONE https://$GITHUB_ACCESS_TOKEN@github.com/calcom/cal.co echo "Cloned" -# get submodule commit -output=$(git submodule status --recursive) # get submodule info +# set up an empty temporary work directory +rm -rf tmp || true # remove the tmp folder if exists +mkdir tmp # create the tmp folder +cd tmp # go into the tmp folder -# Extract each submodule commit hash and path -submodules=$(echo "$output" | sed "s/ /,/g") +# checkout the current submodule commit +git init # initialise empty repo +git remote add $SUBMODULE_PATH https://$GITHUB_ACCESS_TOKEN@$SUBMODULE_GITHUB # add origin of the submodule +git fetch --depth=1 $SUBMODULE_PATH $COMMIT # fetch only the required version +git checkout $COMMIT # checkout on the right commit -for submodule in $submodules; do - IFS=',' read -ra submodule_parts <<<"$submodule" - COMMIT=$(echo ${submodule_parts[0]} | sed "s/-/ /g") - SUBMODULE_PATH=${submodule_parts[1]} - echo "COMMIT: $COMMIT SUBMODULE_PATH: $SUBMODULE_PATH" +# move the submodule from tmp to the submodule path +cd .. # go folder up +rm -rf tmp/.git # remove .git +mv tmp/* $SUBMODULE_PATH/ # move the submodule to the submodule path - # This should be a hash table but couldn't make it work ¯\_(ツ)_/¯ - # SUBMODULE_GITHUB=$remotes[$SUBMODULE_PATH] - if [ "$SUBMODULE_PATH" == "apps/website" ]; then - SUBMODULE_GITHUB=github.com/calcom/website - fi +# clean up +rm -rf tmp # remove the tmp folder - if [ "$SUBMODULE_PATH" == "apps/api" ]; then - SUBMODULE_GITHUB=github.com/calcom/api - COMMIT=$VERCEL_GIT_COMMIT_SHA - fi - - echo "Submodule init" - - # set up an empty temporary work directory - rm -rf tmp || true # remove the tmp folder if exists - mkdir tmp # create the tmp folder - cd tmp # go into the tmp folder - - # checkout the current submodule commit - git init # initialise empty repo - git remote add $SUBMODULE_PATH https://$GITHUB_ACCESS_TOKEN@$SUBMODULE_GITHUB # add origin of the submodule - git fetch --depth=1 $SUBMODULE_PATH $COMMIT # fetch only the required version - git checkout $COMMIT # checkout on the right commit - - # move the submodule from tmp to the submodule path - cd .. # go folder up - rm -rf tmp/.git # remove .git - mv tmp/* $SUBMODULE_PATH/ # move the submodule to the submodule path - - # clean up - rm -rf tmp # remove the tmp folder -done - -git diff --quiet HEAD^ HEAD ':!/apps/docs/*' ':!/apps/website/*' ':!/apps/web/*' +git diff --quiet HEAD^ HEAD ':!/apps/docs/*' ':!/apps/website/*' ':!/apps/web/*' ':!/apps/swagger/*' ':!/apps/console/*' echo "✅ - Build can proceed" -exit 1 \ No newline at end of file +exit 1 diff --git a/tsconfig.json b/tsconfig.json index 26060017f9..2714b86c1c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,12 +9,6 @@ "@/*": ["*"] } }, - "include": [ - "next-env.d.ts", - "../../packages/types/*.d.ts", - "../../packages/types/next-auth.d.ts", - "**/*.ts", - "**/*.tsx" - ], + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], "exclude": ["node_modules", "templates", "auth"] } From 44f0830b16d42c555ea8631d3e795abab5097b0f Mon Sep 17 00:00:00 2001 From: zomars Date: Mon, 23 May 2022 13:20:12 -0600 Subject: [PATCH 264/658] Syncs zod version --- package.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/package.json b/package.json index ede2ad9f15..16c51d9d6b 100644 --- a/package.json +++ b/package.json @@ -6,9 +6,6 @@ "repository": "git@github.com:calcom/api.git", "author": "Cal.com Inc.", "private": true, - "engines": { - "node": ">=14.19.x" - }, "scripts": { "build": "next build", "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist", @@ -38,6 +35,6 @@ "next-validations": "^0.2.0", "typescript": "^4.6.4", "tzdata": "^1.0.30", - "zod": "^3.14.4" + "zod": "^3.16.0" } } From beca5152e9abbb453fd92a43933281c8496adab5 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 23 May 2022 22:55:53 +0200 Subject: [PATCH 265/658] hotfix: debugging event-types in prod --- pages/api/event-types/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index a349cb3f92..c3a7cc954f 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -33,6 +33,7 @@ async function createOrlistAllEventTypes( .findMany({ where: { userId } }) .catch((error) => res.status(404).json({ message: "No event types were found", error })); console.log("eventTypes:", data); + console.log("userId:", userId); // const event_types = data.map( // async (eventType) => await schemaEventTypeReadPublic.safeParseAsync(eventType) // ); From 4629c5d5c77a7594754d36060c805617682b973f Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 23 May 2022 23:18:41 +0200 Subject: [PATCH 266/658] fix: move log of userId --- pages/api/event-types/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index c3a7cc954f..1ab736eec2 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -10,6 +10,7 @@ async function createOrlistAllEventTypes( { method, body, userId }: NextApiRequest, res: NextApiResponse ) { + console.log("userId:", userId); if (method === "GET") { /** * @swagger @@ -33,7 +34,6 @@ async function createOrlistAllEventTypes( .findMany({ where: { userId } }) .catch((error) => res.status(404).json({ message: "No event types were found", error })); console.log("eventTypes:", data); - console.log("userId:", userId); // const event_types = data.map( // async (eventType) => await schemaEventTypeReadPublic.safeParseAsync(eventType) // ); From 6099bfb4ee5904ea73bb0dbd2c1e94b53172a747 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 23 May 2022 23:23:53 +0200 Subject: [PATCH 267/658] fix: more logging --- lib/helpers/verifyApiKey.ts | 1 + pages/api/event-types/index.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 38fa6b44c3..11d481815e 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -40,5 +40,6 @@ export const verifyApiKey: NextMiddleware = async (req, res, next) => { if (!apiKey.userId) return res.status(404).json({ error: "No user found for this apiKey" }); /* We save the user id in the request for later use */ req.userId = apiKey.userId; + console.log(`User ${apiKey.userId} verified`); await next(); }; diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 1ab736eec2..ccbf79d7ca 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -33,7 +33,7 @@ async function createOrlistAllEventTypes( const data = await prisma.eventType .findMany({ where: { userId } }) .catch((error) => res.status(404).json({ message: "No event types were found", error })); - console.log("eventTypes:", data); + console.log(`userid is: ${userId}`, "eventTypes:", data); // const event_types = data.map( // async (eventType) => await schemaEventTypeReadPublic.safeParseAsync(eventType) // ); From 0e95a1d3e8c80136aa0674233b7982f125b66601 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed, 25 May 2022 14:13:52 +0530 Subject: [PATCH 268/658] Enabled webhook create call --- pages/api/hooks/index.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/pages/api/hooks/index.ts b/pages/api/hooks/index.ts index 983fe3ecce..05b6e90d57 100644 --- a/pages/api/hooks/index.ts +++ b/pages/api/hooks/index.ts @@ -55,19 +55,19 @@ async function createOrlistAllWebhooks( * 401: * description: Authorization information is missing or invalid. */ - // const safe = schemaWebhookCreateBodyParams.safeParse(body); - // if (!safe.success) { - // res.status(400).json({ message: "Invalid request body" }); - // return; - // } - // const data = await prisma.webhook.create({ data: { ...safe.data, userId } }); - // if (data) res.status(201).json({ webhook: data, message: "Webhook created successfully" }); - // else - // (error: Error) => - // res.status(400).json({ - // message: "Could not create new webhook", - // error, - // }); + const safe = schemaWebhookCreateBodyParams.safeParse(body); + if (!safe.success) { + res.status(400).json({ message: "Invalid request body" }); + return; + } + const data = await prisma.webhook.create({ data: { ...safe.data, userId } }); + if (data) res.status(201).json({ webhook: data, message: "Webhook created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new webhook", + error, + }); } else res.status(405).json({ message: `Method ${method} not allowed` }); } From 2e22978838b6ce16bb038a0acefbcf94a9910089 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed, 25 May 2022 14:23:43 +0530 Subject: [PATCH 269/658] Added schema for create --- lib/validations/webhook.ts | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index aab40dc502..a655e5f11c 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -12,29 +12,21 @@ const schemaWebhookBaseBodyParams = Webhook.pick({ payloadTemplate: true, }).partial(); -// const schemaWebhookCreateParams = z -// .object({ -// id: z.string(), -// subscriberUrl: z.string(), -// }) -// .strict(); +export const schemaWebhookCreateParams = z + .object({ + userId: z.number().or(z.string()).optional(), + eventTypeId: z.number().or(z.string()).optional(), + eventTriggers: z.any.optional(), + active: z.boolean().optional(), + subscriberUrl: z.string(), + payloadTemplate: z.string().optional(), + }) + .strict(); export const schemaWebhookCreateBodyParams = schemaWebhookBaseBodyParams.merge( - z.object({ - id: z.string(), - subscriberUrl: z.string(), - }) + schemaWebhookCreateParams ); -// const schemaWebhookEditParams = z -// .object({ -// payloadTemplate: z.string().optional(), -// /** @todo: don't use any here and validate eventTriggers proper */ -// eventTriggers: z.any(), -// subscriberUrl: z.string().optional(), -// }) -// .strict(); - export const schemaWebhookEditBodyParams = schemaWebhookBaseBodyParams.merge( z.object({ payloadTemplate: z.string().optional(), From fbab89cf402a490a3df32f903eb98edb447851ec Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed, 25 May 2022 15:07:19 +0530 Subject: [PATCH 270/658] Fixes any invocation --- lib/validations/webhook.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index a655e5f11c..40aec5c288 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -16,7 +16,7 @@ export const schemaWebhookCreateParams = z .object({ userId: z.number().or(z.string()).optional(), eventTypeId: z.number().or(z.string()).optional(), - eventTriggers: z.any.optional(), + eventTriggers: z.any().optional(), active: z.boolean().optional(), subscriberUrl: z.string(), payloadTemplate: z.string().optional(), From b9c5590a4795ab8632a41a341fefcaae723d8750 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 11:20:49 +0530 Subject: [PATCH 271/658] Updated webhook validations --- lib/validations/webhook.ts | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 40aec5c288..86b811739c 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -1,9 +1,15 @@ import { z } from "zod"; import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; +import { WebhookTriggerEvents } from "@calcom/prisma/client"; + +export const WEBHOOK_TRIGGER_EVENTS = [ + WebhookTriggerEvents.BOOKING_CANCELLED, + WebhookTriggerEvents.BOOKING_CREATED, + WebhookTriggerEvents.BOOKING_RESCHEDULED, +] as ["BOOKING_CANCELLED", "BOOKING_CREATED", "BOOKING_RESCHEDULED"]; const schemaWebhookBaseBodyParams = Webhook.pick({ - id: true, userId: true, eventTypeId: true, eventTriggers: true, @@ -14,12 +20,12 @@ const schemaWebhookBaseBodyParams = Webhook.pick({ export const schemaWebhookCreateParams = z .object({ - userId: z.number().or(z.string()).optional(), - eventTypeId: z.number().or(z.string()).optional(), - eventTriggers: z.any().optional(), - active: z.boolean().optional(), - subscriberUrl: z.string(), - payloadTemplate: z.string().optional(), + subscriberUrl: z.string().url(), + eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array(), + active: z.boolean(), + payloadTemplate: z.string().nullable(), + eventTypeId: z.number().optional(), + appId: z.string().optional().nullable(), }) .strict(); @@ -30,8 +36,8 @@ export const schemaWebhookCreateBodyParams = schemaWebhookBaseBodyParams.merge( export const schemaWebhookEditBodyParams = schemaWebhookBaseBodyParams.merge( z.object({ payloadTemplate: z.string().optional(), - /** @todo: don't use any here and validate eventTriggers proper */ - eventTriggers: z.any(), + /** @todo: don't use 'any' here and validate eventTriggers proper */ + eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array().optional(), subscriberUrl: z.string().optional(), }) ); From 4737778dc1e3b360df0aa2797a40c7e6fc36a72e Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 11:41:36 +0530 Subject: [PATCH 272/658] Debug create err --- lib/validations/webhook.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 86b811739c..b228f47e42 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -1,13 +1,13 @@ import { z } from "zod"; import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; -import { WebhookTriggerEvents } from "@calcom/prisma/client"; +// import { WebhookTriggerEvents } from "@calcom/prisma/client"; -export const WEBHOOK_TRIGGER_EVENTS = [ - WebhookTriggerEvents.BOOKING_CANCELLED, - WebhookTriggerEvents.BOOKING_CREATED, - WebhookTriggerEvents.BOOKING_RESCHEDULED, -] as ["BOOKING_CANCELLED", "BOOKING_CREATED", "BOOKING_RESCHEDULED"]; +// export const WEBHOOK_TRIGGER_EVENTS = [ +// WebhookTriggerEvents.BOOKING_CANCELLED, +// WebhookTriggerEvents.BOOKING_CREATED, +// WebhookTriggerEvents.BOOKING_RESCHEDULED, +// ] as ["BOOKING_CANCELLED", "BOOKING_CREATED", "BOOKING_RESCHEDULED"]; const schemaWebhookBaseBodyParams = Webhook.pick({ userId: true, @@ -21,7 +21,7 @@ const schemaWebhookBaseBodyParams = Webhook.pick({ export const schemaWebhookCreateParams = z .object({ subscriberUrl: z.string().url(), - eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array(), + eventTriggers: z.any(), active: z.boolean(), payloadTemplate: z.string().nullable(), eventTypeId: z.number().optional(), @@ -37,7 +37,7 @@ export const schemaWebhookEditBodyParams = schemaWebhookBaseBodyParams.merge( z.object({ payloadTemplate: z.string().optional(), /** @todo: don't use 'any' here and validate eventTriggers proper */ - eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array().optional(), + eventTriggers: z.any().optional(), subscriberUrl: z.string().optional(), }) ); From d372c4c526f9a537ae90df45161a9b8292f54e4b Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 12:03:14 +0530 Subject: [PATCH 273/658] more debug --- lib/validations/webhook.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index b228f47e42..48665c61d1 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -21,9 +21,9 @@ const schemaWebhookBaseBodyParams = Webhook.pick({ export const schemaWebhookCreateParams = z .object({ subscriberUrl: z.string().url(), - eventTriggers: z.any(), + eventTriggers: z.string().array(), active: z.boolean(), - payloadTemplate: z.string().nullable(), + payloadTemplate: z.string().optional().nullable(), eventTypeId: z.number().optional(), appId: z.string().optional().nullable(), }) From 92b011214cbd8eb29932ab2dfd50bda1d0b8f5a8 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 12:06:15 +0530 Subject: [PATCH 274/658] More debug --- lib/validations/webhook.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 48665c61d1..44f433b3c1 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -21,11 +21,11 @@ const schemaWebhookBaseBodyParams = Webhook.pick({ export const schemaWebhookCreateParams = z .object({ subscriberUrl: z.string().url(), - eventTriggers: z.string().array(), + eventTriggers: z.any(), active: z.boolean(), - payloadTemplate: z.string().optional().nullable(), - eventTypeId: z.number().optional(), - appId: z.string().optional().nullable(), +// payloadTemplate: z.string().optional().nullable(), +// eventTypeId: z.number().optional(), +// appId: z.string().optional().nullable(), }) .strict(); From 5e3b51c6217c2c301c7b1c5393219f0ee70a36ed Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 12:12:13 +0530 Subject: [PATCH 275/658] added ID --- lib/validations/webhook.ts | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 44f433b3c1..f523c4c71e 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -1,15 +1,16 @@ import { z } from "zod"; import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; -// import { WebhookTriggerEvents } from "@calcom/prisma/client"; +import { WebhookTriggerEvents } from "@calcom/prisma/client"; -// export const WEBHOOK_TRIGGER_EVENTS = [ -// WebhookTriggerEvents.BOOKING_CANCELLED, -// WebhookTriggerEvents.BOOKING_CREATED, -// WebhookTriggerEvents.BOOKING_RESCHEDULED, -// ] as ["BOOKING_CANCELLED", "BOOKING_CREATED", "BOOKING_RESCHEDULED"]; +export const WEBHOOK_TRIGGER_EVENTS = [ + WebhookTriggerEvents.BOOKING_CANCELLED, + WebhookTriggerEvents.BOOKING_CREATED, + WebhookTriggerEvents.BOOKING_RESCHEDULED, +] as ["BOOKING_CANCELLED", "BOOKING_CREATED", "BOOKING_RESCHEDULED"]; const schemaWebhookBaseBodyParams = Webhook.pick({ + id: true, userId: true, eventTypeId: true, eventTriggers: true, @@ -20,12 +21,13 @@ const schemaWebhookBaseBodyParams = Webhook.pick({ export const schemaWebhookCreateParams = z .object({ + id: z.string(), subscriberUrl: z.string().url(), - eventTriggers: z.any(), + eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array(), active: z.boolean(), -// payloadTemplate: z.string().optional().nullable(), -// eventTypeId: z.number().optional(), -// appId: z.string().optional().nullable(), + payloadTemplate: z.string().optional().nullable(), + eventTypeId: z.number().optional(), + appId: z.string().optional().nullable(), }) .strict(); @@ -36,8 +38,7 @@ export const schemaWebhookCreateBodyParams = schemaWebhookBaseBodyParams.merge( export const schemaWebhookEditBodyParams = schemaWebhookBaseBodyParams.merge( z.object({ payloadTemplate: z.string().optional(), - /** @todo: don't use 'any' here and validate eventTriggers proper */ - eventTriggers: z.any().optional(), + eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array().optional(), subscriberUrl: z.string().optional(), }) ); From 316c5a1266672b653fccb9d5affdbd4e01da9f1d Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 12:16:51 +0530 Subject: [PATCH 276/658] Fixing prettier --- lib/validations/webhook.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index f523c4c71e..1997bdbb3e 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -1,8 +1,9 @@ import { z } from "zod"; -import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; import { WebhookTriggerEvents } from "@calcom/prisma/client"; +import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; + export const WEBHOOK_TRIGGER_EVENTS = [ WebhookTriggerEvents.BOOKING_CANCELLED, WebhookTriggerEvents.BOOKING_CREATED, @@ -31,9 +32,7 @@ export const schemaWebhookCreateParams = z }) .strict(); -export const schemaWebhookCreateBodyParams = schemaWebhookBaseBodyParams.merge( - schemaWebhookCreateParams -); +export const schemaWebhookCreateBodyParams = schemaWebhookBaseBodyParams.merge(schemaWebhookCreateParams); export const schemaWebhookEditBodyParams = schemaWebhookBaseBodyParams.merge( z.object({ From 09acaef90466729979e572962376d5078a6f4143 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 12:20:32 +0530 Subject: [PATCH 277/658] Further prettier changes --- lib/validations/webhook.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 1997bdbb3e..d7109e5912 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -1,7 +1,6 @@ import { z } from "zod"; import { WebhookTriggerEvents } from "@calcom/prisma/client"; - import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; export const WEBHOOK_TRIGGER_EVENTS = [ From b408015df4c10ff52f4f02ce248a2e8a1f45ac63 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 12:25:13 +0530 Subject: [PATCH 278/658] Fixed enum --- lib/validations/webhook.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index d7109e5912..b2d6485275 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -1,8 +1,13 @@ import { z } from "zod"; -import { WebhookTriggerEvents } from "@calcom/prisma/client"; import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; +export const WebhookTriggerEvents: { + BOOKING_CREATED: 'BOOKING_CREATED', + BOOKING_RESCHEDULED: 'BOOKING_RESCHEDULED', + BOOKING_CANCELLED: 'BOOKING_CANCELLED' +}; + export const WEBHOOK_TRIGGER_EVENTS = [ WebhookTriggerEvents.BOOKING_CANCELLED, WebhookTriggerEvents.BOOKING_CREATED, From 7b936073a4b65410981788c7785ed33b154b1031 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 12:28:38 +0530 Subject: [PATCH 279/658] More fix --- lib/validations/webhook.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index b2d6485275..6c35fb9743 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; -export const WebhookTriggerEvents: { +export const WebhookTriggerEvents = { BOOKING_CREATED: 'BOOKING_CREATED', BOOKING_RESCHEDULED: 'BOOKING_RESCHEDULED', BOOKING_CANCELLED: 'BOOKING_CANCELLED' From e8e36abc75d0fe7d804b318c3caeb2f606ceab45 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 12:32:04 +0530 Subject: [PATCH 280/658] prettier fix --- lib/validations/webhook.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 6c35fb9743..59da7bb71a 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -3,9 +3,9 @@ import { z } from "zod"; import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; export const WebhookTriggerEvents = { - BOOKING_CREATED: 'BOOKING_CREATED', - BOOKING_RESCHEDULED: 'BOOKING_RESCHEDULED', - BOOKING_CANCELLED: 'BOOKING_CANCELLED' + BOOKING_CREATED: "BOOKING_CREATED", + BOOKING_RESCHEDULED: "BOOKING_RESCHEDULED", + BOOKING_CANCELLED: "BOOKING_CANCELLED" }; export const WEBHOOK_TRIGGER_EVENTS = [ From 8721a04d445a33f7c3a3e56c2de21b12f80a4385 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 12:35:28 +0530 Subject: [PATCH 281/658] prettier fix again --- lib/validations/webhook.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 59da7bb71a..ee42052204 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -5,7 +5,7 @@ import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; export const WebhookTriggerEvents = { BOOKING_CREATED: "BOOKING_CREATED", BOOKING_RESCHEDULED: "BOOKING_RESCHEDULED", - BOOKING_CANCELLED: "BOOKING_CANCELLED" + BOOKING_CANCELLED: "BOOKING_CANCELLED", }; export const WEBHOOK_TRIGGER_EVENTS = [ From 8f9a970fb63ac8a95fd0e9a4fdf810df6addc5af Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 27 May 2022 20:43:10 +0200 Subject: [PATCH 282/658] fix: moves event-types to find user including it's event-types --- pages/api/event-types/index.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index c3a7cc954f..610743baac 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -29,15 +29,17 @@ async function createOrlistAllEventTypes( * 404: * description: No event types were found */ - const data = await prisma.eventType - .findMany({ where: { userId } }) + const data = await prisma.user + .findUnique({ + where: { id: userId }, + rejectOnNotFound: true, + select: { eventTypes: true }, + }) .catch((error) => res.status(404).json({ message: "No event types were found", error })); - console.log("eventTypes:", data); - console.log("userId:", userId); // const event_types = data.map( // async (eventType) => await schemaEventTypeReadPublic.safeParseAsync(eventType) // ); - if (data) res.status(200).json({ event_types: data }); + if (data) res.status(200).json({ event_types: data.eventTypes }); else (error: Error) => res.status(404).json({ From a945d5a61c7d713a0050ef8e4cf7fb8ec4964a43 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed, 25 May 2022 14:13:52 +0530 Subject: [PATCH 283/658] Enabled webhook create call --- pages/api/hooks/index.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/pages/api/hooks/index.ts b/pages/api/hooks/index.ts index 983fe3ecce..05b6e90d57 100644 --- a/pages/api/hooks/index.ts +++ b/pages/api/hooks/index.ts @@ -55,19 +55,19 @@ async function createOrlistAllWebhooks( * 401: * description: Authorization information is missing or invalid. */ - // const safe = schemaWebhookCreateBodyParams.safeParse(body); - // if (!safe.success) { - // res.status(400).json({ message: "Invalid request body" }); - // return; - // } - // const data = await prisma.webhook.create({ data: { ...safe.data, userId } }); - // if (data) res.status(201).json({ webhook: data, message: "Webhook created successfully" }); - // else - // (error: Error) => - // res.status(400).json({ - // message: "Could not create new webhook", - // error, - // }); + const safe = schemaWebhookCreateBodyParams.safeParse(body); + if (!safe.success) { + res.status(400).json({ message: "Invalid request body" }); + return; + } + const data = await prisma.webhook.create({ data: { ...safe.data, userId } }); + if (data) res.status(201).json({ webhook: data, message: "Webhook created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new webhook", + error, + }); } else res.status(405).json({ message: `Method ${method} not allowed` }); } From fe3f6a70f3bbb6f5ed342f5b84e5a9400afaf583 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed, 25 May 2022 14:23:43 +0530 Subject: [PATCH 284/658] Added schema for create --- lib/validations/webhook.ts | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index aab40dc502..a655e5f11c 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -12,29 +12,21 @@ const schemaWebhookBaseBodyParams = Webhook.pick({ payloadTemplate: true, }).partial(); -// const schemaWebhookCreateParams = z -// .object({ -// id: z.string(), -// subscriberUrl: z.string(), -// }) -// .strict(); +export const schemaWebhookCreateParams = z + .object({ + userId: z.number().or(z.string()).optional(), + eventTypeId: z.number().or(z.string()).optional(), + eventTriggers: z.any.optional(), + active: z.boolean().optional(), + subscriberUrl: z.string(), + payloadTemplate: z.string().optional(), + }) + .strict(); export const schemaWebhookCreateBodyParams = schemaWebhookBaseBodyParams.merge( - z.object({ - id: z.string(), - subscriberUrl: z.string(), - }) + schemaWebhookCreateParams ); -// const schemaWebhookEditParams = z -// .object({ -// payloadTemplate: z.string().optional(), -// /** @todo: don't use any here and validate eventTriggers proper */ -// eventTriggers: z.any(), -// subscriberUrl: z.string().optional(), -// }) -// .strict(); - export const schemaWebhookEditBodyParams = schemaWebhookBaseBodyParams.merge( z.object({ payloadTemplate: z.string().optional(), From 2109001af13577ef182fd8a0e99e77c92ec7fc19 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed, 25 May 2022 15:07:19 +0530 Subject: [PATCH 285/658] Fixes any invocation --- lib/validations/webhook.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index a655e5f11c..40aec5c288 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -16,7 +16,7 @@ export const schemaWebhookCreateParams = z .object({ userId: z.number().or(z.string()).optional(), eventTypeId: z.number().or(z.string()).optional(), - eventTriggers: z.any.optional(), + eventTriggers: z.any().optional(), active: z.boolean().optional(), subscriberUrl: z.string(), payloadTemplate: z.string().optional(), From 4aba0af1b46f2d19291e7d76bac96fce04651d3c Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 11:20:49 +0530 Subject: [PATCH 286/658] Updated webhook validations --- lib/validations/webhook.ts | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 40aec5c288..86b811739c 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -1,9 +1,15 @@ import { z } from "zod"; import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; +import { WebhookTriggerEvents } from "@calcom/prisma/client"; + +export const WEBHOOK_TRIGGER_EVENTS = [ + WebhookTriggerEvents.BOOKING_CANCELLED, + WebhookTriggerEvents.BOOKING_CREATED, + WebhookTriggerEvents.BOOKING_RESCHEDULED, +] as ["BOOKING_CANCELLED", "BOOKING_CREATED", "BOOKING_RESCHEDULED"]; const schemaWebhookBaseBodyParams = Webhook.pick({ - id: true, userId: true, eventTypeId: true, eventTriggers: true, @@ -14,12 +20,12 @@ const schemaWebhookBaseBodyParams = Webhook.pick({ export const schemaWebhookCreateParams = z .object({ - userId: z.number().or(z.string()).optional(), - eventTypeId: z.number().or(z.string()).optional(), - eventTriggers: z.any().optional(), - active: z.boolean().optional(), - subscriberUrl: z.string(), - payloadTemplate: z.string().optional(), + subscriberUrl: z.string().url(), + eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array(), + active: z.boolean(), + payloadTemplate: z.string().nullable(), + eventTypeId: z.number().optional(), + appId: z.string().optional().nullable(), }) .strict(); @@ -30,8 +36,8 @@ export const schemaWebhookCreateBodyParams = schemaWebhookBaseBodyParams.merge( export const schemaWebhookEditBodyParams = schemaWebhookBaseBodyParams.merge( z.object({ payloadTemplate: z.string().optional(), - /** @todo: don't use any here and validate eventTriggers proper */ - eventTriggers: z.any(), + /** @todo: don't use 'any' here and validate eventTriggers proper */ + eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array().optional(), subscriberUrl: z.string().optional(), }) ); From 7c6141fdffcb86532feb3f1cee5d8bdfa0934ceb Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 11:41:36 +0530 Subject: [PATCH 287/658] Debug create err --- lib/validations/webhook.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 86b811739c..b228f47e42 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -1,13 +1,13 @@ import { z } from "zod"; import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; -import { WebhookTriggerEvents } from "@calcom/prisma/client"; +// import { WebhookTriggerEvents } from "@calcom/prisma/client"; -export const WEBHOOK_TRIGGER_EVENTS = [ - WebhookTriggerEvents.BOOKING_CANCELLED, - WebhookTriggerEvents.BOOKING_CREATED, - WebhookTriggerEvents.BOOKING_RESCHEDULED, -] as ["BOOKING_CANCELLED", "BOOKING_CREATED", "BOOKING_RESCHEDULED"]; +// export const WEBHOOK_TRIGGER_EVENTS = [ +// WebhookTriggerEvents.BOOKING_CANCELLED, +// WebhookTriggerEvents.BOOKING_CREATED, +// WebhookTriggerEvents.BOOKING_RESCHEDULED, +// ] as ["BOOKING_CANCELLED", "BOOKING_CREATED", "BOOKING_RESCHEDULED"]; const schemaWebhookBaseBodyParams = Webhook.pick({ userId: true, @@ -21,7 +21,7 @@ const schemaWebhookBaseBodyParams = Webhook.pick({ export const schemaWebhookCreateParams = z .object({ subscriberUrl: z.string().url(), - eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array(), + eventTriggers: z.any(), active: z.boolean(), payloadTemplate: z.string().nullable(), eventTypeId: z.number().optional(), @@ -37,7 +37,7 @@ export const schemaWebhookEditBodyParams = schemaWebhookBaseBodyParams.merge( z.object({ payloadTemplate: z.string().optional(), /** @todo: don't use 'any' here and validate eventTriggers proper */ - eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array().optional(), + eventTriggers: z.any().optional(), subscriberUrl: z.string().optional(), }) ); From fbe3d2fd101946fc44300c422da7fd8a55fe7fe3 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 12:03:14 +0530 Subject: [PATCH 288/658] more debug --- lib/validations/webhook.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index b228f47e42..48665c61d1 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -21,9 +21,9 @@ const schemaWebhookBaseBodyParams = Webhook.pick({ export const schemaWebhookCreateParams = z .object({ subscriberUrl: z.string().url(), - eventTriggers: z.any(), + eventTriggers: z.string().array(), active: z.boolean(), - payloadTemplate: z.string().nullable(), + payloadTemplate: z.string().optional().nullable(), eventTypeId: z.number().optional(), appId: z.string().optional().nullable(), }) From 014a682d64138375d07899d17f1928d15ed2c18e Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 12:06:15 +0530 Subject: [PATCH 289/658] More debug --- lib/validations/webhook.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 48665c61d1..44f433b3c1 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -21,11 +21,11 @@ const schemaWebhookBaseBodyParams = Webhook.pick({ export const schemaWebhookCreateParams = z .object({ subscriberUrl: z.string().url(), - eventTriggers: z.string().array(), + eventTriggers: z.any(), active: z.boolean(), - payloadTemplate: z.string().optional().nullable(), - eventTypeId: z.number().optional(), - appId: z.string().optional().nullable(), +// payloadTemplate: z.string().optional().nullable(), +// eventTypeId: z.number().optional(), +// appId: z.string().optional().nullable(), }) .strict(); From 35ba69fb8ae042aaef4f5d8eb61f0dc7cfe1ff8f Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 12:12:13 +0530 Subject: [PATCH 290/658] added ID --- lib/validations/webhook.ts | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 44f433b3c1..f523c4c71e 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -1,15 +1,16 @@ import { z } from "zod"; import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; -// import { WebhookTriggerEvents } from "@calcom/prisma/client"; +import { WebhookTriggerEvents } from "@calcom/prisma/client"; -// export const WEBHOOK_TRIGGER_EVENTS = [ -// WebhookTriggerEvents.BOOKING_CANCELLED, -// WebhookTriggerEvents.BOOKING_CREATED, -// WebhookTriggerEvents.BOOKING_RESCHEDULED, -// ] as ["BOOKING_CANCELLED", "BOOKING_CREATED", "BOOKING_RESCHEDULED"]; +export const WEBHOOK_TRIGGER_EVENTS = [ + WebhookTriggerEvents.BOOKING_CANCELLED, + WebhookTriggerEvents.BOOKING_CREATED, + WebhookTriggerEvents.BOOKING_RESCHEDULED, +] as ["BOOKING_CANCELLED", "BOOKING_CREATED", "BOOKING_RESCHEDULED"]; const schemaWebhookBaseBodyParams = Webhook.pick({ + id: true, userId: true, eventTypeId: true, eventTriggers: true, @@ -20,12 +21,13 @@ const schemaWebhookBaseBodyParams = Webhook.pick({ export const schemaWebhookCreateParams = z .object({ + id: z.string(), subscriberUrl: z.string().url(), - eventTriggers: z.any(), + eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array(), active: z.boolean(), -// payloadTemplate: z.string().optional().nullable(), -// eventTypeId: z.number().optional(), -// appId: z.string().optional().nullable(), + payloadTemplate: z.string().optional().nullable(), + eventTypeId: z.number().optional(), + appId: z.string().optional().nullable(), }) .strict(); @@ -36,8 +38,7 @@ export const schemaWebhookCreateBodyParams = schemaWebhookBaseBodyParams.merge( export const schemaWebhookEditBodyParams = schemaWebhookBaseBodyParams.merge( z.object({ payloadTemplate: z.string().optional(), - /** @todo: don't use 'any' here and validate eventTriggers proper */ - eventTriggers: z.any().optional(), + eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array().optional(), subscriberUrl: z.string().optional(), }) ); From 4c7dc10f7dc35661d3b23cbc8b29c03687413bdf Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 12:16:51 +0530 Subject: [PATCH 291/658] Fixing prettier --- lib/validations/webhook.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index f523c4c71e..1997bdbb3e 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -1,8 +1,9 @@ import { z } from "zod"; -import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; import { WebhookTriggerEvents } from "@calcom/prisma/client"; +import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; + export const WEBHOOK_TRIGGER_EVENTS = [ WebhookTriggerEvents.BOOKING_CANCELLED, WebhookTriggerEvents.BOOKING_CREATED, @@ -31,9 +32,7 @@ export const schemaWebhookCreateParams = z }) .strict(); -export const schemaWebhookCreateBodyParams = schemaWebhookBaseBodyParams.merge( - schemaWebhookCreateParams -); +export const schemaWebhookCreateBodyParams = schemaWebhookBaseBodyParams.merge(schemaWebhookCreateParams); export const schemaWebhookEditBodyParams = schemaWebhookBaseBodyParams.merge( z.object({ From 81793aebcddaefce090b2dd5a6bb352b2c4092dd Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 12:20:32 +0530 Subject: [PATCH 292/658] Further prettier changes --- lib/validations/webhook.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 1997bdbb3e..d7109e5912 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -1,7 +1,6 @@ import { z } from "zod"; import { WebhookTriggerEvents } from "@calcom/prisma/client"; - import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; export const WEBHOOK_TRIGGER_EVENTS = [ From c185883e5a2c07d1a8901ed0a7c2d16edde942be Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 12:25:13 +0530 Subject: [PATCH 293/658] Fixed enum --- lib/validations/webhook.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index d7109e5912..b2d6485275 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -1,8 +1,13 @@ import { z } from "zod"; -import { WebhookTriggerEvents } from "@calcom/prisma/client"; import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; +export const WebhookTriggerEvents: { + BOOKING_CREATED: 'BOOKING_CREATED', + BOOKING_RESCHEDULED: 'BOOKING_RESCHEDULED', + BOOKING_CANCELLED: 'BOOKING_CANCELLED' +}; + export const WEBHOOK_TRIGGER_EVENTS = [ WebhookTriggerEvents.BOOKING_CANCELLED, WebhookTriggerEvents.BOOKING_CREATED, From c47329c2929eaca5ae0f027fa09249e284084c7f Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 12:28:38 +0530 Subject: [PATCH 294/658] More fix --- lib/validations/webhook.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index b2d6485275..6c35fb9743 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -2,7 +2,7 @@ import { z } from "zod"; import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; -export const WebhookTriggerEvents: { +export const WebhookTriggerEvents = { BOOKING_CREATED: 'BOOKING_CREATED', BOOKING_RESCHEDULED: 'BOOKING_RESCHEDULED', BOOKING_CANCELLED: 'BOOKING_CANCELLED' From de557fccce691d93dfb7c15f4ad533ec5d5ac35e Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 12:32:04 +0530 Subject: [PATCH 295/658] prettier fix --- lib/validations/webhook.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 6c35fb9743..59da7bb71a 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -3,9 +3,9 @@ import { z } from "zod"; import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; export const WebhookTriggerEvents = { - BOOKING_CREATED: 'BOOKING_CREATED', - BOOKING_RESCHEDULED: 'BOOKING_RESCHEDULED', - BOOKING_CANCELLED: 'BOOKING_CANCELLED' + BOOKING_CREATED: "BOOKING_CREATED", + BOOKING_RESCHEDULED: "BOOKING_RESCHEDULED", + BOOKING_CANCELLED: "BOOKING_CANCELLED" }; export const WEBHOOK_TRIGGER_EVENTS = [ From 49ef2c341d4c869feff1d4539a2297840a20bc7b Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 26 May 2022 12:35:28 +0530 Subject: [PATCH 296/658] prettier fix again --- lib/validations/webhook.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index 59da7bb71a..ee42052204 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -5,7 +5,7 @@ import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; export const WebhookTriggerEvents = { BOOKING_CREATED: "BOOKING_CREATED", BOOKING_RESCHEDULED: "BOOKING_RESCHEDULED", - BOOKING_CANCELLED: "BOOKING_CANCELLED" + BOOKING_CANCELLED: "BOOKING_CANCELLED", }; export const WEBHOOK_TRIGGER_EVENTS = [ From 46e0b8f4f5084725582fb93f3299fd4529a0bca0 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 27 May 2022 20:43:10 +0200 Subject: [PATCH 297/658] fix: moves event-types to find user including it's event-types --- pages/api/event-types/index.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index ccbf79d7ca..e5660f138f 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -30,14 +30,14 @@ async function createOrlistAllEventTypes( * 404: * description: No event types were found */ - const data = await prisma.eventType - .findMany({ where: { userId } }) + const data = await prisma.user + .findUnique({ + where: { id: userId }, + rejectOnNotFound: true, + select: { eventTypes: true }, + }) .catch((error) => res.status(404).json({ message: "No event types were found", error })); - console.log(`userid is: ${userId}`, "eventTypes:", data); - // const event_types = data.map( - // async (eventType) => await schemaEventTypeReadPublic.safeParseAsync(eventType) - // ); - if (data) res.status(200).json({ event_types: data }); + if (data) res.status(200).json({ event_types: data.eventTypes }); else (error: Error) => res.status(404).json({ From d09fa56f631387e9bb2763134861582cb39abb28 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 27 May 2022 20:47:02 +0200 Subject: [PATCH 298/658] fix --- pages/api/event-types/index.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index e5660f138f..5c895a9165 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -37,6 +37,16 @@ async function createOrlistAllEventTypes( select: { eventTypes: true }, }) .catch((error) => res.status(404).json({ message: "No event types were found", error })); +<<<<<<< HEAD +======= +<<<<<<< HEAD +======= + console.log(`userid is: ${userId}`, "eventTypes:", data); +>>>>>>> 6099bfb (fix: more logging) + // const event_types = data.map( + // async (eventType) => await schemaEventTypeReadPublic.safeParseAsync(eventType) + // ); +>>>>>>> d374031 (fix: more logging) if (data) res.status(200).json({ event_types: data.eventTypes }); else (error: Error) => From 9f509725702200f86eca958b928f2b32502d2cc2 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 27 May 2022 20:49:50 +0200 Subject: [PATCH 299/658] fix event-types --- pages/api/event-types/index.ts | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 5c895a9165..786d4453f3 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -37,16 +37,7 @@ async function createOrlistAllEventTypes( select: { eventTypes: true }, }) .catch((error) => res.status(404).json({ message: "No event types were found", error })); -<<<<<<< HEAD -======= -<<<<<<< HEAD -======= - console.log(`userid is: ${userId}`, "eventTypes:", data); ->>>>>>> 6099bfb (fix: more logging) - // const event_types = data.map( - // async (eventType) => await schemaEventTypeReadPublic.safeParseAsync(eventType) - // ); ->>>>>>> d374031 (fix: more logging) + if (data) res.status(200).json({ event_types: data.eventTypes }); else (error: Error) => From a91dd428c0c8f14e66b58beabfeabdf3c9224aa7 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 27 May 2022 21:01:01 +0200 Subject: [PATCH 300/658] fix --- lib/helpers/verifyApiKey.ts | 1 - pages/api/event-types/index.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 11d481815e..38fa6b44c3 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -40,6 +40,5 @@ export const verifyApiKey: NextMiddleware = async (req, res, next) => { if (!apiKey.userId) return res.status(404).json({ error: "No user found for this apiKey" }); /* We save the user id in the request for later use */ req.userId = apiKey.userId; - console.log(`User ${apiKey.userId} verified`); await next(); }; diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 786d4453f3..b5c82ef67d 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -10,7 +10,6 @@ async function createOrlistAllEventTypes( { method, body, userId }: NextApiRequest, res: NextApiResponse ) { - console.log("userId:", userId); if (method === "GET") { /** * @swagger From 824d01f3588fdfbfd6add42be2dbb7240271f212 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 23 May 2022 23:18:41 +0200 Subject: [PATCH 301/658] fix: move log of userId --- pages/api/event-types/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index b5c82ef67d..786d4453f3 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -10,6 +10,7 @@ async function createOrlistAllEventTypes( { method, body, userId }: NextApiRequest, res: NextApiResponse ) { + console.log("userId:", userId); if (method === "GET") { /** * @swagger From 5b65bd1b660592bf417b1c687df596603373421e Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 27 May 2022 20:48:21 +0200 Subject: [PATCH 302/658] fix --- lib/helpers/verifyApiKey.ts | 1 + pages/api/event-types/index.ts | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 38fa6b44c3..11d481815e 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -40,5 +40,6 @@ export const verifyApiKey: NextMiddleware = async (req, res, next) => { if (!apiKey.userId) return res.status(404).json({ error: "No user found for this apiKey" }); /* We save the user id in the request for later use */ req.userId = apiKey.userId; + console.log(`User ${apiKey.userId} verified`); await next(); }; diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 786d4453f3..57ebba1ce4 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -37,8 +37,16 @@ async function createOrlistAllEventTypes( select: { eventTypes: true }, }) .catch((error) => res.status(404).json({ message: "No event types were found", error })); +<<<<<<< HEAD if (data) res.status(200).json({ event_types: data.eventTypes }); +======= + console.log(`userid is: ${userId}`, "eventTypes:", data); + // const event_types = data.map( + // async (eventType) => await schemaEventTypeReadPublic.safeParseAsync(eventType) + // ); + if (data) res.status(200).json({ event_types: data }); +>>>>>>> 6099bfb (fix: more logging) else (error: Error) => res.status(404).json({ From f40e799769062b7677b7d75abe6baf0b86690a61 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 27 May 2022 20:48:55 +0200 Subject: [PATCH 303/658] fix event types --- pages/api/event-types/index.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 57ebba1ce4..ceb8ef269b 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -37,16 +37,13 @@ async function createOrlistAllEventTypes( select: { eventTypes: true }, }) .catch((error) => res.status(404).json({ message: "No event types were found", error })); -<<<<<<< HEAD - if (data) res.status(200).json({ event_types: data.eventTypes }); -======= + console.log(`userid is: ${userId}`, "eventTypes:", data); // const event_types = data.map( // async (eventType) => await schemaEventTypeReadPublic.safeParseAsync(eventType) // ); - if (data) res.status(200).json({ event_types: data }); ->>>>>>> 6099bfb (fix: more logging) + if (data) res.status(200).json({ event_types: data.eventTypes }); else (error: Error) => res.status(404).json({ From b52832f333f3e3246d94ad0157d3683cd629bdf1 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 27 May 2022 20:47:02 +0200 Subject: [PATCH 304/658] fix --- pages/api/event-types/index.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index ceb8ef269b..178b37028c 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -37,6 +37,16 @@ async function createOrlistAllEventTypes( select: { eventTypes: true }, }) .catch((error) => res.status(404).json({ message: "No event types were found", error })); +<<<<<<< HEAD +======= +<<<<<<< HEAD +======= + console.log(`userid is: ${userId}`, "eventTypes:", data); +>>>>>>> 6099bfb (fix: more logging) + // const event_types = data.map( + // async (eventType) => await schemaEventTypeReadPublic.safeParseAsync(eventType) + // ); +>>>>>>> d374031 (fix: more logging) if (data) res.status(200).json({ event_types: data.eventTypes }); console.log(`userid is: ${userId}`, "eventTypes:", data); From 8627b28a8ea6da4cf40463b5d4334e7ff20a78a8 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 27 May 2022 21:18:47 +0200 Subject: [PATCH 305/658] fix: conflicts --- lib/helpers/verifyApiKey.ts | 1 - pages/api/event-types/index.ts | 16 ---------------- 2 files changed, 17 deletions(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 11d481815e..38fa6b44c3 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -40,6 +40,5 @@ export const verifyApiKey: NextMiddleware = async (req, res, next) => { if (!apiKey.userId) return res.status(404).json({ error: "No user found for this apiKey" }); /* We save the user id in the request for later use */ req.userId = apiKey.userId; - console.log(`User ${apiKey.userId} verified`); await next(); }; diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 178b37028c..b5c82ef67d 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -10,7 +10,6 @@ async function createOrlistAllEventTypes( { method, body, userId }: NextApiRequest, res: NextApiResponse ) { - console.log("userId:", userId); if (method === "GET") { /** * @swagger @@ -37,22 +36,7 @@ async function createOrlistAllEventTypes( select: { eventTypes: true }, }) .catch((error) => res.status(404).json({ message: "No event types were found", error })); -<<<<<<< HEAD -======= -<<<<<<< HEAD -======= - console.log(`userid is: ${userId}`, "eventTypes:", data); ->>>>>>> 6099bfb (fix: more logging) - // const event_types = data.map( - // async (eventType) => await schemaEventTypeReadPublic.safeParseAsync(eventType) - // ); ->>>>>>> d374031 (fix: more logging) - if (data) res.status(200).json({ event_types: data.eventTypes }); - console.log(`userid is: ${userId}`, "eventTypes:", data); - // const event_types = data.map( - // async (eventType) => await schemaEventTypeReadPublic.safeParseAsync(eventType) - // ); if (data) res.status(200).json({ event_types: data.eventTypes }); else (error: Error) => From be4ca8835e2daa3ba53f50632821264795362c81 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 27 May 2022 21:44:45 +0200 Subject: [PATCH 306/658] fix: event types id endpoints --- lib/validations/event-type.ts | 20 ++++++++++---------- pages/api/event-types/[id].ts | 8 ++++++-- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index e3a6d83228..bd2ba68728 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -93,16 +93,16 @@ export const schemaEventTypeReadPublic = EventType.pick({ metadata: true, }).merge( z.object({ - // { dtstart?: Date | undefined; interval?: number | undefined; count?: number | undefined; freq?: Frequency | undefined; until?: Date | undefined; tzid?: string | undefined; } | undefined' - // recurringEvent: jsonSchema.nullable(), - recurringEvent: z.object({ - dtstart: z.date().optional(), - interval: z.number().int().optional(), - count: z.number().int().optional(), - freq: z.nativeEnum(Frequency).optional(), - until: z.date().optional(), - tzid: timeZone, - }), + recurringEvent: z + .object({ + dtstart: z.date().optional(), + interval: z.number().int().optional(), + count: z.number().int().optional(), + freq: z.nativeEnum(Frequency).optional(), + until: z.date().optional(), + tzid: timeZone.optional(), + }) + .optional(), locations: z.array( z.object({ link: z.string().optional(), diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 6319b48b9e..12cee4433c 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -19,8 +19,12 @@ export async function eventTypeById( res.status(400).json({ message: "Your query was invalid" }); return; } - const data = await prisma.eventType.findMany({ where: { userId } }); - const userEventTypes = data.map((eventType) => eventType.id); + const data = await await prisma.user.findUnique({ + where: { id: userId }, + rejectOnNotFound: true, + select: { eventTypes: true }, + }); + const userEventTypes = data.eventTypes.map((eventType) => eventType.id); if (!userEventTypes.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { From 0b66e964fe021dc65159e66e811bde04b1515737 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 27 May 2022 21:51:40 +0200 Subject: [PATCH 307/658] fix: some logggingeventtypeid --- pages/api/event-types/[id].ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 12cee4433c..8654585786 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -25,6 +25,8 @@ export async function eventTypeById( select: { eventTypes: true }, }); const userEventTypes = data.eventTypes.map((eventType) => eventType.id); + console.log(userEventTypes); + console.log(userId); if (!userEventTypes.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { From b9a2e0f4c6ca1f8f617c57a319cb67b22f8482ae Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 27 May 2022 21:58:38 +0200 Subject: [PATCH 308/658] fix: event types validations recurring event and locations nullable: --- lib/validations/event-type.ts | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index bd2ba68728..b67f13fa6a 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -102,15 +102,18 @@ export const schemaEventTypeReadPublic = EventType.pick({ until: z.date().optional(), tzid: timeZone.optional(), }) - .optional(), - locations: z.array( - z.object({ - link: z.string().optional(), - address: z.string().optional(), - hostPhoneNumber: z.string().optional(), - type: z.nativeEnum(DefaultLocationType).or(z.nativeEnum(AppStoreLocationType)), - }) - ), + .optional() + .nullable(), + locations: z + .array( + z.object({ + link: z.string().optional(), + address: z.string().optional(), + hostPhoneNumber: z.string().optional(), + type: z.nativeEnum(DefaultLocationType).or(z.nativeEnum(AppStoreLocationType)), + }) + ) + .nullable(), metadata: jsonSchema.nullable(), }) ); From 2cd548bdb202f61331049184f14d4da0590b7a71 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 27 May 2022 22:04:08 +0200 Subject: [PATCH 309/658] fix: or z nul --- lib/validations/event-type.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index b67f13fa6a..4d4c2446fd 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -103,7 +103,8 @@ export const schemaEventTypeReadPublic = EventType.pick({ tzid: timeZone.optional(), }) .optional() - .nullable(), + .nullable() + .or(z.null()), locations: z .array( z.object({ From eea7c1148801920cc85f0afb76aa293db2f4d43c Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 28 May 2022 01:50:28 +0200 Subject: [PATCH 310/658] fix event type valdiations --- lib/types.ts | 16 +++++++++------- lib/validations/event-type.ts | 3 +-- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/types.ts b/lib/types.ts index 257568d551..b5d9ac4663 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -142,13 +142,15 @@ interface EventTypeExtended extends Omit Date: Sat, 28 May 2022 01:51:25 +0200 Subject: [PATCH 311/658] fix: remove console logs --- pages/api/event-types/[id].ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 8654585786..20ad84d776 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -25,8 +25,7 @@ export async function eventTypeById( select: { eventTypes: true }, }); const userEventTypes = data.eventTypes.map((eventType) => eventType.id); - console.log(userEventTypes); - console.log(userId); + if (!userEventTypes.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); else { switch (method) { From 9459b9048db6adeeb7b83f2948915300553d4469 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 31 May 2022 18:33:01 +0200 Subject: [PATCH 312/658] feat: Admin API users manegement endpoints --- lib/utils/isAdmin.ts | 6 +++++ lib/validations/user.ts | 32 ++++++++++++++++++++--- pages/api/users/[id].ts | 8 ++++-- pages/api/users/index.ts | 56 +++++++++++++++++++++------------------- 4 files changed, 70 insertions(+), 32 deletions(-) create mode 100644 lib/utils/isAdmin.ts diff --git a/lib/utils/isAdmin.ts b/lib/utils/isAdmin.ts new file mode 100644 index 0000000000..1026b8deb1 --- /dev/null +++ b/lib/utils/isAdmin.ts @@ -0,0 +1,6 @@ +import prisma from "@calcom/prisma"; + +export const isAdminGuard = async (userId: number) => { + const user = await prisma.user.findUnique({ where: { id: userId } }); + return user?.role === "ADMIN"; +}; diff --git a/lib/validations/user.ts b/lib/validations/user.ts index d78d8e23b2..3955caabd4 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -85,19 +85,45 @@ const schemaUserEditParams = z.object({ bufferTime: z.number().min(0).max(86400).optional(), startTime: z.number().min(0).max(86400).optional(), endTime: z.number().min(0).max(86400).optional(), - theme: z.nativeEnum(theme).optional(), + theme: z.nativeEnum(theme).optional().nullable(), timeFormat: z.nativeEnum(timeFormat).optional(), defaultScheduleId: z .number() .refine((id: number) => id > 0) - .optional(), + .optional() + .nullable(), + locale: z.nativeEnum(locales).optional().nullable(), + metadata: jsonSchema.or(z.null()), +}); + +// @note: These are the values that are editable via PATCH method on the user Model, +// merging both BaseBodyParams with RequiredParams, and omiting whatever we want at the end. + +const schemaUserCreateParams = z.object({ + email: z.string().email(), + weekStart: z.nativeEnum(weekdays).optional(), + brandColor: z.string().min(4).max(9).regex(/^#/).optional(), + darkBrandColor: z.string().min(4).max(9).regex(/^#/).optional(), + timeZone: timeZone.optional(), + bufferTime: z.number().min(0).max(86400).optional(), + startTime: z.number().min(0).max(86400).optional(), + endTime: z.number().min(0).max(86400).optional(), + theme: z.nativeEnum(theme).optional().nullable(), + timeFormat: z.nativeEnum(timeFormat).optional(), + defaultScheduleId: z + .number() + .refine((id: number) => id > 0) + .optional() + .nullable(), locale: z.nativeEnum(locales).optional(), metadata: jsonSchema, + createdDate: z.string().or(z.date()).optional(), }); // @note: These are the values that are editable via PATCH method on the user Model, // merging both BaseBodyParams with RequiredParams, and omiting whatever we want at the end. export const schemaUserEditBodyParams = schemaUserBaseBodyParams.merge(schemaUserEditParams).omit({}); +export const schemaUserCreateBodyParams = schemaUserBaseBodyParams.merge(schemaUserCreateParams).omit({}); // @note: These are the values that are always returned when reading a user export const schemaUserReadPublic = User.pick({ @@ -124,4 +150,4 @@ export const schemaUserReadPublic = User.pick({ createdDate: true, verified: true, invitedTo: true, -}); +}).merge(schemaUserEditBodyParams); diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index 7539d513b8..65b864c652 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { UserResponse } from "@lib/types"; +import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, @@ -20,8 +21,11 @@ export async function userById( res.status(400).json({ message: "Your query was invalid" }); return; } - if (safeQuery.data.id !== userId) res.status(401).json({ message: "Unauthorized" }); - else { + const isAdmin = await isAdminGuard(userId); + // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user + if (!isAdmin) { + if (safeQuery.data.id !== userId) res.status(401).json({ message: "Unauthorized" }); + } else { switch (method) { case "GET": /** diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 9f80a421d2..122892f2e1 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -4,7 +4,8 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { UserResponse, UsersResponse } from "@lib/types"; -import { schemaUserReadPublic } from "@lib/validations/user"; +import { isAdminGuard } from "@lib/utils/isAdmin"; +import { schemaUserReadPublic, schemaUserCreateBodyParams } from "@lib/validations/user"; /** * @swagger @@ -26,34 +27,35 @@ async function getAllorCreateUser( { userId, method, body }: NextApiRequest, res: NextApiResponse ) { + const isAdmin = await isAdminGuard(userId); if (method === "GET") { - const data = await prisma.user.findMany({ - where: { - id: userId, - }, - }); - const users = data.map((user) => schemaUserReadPublic.parse(user)); - if (users) res.status(200).json({ users }); - else - (error: Error) => - res.status(404).json({ - message: "No Users were found", - error, - }); + if (!isAdmin) { + const data = await prisma.user.findMany({ + where: { + id: userId, + }, + }); + const users = data.map((user) => schemaUserReadPublic.parse(user)); + if (users) res.status(200).json({ users }); + } else { + const data = await prisma.user.findMany({}); + const users = data.map((user) => schemaUserReadPublic.parse(user)); + if (users) res.status(200).json({ users }); + } + } else if (method === "POST") { + if (!isAdmin) res.status(401).json({ message: "You are not authorized" }); + else { + const safeBody = schemaUserCreateBodyParams.safeParse(body); + if (!safeBody.success) { + res.status(400).json({ message: "Your body was invalid" }); + return; + } + const user = await prisma.user.create({ + data: safeBody.data, + }); + res.status(201).json({ user }); + } } - // else if (method === "POST") { - // const isAdmin = await prisma.user - // .findUnique({ where: { id: userId } }) - // .then((user) => user?.role === "ADMIN"); - // if (!isAdmin) res.status(401).json({ message: "You are not authorized" }); - // else { - // const user = await prisma.user.create({ - // data: schemaUserReadPublic.parse(body), - // }); - // res.status(201).json({ user }); - // } - // } } -// No POST endpoint for users for now as a regular user you're expected to signup. export default withMiddleware("HTTP_GET_OR_POST")(getAllorCreateUser); From 4eccc8a74befcc0daf05f5148be3141f3f419541 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 31 May 2022 18:42:20 +0200 Subject: [PATCH 313/658] fix: build error jsonSchema metadata not nullable --- lib/validations/user.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/user.ts b/lib/validations/user.ts index 3955caabd4..528bc2e292 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -93,7 +93,7 @@ const schemaUserEditParams = z.object({ .optional() .nullable(), locale: z.nativeEnum(locales).optional().nullable(), - metadata: jsonSchema.or(z.null()), + metadata: jsonSchema, }); // @note: These are the values that are editable via PATCH method on the user Model, From 187d5f2b1003f222d4224db1381e51e6da59dd5e Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 31 May 2022 18:53:41 +0200 Subject: [PATCH 314/658] docs: add some comments --- pages/api/users/index.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 122892f2e1..3839ae21b6 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -30,19 +30,18 @@ async function getAllorCreateUser( const isAdmin = await isAdminGuard(userId); if (method === "GET") { if (!isAdmin) { - const data = await prisma.user.findMany({ - where: { - id: userId, - }, - }); + // If user is not ADMIN, return only his data. + const data = await prisma.user.findMany({ where: { id: userId } }); const users = data.map((user) => schemaUserReadPublic.parse(user)); if (users) res.status(200).json({ users }); } else { + // If user is admin, return all users. const data = await prisma.user.findMany({}); const users = data.map((user) => schemaUserReadPublic.parse(user)); if (users) res.status(200).json({ users }); } } else if (method === "POST") { + // If user is not ADMIN, return unauthorized. if (!isAdmin) res.status(401).json({ message: "You are not authorized" }); else { const safeBody = schemaUserCreateBodyParams.safeParse(body); From 7f42cc84793fd59808a030aedcc44079c1315565 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 31 May 2022 20:46:09 +0200 Subject: [PATCH 315/658] fix: improve admin check using enum instead of string --- lib/utils/isAdmin.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/utils/isAdmin.ts b/lib/utils/isAdmin.ts index 1026b8deb1..c97628b46d 100644 --- a/lib/utils/isAdmin.ts +++ b/lib/utils/isAdmin.ts @@ -1,6 +1,7 @@ import prisma from "@calcom/prisma"; +import { UserPermissionRole } from "@calcom/prisma/client"; export const isAdminGuard = async (userId: number) => { const user = await prisma.user.findUnique({ where: { id: userId } }); - return user?.role === "ADMIN"; + return user?.role === UserPermissionRole.ADMIN; }; From 43b94d3e9662bb2be8128c7546cc58148c2fbf8f Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 1 Jun 2022 17:05:33 +0200 Subject: [PATCH 316/658] feat: adds automatic generation of uuid id for webhooks create on API --- lib/helpers/verifyApiKey.ts | 1 - lib/utils/isAdmin.ts | 3 ++- lib/validations/webhook.ts | 2 +- pages/api/hooks/[id].ts | 4 ++-- pages/api/hooks/index.ts | 3 ++- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 38fa6b44c3..c45f3d3c3f 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -11,7 +11,6 @@ declare module "next" { userId: number; method: string; query: { [key: string]: string | string[] }; - body: any; } } diff --git a/lib/utils/isAdmin.ts b/lib/utils/isAdmin.ts index c97628b46d..64af37367f 100644 --- a/lib/utils/isAdmin.ts +++ b/lib/utils/isAdmin.ts @@ -1,5 +1,6 @@ +import { UserPermissionRole } from "@prisma/client"; + import prisma from "@calcom/prisma"; -import { UserPermissionRole } from "@calcom/prisma/client"; export const isAdminGuard = async (userId: number) => { const user = await prisma.user.findUnique({ where: { id: userId } }); diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index ee42052204..c157a6e367 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -26,7 +26,7 @@ const schemaWebhookBaseBodyParams = Webhook.pick({ export const schemaWebhookCreateParams = z .object({ - id: z.string(), + // id: z.string(), subscriberUrl: z.string().url(), eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array(), active: z.boolean(), diff --git a/pages/api/hooks/[id].ts b/pages/api/hooks/[id].ts index dcf82aaa2d..32a81e7b12 100644 --- a/pages/api/hooks/[id].ts +++ b/pages/api/hooks/[id].ts @@ -51,7 +51,7 @@ export async function WebhookById( case "GET": await prisma.webhook .findUnique({ where: { id: safeQuery.data.id } }) - // .then((data) => schemaWebhookReadPublic.parse(data)) + .then((data) => schemaWebhookReadPublic.parse(data)) .then((webhook) => res.status(200).json({ webhook })) .catch((error: Error) => res.status(404).json({ @@ -97,7 +97,7 @@ export async function WebhookById( } await prisma.webhook .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) - // .then((data) => schemaWebhookReadPublic.parse(data)) + .then((data) => schemaWebhookReadPublic.parse(data)) .then((webhook) => res.status(200).json({ webhook })) .catch((error: Error) => res.status(404).json({ diff --git a/pages/api/hooks/index.ts b/pages/api/hooks/index.ts index 05b6e90d57..422a30e419 100644 --- a/pages/api/hooks/index.ts +++ b/pages/api/hooks/index.ts @@ -1,4 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; +import { v4 as uuidv4 } from "uuid"; import prisma from "@calcom/prisma"; @@ -60,7 +61,7 @@ async function createOrlistAllWebhooks( res.status(400).json({ message: "Invalid request body" }); return; } - const data = await prisma.webhook.create({ data: { ...safe.data, userId } }); + const data = await prisma.webhook.create({ data: { id: uuidv4(), ...safe.data, userId } }); if (data) res.status(201).json({ webhook: data, message: "Webhook created successfully" }); else (error: Error) => From 3fc22a8eff2cd9327ebd5e2c19af58925be5df16 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 1 Jun 2022 17:08:01 +0200 Subject: [PATCH 317/658] fix: remove comments --- lib/validations/webhook.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index c157a6e367..f5de69c45a 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -26,7 +26,6 @@ const schemaWebhookBaseBodyParams = Webhook.pick({ export const schemaWebhookCreateParams = z .object({ - // id: z.string(), subscriberUrl: z.string().url(), eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array(), active: z.boolean(), @@ -52,6 +51,7 @@ export const schemaWebhookReadPublic = Webhook.pick({ eventTypeId: true, payloadTemplate: true, eventTriggers: true, + /** @todo: find out how to properly add back and validate those. */ // eventType: true, // app: true, appId: true, From fe73973b7a9bf9869174a1d5e6b8ed1ed24da3ab Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 2 Jun 2022 15:55:52 +0200 Subject: [PATCH 318/658] fix: add uuid to api/package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 16c51d9d6b..57da05e5e6 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "next-validations": "^0.2.0", "typescript": "^4.6.4", "tzdata": "^1.0.30", + "uuid": "^8.3.2", "zod": "^3.16.0" } } From 12b7b3ecbf5486336ee5095924ddbdccc3102012 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 4 Jun 2022 01:17:01 +0200 Subject: [PATCH 319/658] fix: add event-types admin endpoints --- pages/api/event-types/index.ts | 58 +++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 0e2467692f..bfe8c3e7ee 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -4,12 +4,14 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { EventTypeResponse, EventTypesResponse } from "@lib/types"; +import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaEventTypeCreateBodyParams, schemaEventTypeReadPublic } from "@lib/validations/event-type"; async function createOrlistAllEventTypes( { method, body, userId }: NextApiRequest, res: NextApiResponse ) { + const isAdmin = await isAdminGuard(userId); if (method === "GET") { /** * @swagger @@ -29,20 +31,27 @@ async function createOrlistAllEventTypes( * 404: * description: No event types were found */ - const data = await prisma.user - .findUnique({ - where: { id: userId }, - rejectOnNotFound: true, - select: { eventTypes: true }, - }) - .catch((error) => res.status(404).json({ message: "No event types were found", error })); - if (data) res.status(200).json({ event_types: data.eventTypes }); - else - (error: Error) => - res.status(404).json({ - message: "No EventTypes were found", - error, - }); + if (!isAdmin) { + const data = await prisma.user + .findUnique({ + where: { id: userId }, + rejectOnNotFound: true, + select: { eventTypes: true }, + }) + .catch((error) => res.status(404).json({ message: "No event types were found", error })); + // @todo: add validations back schemaReadEventType.parse + if (data) res.status(200).json({ event_types: data.eventTypes }); + else + (error: Error) => + res.status(404).json({ + message: "No EventTypes were found", + error, + }); + } else { + const data = await prisma.eventType.findMany({}); + const event_types = data.map((eventType) => schemaEventTypeReadPublic.parse(eventType)); + if (event_types) res.status(200).json({ event_types }); + } } else if (method === "POST") { /** * @swagger @@ -92,17 +101,16 @@ async function createOrlistAllEventTypes( res.status(400).json({ message: "Invalid request body", error: safe.error }); return; } - - const data = await prisma.eventType.create({ data: { ...safe.data, userId } }); - const event_type = schemaEventTypeReadPublic.parse(data); - - if (data) res.status(201).json({ event_type, message: "EventType created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new event type", - error, - }); + if (!isAdmin) { + const data = await prisma.eventType.create({ data: { ...safe.data, userId } }); + const event_type = schemaEventTypeReadPublic.parse(data); + if (data) res.status(201).json({ event_type, message: "EventType created successfully" }); + } else { + // if admin don't re-set userId from input + const data = await prisma.eventType.create({ data: { ...safe.data } }); + const event_type = schemaEventTypeReadPublic.parse(data); + if (data) res.status(201).json({ event_type, message: "EventType created successfully" }); + } } else res.status(405).json({ message: `Method ${method} not allowed` }); } From 0fc374c810d282896aa41e2c3eb3374777c9cf69 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 4 Jun 2022 01:32:05 +0200 Subject: [PATCH 320/658] feat: add admin endpoint support for event-types id --- pages/api/event-types/[id].ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 20ad84d776..81cefb3ab7 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { EventTypeResponse } from "@lib/types"; +import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaEventTypeEditBodyParams, schemaEventTypeReadPublic } from "@lib/validations/event-type"; import { schemaQueryIdParseInt, @@ -14,19 +15,21 @@ export async function eventTypeById( { method, query, body, userId }: NextApiRequest, res: NextApiResponse ) { + const isAdmin = await isAdminGuard(userId); const safeQuery = schemaQueryIdParseInt.safeParse(query); if (!safeQuery.success) { res.status(400).json({ message: "Your query was invalid" }); return; } - const data = await await prisma.user.findUnique({ + const data = await prisma.user.findUnique({ where: { id: userId }, rejectOnNotFound: true, select: { eventTypes: true }, }); const userEventTypes = data.eventTypes.map((eventType) => eventType.id); - if (!userEventTypes.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); + if (!isAdmin || !userEventTypes.includes(safeQuery.data.id)) + res.status(401).json({ message: "Unauthorized" }); else { switch (method) { /** From 0eed3e51e48c2ebb6ba8461d4f84308d56602e29 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 4 Jun 2022 02:26:16 +0200 Subject: [PATCH 321/658] fix: only check event type ownership if not admin --- pages/api/event-types/[id].ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 81cefb3ab7..19435a0bc6 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -27,10 +27,9 @@ export async function eventTypeById( select: { eventTypes: true }, }); const userEventTypes = data.eventTypes.map((eventType) => eventType.id); - - if (!isAdmin || !userEventTypes.includes(safeQuery.data.id)) - res.status(401).json({ message: "Unauthorized" }); - else { + if (!isAdmin) { + if (!userEventTypes.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); + } else { switch (method) { /** * @swagger From e407a16766996a1b00e5c1791c94e2fdd3e46ed7 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 6 Jun 2022 18:17:10 +0200 Subject: [PATCH 322/658] feat: dynamic prisma --- jest.setup.ts | 2 +- lib/helpers/customApiEndpoints.ts | 20 ++++++ lib/helpers/extendRequest.ts | 19 +++++ lib/helpers/verifyApiKey.ts | 24 ++++--- lib/helpers/withMiddleware.ts | 6 +- lib/utils/isAdmin.ts | 2 +- pages/api/attendees/[id].ts | 13 ++-- pages/api/attendees/index.ts | 92 ++++++++++++++---------- pages/api/availabilities/[id].ts | 5 +- pages/api/availabilities/index.ts | 5 +- pages/api/booking-references/[id].ts | 5 +- pages/api/booking-references/index.ts | 4 +- pages/api/bookings/[id].ts | 13 ++-- pages/api/bookings/index.ts | 67 ++++++++++------- pages/api/custom-inputs/[id].ts | 4 +- pages/api/custom-inputs/index.ts | 4 +- pages/api/destination-calendars/[id].ts | 4 +- pages/api/destination-calendars/index.ts | 4 +- pages/api/event-references/[id].ts | 4 +- pages/api/event-references/index.ts | 4 +- pages/api/event-types/[id].ts | 4 +- pages/api/event-types/index.ts | 6 +- pages/api/hooks/[id].ts | 4 +- pages/api/hooks/index.ts | 4 +- pages/api/memberships/[id].ts | 4 +- pages/api/memberships/index.ts | 4 +- pages/api/payments/[id].ts | 4 +- pages/api/payments/index.ts | 4 +- pages/api/schedules/[id].ts | 4 +- pages/api/schedules/index.ts | 4 +- pages/api/selected-calendars/[id].ts | 4 +- pages/api/selected-calendars/index.ts | 4 +- pages/api/teams/[id].ts | 4 +- pages/api/teams/index.ts | 4 +- pages/api/users/[id].ts | 4 +- pages/api/users/index.ts | 4 +- 36 files changed, 201 insertions(+), 166 deletions(-) create mode 100644 lib/helpers/customApiEndpoints.ts create mode 100644 lib/helpers/extendRequest.ts diff --git a/jest.setup.ts b/jest.setup.ts index b764cee58f..d26c6b4183 100644 --- a/jest.setup.ts +++ b/jest.setup.ts @@ -1,6 +1,6 @@ import prisma from "@calcom/prisma"; afterEach((done) => { - prisma.$disconnect().then(); + prisma().$disconnect().then(); done(); }); diff --git a/lib/helpers/customApiEndpoints.ts b/lib/helpers/customApiEndpoints.ts new file mode 100644 index 0000000000..55d7dc78a2 --- /dev/null +++ b/lib/helpers/customApiEndpoints.ts @@ -0,0 +1,20 @@ +import { NextMiddleware } from "next-api-middleware"; + +import prisma from "@calcom/prisma"; + +// This replaces the prisma client for the cusotm one if the customApiId is valid +export const customApiEndpoints: NextMiddleware = async (req, res, next) => { + const { + query: { customApiId }, + } = req; + // If no custom api Id is provided, return the regular cal.com prisma client. + if (!customApiId) { + req.prisma = prisma(); + await next(); + } + // Hardcoded new database, this should be a dynamic call to console prisma/api? + const newDatabseUrl = process.env.DATABASE_PROD_URL; + req.prisma = prisma(newDatabseUrl); + + await next(); +}; diff --git a/lib/helpers/extendRequest.ts b/lib/helpers/extendRequest.ts new file mode 100644 index 0000000000..ac9e54d5ed --- /dev/null +++ b/lib/helpers/extendRequest.ts @@ -0,0 +1,19 @@ +import type { IncomingMessage } from "http"; +import { NextMiddleware } from "next-api-middleware"; + +import type { PrismaClient } from ".prisma/client"; + +/** @todo figure how to use the one from `@calcom/types`fi */ +/** @todo: remove once `@calcom/types` is updated with it.*/ +declare module "next" { + export interface NextApiRequest extends IncomingMessage { + userId: number; + method: string; + prisma: PrismaClient; + body: any; + query: { [key: string]: string | string[] }; + } +} +export const extendRequest: NextMiddleware = async (req, res, next) => { + await next(); +}; diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index c45f3d3c3f..d350f4e1f3 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -1,18 +1,19 @@ -import type { IncomingMessage } from "http"; +// import type { IncomingMessage } from "http"; import { NextMiddleware } from "next-api-middleware"; import { hashAPIKey } from "@calcom/ee/lib/api/apiKeys"; -import prisma from "@calcom/prisma"; -/** @todo figure how to use the one from `@calcom/types`fi */ -/** @todo: remove once `@calcom/types` is updated with it.*/ -declare module "next" { - export interface NextApiRequest extends IncomingMessage { - userId: number; - method: string; - query: { [key: string]: string | string[] }; - } -} +// // import prisma from "@calcom/prisma"; + +// /** @todo figure how to use the one from `@calcom/types`fi */ +// /** @todo: remove once `@calcom/types` is updated with it.*/ +// declare module "next" { +// export interface NextApiRequest extends IncomingMessage { +// userId: number; +// method: string; +// query: { [key: string]: string | string[] }; +// } +// } // Used to check if the apiKey is not expired, could be extracted if reused. but not for now. export const dateNotInPast = function (date: Date) { @@ -24,6 +25,7 @@ export const dateNotInPast = function (date: Date) { // This verifies the apiKey and sets the user if it is valid. export const verifyApiKey: NextMiddleware = async (req, res, next) => { + const { prisma } = req; if (!req.query.apiKey) return res.status(401).json({ message: "No apiKey provided" }); // We remove the prefix from the user provided api_key. If no env set default to "cal_" const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "cal_", ""); diff --git a/lib/helpers/withMiddleware.ts b/lib/helpers/withMiddleware.ts index c926eff4ec..73eef171f9 100644 --- a/lib/helpers/withMiddleware.ts +++ b/lib/helpers/withMiddleware.ts @@ -2,6 +2,8 @@ import { label } from "next-api-middleware"; import { addRequestId } from "./addRequestid"; import { captureErrors } from "./captureErrors"; +import { customApiEndpoints } from "./customApiEndpoints"; +import { extendRequest } from "./extendRequest"; import { HTTP_POST, HTTP_DELETE, @@ -22,9 +24,11 @@ const withMiddleware = label( HTTP_DELETE, addRequestId, verifyApiKey, + customApiEndpoints, + extendRequest, sentry: captureErrors, }, - ["sentry", "verifyApiKey", "addRequestId"] // <-- Provide a list of middleware to call automatically + ["sentry", "customApiEndpoints", "verifyApiKey", "addRequestId", "extendRequest"] // <-- Provide a list of middleware to call automatically ); export { withMiddleware }; diff --git a/lib/utils/isAdmin.ts b/lib/utils/isAdmin.ts index 64af37367f..4991934509 100644 --- a/lib/utils/isAdmin.ts +++ b/lib/utils/isAdmin.ts @@ -3,6 +3,6 @@ import { UserPermissionRole } from "@prisma/client"; import prisma from "@calcom/prisma"; export const isAdminGuard = async (userId: number) => { - const user = await prisma.user.findUnique({ where: { id: userId } }); + const user = await prisma().user.findUnique({ where: { id: userId } }); return user?.role === UserPermissionRole.ADMIN; }; diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index a1674d87a4..c37e92b9ba 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -1,9 +1,9 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - +// // import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { AttendeeResponse } from "@lib/types"; +import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaAttendeeEditBodyParams, schemaAttendeeReadPublic } from "@lib/validations/attendee"; import { schemaQueryIdParseInt, @@ -11,9 +11,10 @@ import { } from "@lib/validations/shared/queryIdTransformParseInt"; export async function attendeeById( - { method, query, body, userId }: NextApiRequest, + { method, query, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { + const isAdmin = await isAdminGuard(userId); const safeQuery = schemaQueryIdParseInt.safeParse(query); if (!safeQuery.success) { res.status(400).json({ error: safeQuery.error }); @@ -34,8 +35,10 @@ export async function attendeeById( .map((attendee) => attendee.id) ); // @note: Here we make sure to only return attendee's of the user's own bookings. - if (!userBookingsAttendeeIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); - else { + if (!isAdmin) { + if (!userBookingsAttendeeIds.includes(safeQuery.data.id)) + res.status(401).json({ message: "Unauthorized" }); + } else { switch (method) { /** * @swagger diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index eaae0b28ff..25f459823e 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -1,24 +1,31 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import db from "@calcom/prisma"; - +// import db from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { AttendeeResponse, AttendeesResponse } from "@lib/types"; +import type { AttendeeResponse, AttendeesResponse } from "@lib/types"; +import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaAttendeeCreateBodyParams, schemaAttendeeReadPublic } from "@lib/validations/attendee"; async function createOrlistAllAttendees( - { method, userId, body }: NextApiRequest, + { method, userId, body, prisma }: NextApiRequest, res: NextApiResponse ) { - const userBookings = await db.booking.findMany({ - where: { - userId, - }, - include: { - attendees: true, - }, - }); - const attendees = userBookings.map((booking) => booking.attendees).flat(); + const isAdmin = await isAdminGuard(userId); + let attendees; + if (!isAdmin) { + const userBookings = await prisma.booking.findMany({ + where: { + userId, + }, + include: { + attendees: true, + }, + }); + attendees = userBookings.map((booking) => booking.attendees).flat(); + } else { + const data = await prisma.attendee.findMany(); + attendees = data.map((attendee) => schemaAttendeeReadPublic.parse(attendee)); + } if (method === "GET") { /** * @swagger @@ -37,12 +44,7 @@ async function createOrlistAllAttendees( * description: No attendees were found */ if (attendees) res.status(200).json({ attendees }); - else - (error: Error) => - res.status(404).json({ - message: "No Attendees were found", - error, - }); + else (error: Error) => res.status(400).json({ error }); } else if (method === "POST") { /** * @swagger @@ -90,16 +92,40 @@ async function createOrlistAllAttendees( res.status(400).json({ message: "Invalid request body", error: safePost.error }); return; } - const userWithBookings = await db.user.findUnique({ where: { id: userId }, include: { bookings: true } }); - if (!userWithBookings) { - res.status(404).json({ message: "User not found" }); - return; - } - const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); - // Here we make sure to only return attendee's of the user's own bookings. - if (!userBookingIds.includes(safePost.data.bookingId)) res.status(401).json({ message: "Unauthorized" }); - else { - const data = await db.attendee.create({ + if (!isAdmin) { + const userWithBookings = await prisma.user.findUnique({ + where: { id: userId }, + include: { bookings: true }, + }); + if (!userWithBookings) { + res.status(404).json({ message: "User not found" }); + return; + } + const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); + // Here we make sure to only return attendee's of the user's own bookings. + if (!userBookingIds.includes(safePost.data.bookingId)) + res.status(401).json({ message: "Unauthorized" }); + else { + const data = await prisma.attendee.create({ + data: { + email: safePost.data.email, + name: safePost.data.name, + timeZone: safePost.data.timeZone, + booking: { connect: { id: safePost.data.bookingId } }, + }, + }); + const attendee = schemaAttendeeReadPublic.parse(data); + + if (attendee) { + res.status(201).json({ + attendee, + message: "Attendee created successfully", + }); + } else (error: Error) => res.status(400).json({ error }); + } + } else { + // @todo: check real availability times before booking + const data = await prisma.attendee.create({ data: { email: safePost.data.email, name: safePost.data.name, @@ -114,13 +140,7 @@ async function createOrlistAllAttendees( attendee, message: "Attendee created successfully", }); - } else { - (error: Error) => - res.status(400).json({ - message: "Could not create new attendee", - error, - }); - } + } else (error: Error) => res.status(400).json({ error }); } } else res.status(405).json({ message: `Method ${method} not allowed` }); } diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index 0b6a58c338..3dcbdbbca3 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -1,7 +1,6 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - +// // import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { AvailabilityResponse } from "@lib/types"; import { @@ -14,7 +13,7 @@ import { } from "@lib/validations/shared/queryIdTransformParseInt"; export async function availabilityById( - { method, query, body, userId }: NextApiRequest, + { method, query, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index bf17bd1ede..0e45564270 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -1,7 +1,6 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - +// import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { AvailabilityResponse, AvailabilitiesResponse } from "@lib/types"; import { @@ -10,7 +9,7 @@ import { } from "@lib/validations/availability"; async function createOrlistAllAvailabilities( - { method, body, userId }: NextApiRequest, + { method, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { if (method === "GET") { diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts index f7a14056eb..17e444d717 100644 --- a/pages/api/booking-references/[id].ts +++ b/pages/api/booking-references/[id].ts @@ -1,7 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { BookingReferenceResponse } from "@lib/types"; import { @@ -14,7 +12,7 @@ import { } from "@lib/validations/shared/queryIdTransformParseInt"; export async function bookingReferenceById( - { method, query, body, userId }: NextApiRequest, + { method, query, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); @@ -64,7 +62,6 @@ export async function bookingReferenceById( .then((data) => schemaBookingReferenceReadPublic.parse(data)) .then((booking_reference) => res.status(200).json({ booking_reference })) .catch((error: Error) => { - console.log(error); res.status(404).json({ message: `BookingReference with id: ${safeQuery.data.id} not found`, error, diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index 58e45d5c9e..5c63a605b7 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -1,7 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import { BookingReferenceResponse, BookingReferencesResponse } from "@lib/types"; import { @@ -10,7 +8,7 @@ import { } from "@lib/validations/booking-reference"; async function createOrlistAllBookingReferences( - { method, userId, body }: NextApiRequest, + { method, userId, body, prisma }: NextApiRequest, res: NextApiResponse ) { const userWithBookings = await prisma.user.findUnique({ diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index 7e17c9613a..68540fb69b 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -1,9 +1,9 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - +// import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { BookingResponse } from "@lib/types"; +import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaBookingEditBodyParams, schemaBookingReadPublic } from "@lib/validations/booking"; import { schemaQueryIdParseInt, @@ -11,7 +11,7 @@ import { } from "@lib/validations/shared/queryIdTransformParseInt"; export async function bookingById( - { method, query, body, userId }: NextApiRequest, + { method, query, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); @@ -25,8 +25,11 @@ export async function bookingById( }); if (!userWithBookings) throw new Error("User not found"); const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); - if (!userBookingIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); - else { + const isAdmin = await isAdminGuard(userId); + + if (!isAdmin) { + if (!userBookingIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); + } else { switch (method) { /** * @swagger diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 40f24283ee..f1befaeb23 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -1,16 +1,16 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - +// import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { BookingResponse, BookingsResponse } from "@lib/types"; +import type { BookingResponse, BookingsResponse } from "@lib/types"; +import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaBookingCreateBodyParams, schemaBookingReadPublic } from "@lib/validations/booking"; async function createOrlistAllBookings( - { method, body, userId }: NextApiRequest, + { method, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { - console.log("userIduserId", userId); + const isAdmin = await isAdminGuard(userId); if (method === "GET") { /** * @swagger @@ -28,15 +28,29 @@ async function createOrlistAllBookings( * 404: * description: No bookings were found */ - const data = await prisma.booking.findMany({ where: { userId } }); - const bookings = data.map((booking) => schemaBookingReadPublic.parse(booking)); - if (bookings) res.status(200).json({ bookings }); - else - (error: Error) => - res.status(404).json({ - message: "No Bookings were found", - error, - }); + if (!isAdmin) { + const data = await prisma.booking.findMany({ where: { userId } }); + const bookings = data.map((booking) => schemaBookingReadPublic.parse(booking)); + if (bookings) res.status(200).json({ bookings }); + else { + (error: Error) => + res.status(404).json({ + message: "No Bookings were found", + error, + }); + } + } else { + const data = await prisma.booking.findMany(); + const bookings = data.map((booking) => schemaBookingReadPublic.parse(booking)); + if (bookings) res.status(200).json({ bookings }); + else { + (error: Error) => + res.status(404).json({ + message: "No Bookings were found", + error, + }); + } + } } else if (method === "POST") { /** * @swagger @@ -77,19 +91,20 @@ async function createOrlistAllBookings( res.status(400).json({ message: "Bad request. Booking body is invalid." }); return; } - safe.data.userId = userId; - const data = await prisma.booking.create({ data: { ...safe.data } }); - const booking = schemaBookingReadPublic.parse(data); + if (!isAdmin) { + safe.data.userId = userId; + const data = await prisma.booking.create({ data: { ...safe.data } }); + const booking = schemaBookingReadPublic.parse(data); - if (booking) res.status(201).json({ booking, message: "Booking created successfully" }); - else - (error: Error) => { - console.log(error); - res.status(400).json({ - message: "Could not create new booking", - error, - }); - }; + if (booking) res.status(201).json({ booking, message: "Booking created successfully" }); + else (error: Error) => res.status(400).json({ error }); + } else { + const data = await prisma.booking.create({ data: { ...safe.data } }); + const booking = schemaBookingReadPublic.parse(data); + + if (booking) res.status(201).json({ booking, message: "Booking created successfully" }); + else (error: Error) => res.status(400).json({ error }); + } } else res.status(405).json({ message: `Method ${method} not allowed` }); } diff --git a/pages/api/custom-inputs/[id].ts b/pages/api/custom-inputs/[id].ts index 7423a10b99..5b778714ad 100644 --- a/pages/api/custom-inputs/[id].ts +++ b/pages/api/custom-inputs/[id].ts @@ -1,7 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { EventTypeCustomInputResponse } from "@lib/types"; import { @@ -72,7 +70,7 @@ import { * description: Authorization information is missing or invalid. */ async function eventTypeById( - { method, query, body, userId }: NextApiRequest, + { method, query, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); diff --git a/pages/api/custom-inputs/index.ts b/pages/api/custom-inputs/index.ts index e1c2d484ed..17500249aa 100644 --- a/pages/api/custom-inputs/index.ts +++ b/pages/api/custom-inputs/index.ts @@ -1,7 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import { EventTypeCustomInputResponse, EventTypeCustomInputsResponse } from "@lib/types"; import { @@ -10,7 +8,7 @@ import { } from "@lib/validations/event-type-custom-input"; async function createOrlistAllEventTypeCustomInputs( - { userId, method, body }: NextApiRequest, + { userId, method, body, prisma }: NextApiRequest, res: NextApiResponse ) { const data = await prisma.eventType.findMany({ where: { userId } }); diff --git a/pages/api/destination-calendars/[id].ts b/pages/api/destination-calendars/[id].ts index 528b9e5f2d..307e2634ba 100644 --- a/pages/api/destination-calendars/[id].ts +++ b/pages/api/destination-calendars/[id].ts @@ -1,7 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { DestinationCalendarResponse } from "@lib/types"; import { @@ -14,7 +12,7 @@ import { } from "@lib/validations/shared/queryIdTransformParseInt"; export async function destionationCalendarById( - { method, query, body, userId }: NextApiRequest, + { method, query, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); diff --git a/pages/api/destination-calendars/index.ts b/pages/api/destination-calendars/index.ts index bfd7df6d89..5fced320d9 100644 --- a/pages/api/destination-calendars/index.ts +++ b/pages/api/destination-calendars/index.ts @@ -1,7 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import { DestinationCalendarResponse, DestinationCalendarsResponse } from "@lib/types"; import { @@ -10,7 +8,7 @@ import { } from "@lib/validations/destination-calendar"; async function createOrlistAllDestinationCalendars( - { method, body, userId }: NextApiRequest, + { method, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { if (method === "GET") { diff --git a/pages/api/event-references/[id].ts b/pages/api/event-references/[id].ts index 7a72fea4c7..58bc27599d 100644 --- a/pages/api/event-references/[id].ts +++ b/pages/api/event-references/[id].ts @@ -1,7 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { DailyEventReferenceResponse } from "@lib/types"; import { @@ -14,7 +12,7 @@ import { } from "@lib/validations/shared/queryIdTransformParseInt"; export async function dailyEventReferenceById( - { method, query, body, userId }: NextApiRequest, + { method, query, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); diff --git a/pages/api/event-references/index.ts b/pages/api/event-references/index.ts index 48a438e321..449737cd06 100644 --- a/pages/api/event-references/index.ts +++ b/pages/api/event-references/index.ts @@ -1,7 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import { DailyEventReferenceResponse, DailyEventReferencesResponse } from "@lib/types"; import { @@ -10,7 +8,7 @@ import { } from "@lib/validations/event-reference"; async function createOrlistAllDailyEventReferences( - { method, body, userId }: NextApiRequest, + { method, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { const userBookings = await prisma.booking.findMany({ where: { userId } }); diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 19435a0bc6..117ee7bf43 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -1,7 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { EventTypeResponse } from "@lib/types"; import { isAdminGuard } from "@lib/utils/isAdmin"; @@ -12,7 +10,7 @@ import { } from "@lib/validations/shared/queryIdTransformParseInt"; export async function eventTypeById( - { method, query, body, userId }: NextApiRequest, + { method, query, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { const isAdmin = await isAdminGuard(userId); diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index bfe8c3e7ee..b7939bd0c7 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -1,14 +1,12 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { EventTypeResponse, EventTypesResponse } from "@lib/types"; +import type { EventTypeResponse, EventTypesResponse } from "@lib/types"; import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaEventTypeCreateBodyParams, schemaEventTypeReadPublic } from "@lib/validations/event-type"; async function createOrlistAllEventTypes( - { method, body, userId }: NextApiRequest, + { method, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { const isAdmin = await isAdminGuard(userId); diff --git a/pages/api/hooks/[id].ts b/pages/api/hooks/[id].ts index 32a81e7b12..e88761736c 100644 --- a/pages/api/hooks/[id].ts +++ b/pages/api/hooks/[id].ts @@ -1,14 +1,12 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { WebhookResponse } from "@lib/types"; import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; import { schemaWebhookEditBodyParams, schemaWebhookReadPublic } from "@lib/validations/webhook"; export async function WebhookById( - { method, query, body, userId }: NextApiRequest, + { method, query, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { const safeQuery = schemaQueryIdAsString.safeParse(query); diff --git a/pages/api/hooks/index.ts b/pages/api/hooks/index.ts index 422a30e419..3fb8380f4c 100644 --- a/pages/api/hooks/index.ts +++ b/pages/api/hooks/index.ts @@ -1,14 +1,12 @@ import type { NextApiRequest, NextApiResponse } from "next"; import { v4 as uuidv4 } from "uuid"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import { WebhookResponse, WebhooksResponse } from "@lib/types"; import { schemaWebhookCreateBodyParams } from "@lib/validations/webhook"; async function createOrlistAllWebhooks( - { method, body, userId }: NextApiRequest, + { method, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { if (method === "GET") { diff --git a/pages/api/memberships/[id].ts b/pages/api/memberships/[id].ts index ea99860d14..b6050ebbe9 100644 --- a/pages/api/memberships/[id].ts +++ b/pages/api/memberships/[id].ts @@ -1,14 +1,12 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { MembershipResponse } from "@lib/types"; import { schemaMembershipBodyParams, schemaMembershipPublic } from "@lib/validations/membership"; import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; export async function membershipById( - { method, query, body, userId }: NextApiRequest, + { method, query, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { const safeQuery = schemaQueryIdAsString.safeParse(query); diff --git a/pages/api/memberships/index.ts b/pages/api/memberships/index.ts index efd3fb278c..5aaa36f6db 100644 --- a/pages/api/memberships/index.ts +++ b/pages/api/memberships/index.ts @@ -1,13 +1,11 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import { MembershipResponse, MembershipsResponse } from "@lib/types"; import { schemaMembershipBodyParams, schemaMembershipPublic } from "@lib/validations/membership"; async function createOrlistAllMemberships( - { method, body, userId }: NextApiRequest, + { method, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { if (method === "GET") { diff --git a/pages/api/payments/[id].ts b/pages/api/payments/[id].ts index 99d515fe45..26f2138536 100644 --- a/pages/api/payments/[id].ts +++ b/pages/api/payments/[id].ts @@ -1,7 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { PaymentResponse } from "@lib/types"; import { schemaPaymentPublic } from "@lib/validations/payment"; @@ -33,7 +31,7 @@ import { * description: Payment was not found */ export async function paymentById( - { method, query, userId }: NextApiRequest, + { method, query, userId, prisma }: NextApiRequest, res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); diff --git a/pages/api/payments/index.ts b/pages/api/payments/index.ts index d758421f46..829d24681d 100644 --- a/pages/api/payments/index.ts +++ b/pages/api/payments/index.ts @@ -1,7 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import { PaymentsResponse } from "@lib/types"; import { schemaPaymentPublic } from "@lib/validations/payment"; @@ -21,7 +19,7 @@ import { schemaPaymentPublic } from "@lib/validations/payment"; * 404: * description: No payments were found */ -async function allPayments({ userId }: NextApiRequest, res: NextApiResponse) { +async function allPayments({ userId, prisma }: NextApiRequest, res: NextApiResponse) { const userWithBookings = await prisma.user.findUnique({ where: { id: userId }, include: { bookings: true }, diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index 305cc5c51b..593f9d7846 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -1,7 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { ScheduleResponse } from "@lib/types"; import { schemaScheduleBodyParams, schemaSchedulePublic } from "@lib/validations/schedule"; @@ -11,7 +9,7 @@ import { } from "@lib/validations/shared/queryIdTransformParseInt"; export async function scheduleById( - { method, query, body, userId }: NextApiRequest, + { method, query, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index 4421844047..81964f4030 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -1,13 +1,11 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import { ScheduleResponse, SchedulesResponse } from "@lib/types"; import { schemaScheduleBodyParams, schemaSchedulePublic } from "@lib/validations/schedule"; async function createOrlistAllSchedules( - { method, body, userId }: NextApiRequest, + { method, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { if (method === "GET") { diff --git a/pages/api/selected-calendars/[id].ts b/pages/api/selected-calendars/[id].ts index 88dca61806..ea2037fba3 100644 --- a/pages/api/selected-calendars/[id].ts +++ b/pages/api/selected-calendars/[id].ts @@ -1,7 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { SelectedCalendarResponse } from "@lib/types"; import { @@ -11,7 +9,7 @@ import { import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; export async function selectedCalendarById( - { method, query, body, userId }: NextApiRequest, + { method, query, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { const safeQuery = schemaQueryIdAsString.safeParse(query); diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index f0021f9f0e..3ab69494a8 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -1,7 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import { SelectedCalendarResponse, SelectedCalendarsResponse } from "@lib/types"; import { @@ -10,7 +8,7 @@ import { } from "@lib/validations/selected-calendar"; async function createOrlistAllSelectedCalendars( - { method, body, userId }: NextApiRequest, + { method, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { if (method === "GET") { diff --git a/pages/api/teams/[id].ts b/pages/api/teams/[id].ts index 2cfd371749..65dd8d116e 100644 --- a/pages/api/teams/[id].ts +++ b/pages/api/teams/[id].ts @@ -1,7 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { TeamResponse } from "@lib/types"; import { @@ -72,7 +70,7 @@ import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; * description: Authorization information is missing or invalid. */ export async function teamById( - { method, query, body, userId }: NextApiRequest, + { method, query, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index e5f870cef6..1dcc046f6e 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -1,14 +1,12 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import { TeamResponse, TeamsResponse } from "@lib/types"; import { schemaMembershipPublic } from "@lib/validations/membership"; import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; async function createOrlistAllTeams( - { method, body, userId }: NextApiRequest, + { method, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { if (method === "GET") { diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index 65b864c652..276f015f9d 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -1,7 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { UserResponse } from "@lib/types"; import { isAdminGuard } from "@lib/utils/isAdmin"; @@ -12,7 +10,7 @@ import { import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations/user"; export async function userById( - { method, query, body, userId }: NextApiRequest, + { method, query, body, userId, prisma }: NextApiRequest, res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 3839ae21b6..cbb0eab69a 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -1,7 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import prisma from "@calcom/prisma"; - import { withMiddleware } from "@lib/helpers/withMiddleware"; import { UserResponse, UsersResponse } from "@lib/types"; import { isAdminGuard } from "@lib/utils/isAdmin"; @@ -24,7 +22,7 @@ import { schemaUserReadPublic, schemaUserCreateBodyParams } from "@lib/validatio * description: No users were found */ async function getAllorCreateUser( - { userId, method, body }: NextApiRequest, + { userId, method, body, prisma }: NextApiRequest, res: NextApiResponse ) { const isAdmin = await isAdminGuard(userId); From cd03f5a821e4271df3291b4f1603d1574de9f269 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed, 8 Jun 2022 13:06:28 +0530 Subject: [PATCH 323/658] Adds team event type check --- pages/api/hooks/[id].ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pages/api/hooks/[id].ts b/pages/api/hooks/[id].ts index 32a81e7b12..3a14efa592 100644 --- a/pages/api/hooks/[id].ts +++ b/pages/api/hooks/[id].ts @@ -95,6 +95,27 @@ export async function WebhookById( return; } } + if (safeBody.data.eventTypeId) { + const team = await ctx.prisma.team.findFirst({ + where: { + eventTypes: { + some: { + id: safeBody.data.eventTypeId, + }, + }, + }, + include: { + members: true, + }, + }); + + // Team should be available and the user should be a member of the team + if (!team?.members.some((membership) => membership.userId === userId)) { + throw new TRPCError({ + code: "UNAUTHORIZED", + }); + } + } await prisma.webhook .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) .then((data) => schemaWebhookReadPublic.parse(data)) From bae84f2ce4e7daa9fcc3c8984a18997946cdab20 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed, 8 Jun 2022 13:12:05 +0530 Subject: [PATCH 324/658] Added team event check to POST --- pages/api/hooks/index.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pages/api/hooks/index.ts b/pages/api/hooks/index.ts index 422a30e419..e92a681080 100644 --- a/pages/api/hooks/index.ts +++ b/pages/api/hooks/index.ts @@ -61,6 +61,27 @@ async function createOrlistAllWebhooks( res.status(400).json({ message: "Invalid request body" }); return; } + if (safe.data.eventTypeId) { + const team = await ctx.prisma.team.findFirst({ + where: { + eventTypes: { + some: { + id: safe.data.eventTypeId, + }, + }, + }, + include: { + members: true, + }, + }); + + // Team should be available and the user should be a member of the team + if (!team?.members.some((membership) => membership.userId === userId)) { + throw new TRPCError({ + code: "UNAUTHORIZED", + }); + } + } const data = await prisma.webhook.create({ data: { id: uuidv4(), ...safe.data, userId } }); if (data) res.status(201).json({ webhook: data, message: "Webhook created successfully" }); else From ef3838b4764cf57d9928fa6581f814652627248b Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed, 8 Jun 2022 13:20:09 +0530 Subject: [PATCH 325/658] hotfix ctx removal --- pages/api/hooks/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/hooks/index.ts b/pages/api/hooks/index.ts index e92a681080..f3f3257499 100644 --- a/pages/api/hooks/index.ts +++ b/pages/api/hooks/index.ts @@ -62,7 +62,7 @@ async function createOrlistAllWebhooks( return; } if (safe.data.eventTypeId) { - const team = await ctx.prisma.team.findFirst({ + const team = await prisma.team.findFirst({ where: { eventTypes: { some: { From b881312f1038ea9b67afa52c6a01a9c3c07f8028 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed, 8 Jun 2022 13:20:44 +0530 Subject: [PATCH 326/658] hotfix ctx removal --- pages/api/hooks/[id].ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/hooks/[id].ts b/pages/api/hooks/[id].ts index 3a14efa592..7debc7ac8d 100644 --- a/pages/api/hooks/[id].ts +++ b/pages/api/hooks/[id].ts @@ -96,7 +96,7 @@ export async function WebhookById( } } if (safeBody.data.eventTypeId) { - const team = await ctx.prisma.team.findFirst({ + const team = await prisma.team.findFirst({ where: { eventTypes: { some: { From 9b1dffbdb9e64969c79d87c892e4a0083e8e64f1 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed, 8 Jun 2022 13:27:48 +0530 Subject: [PATCH 327/658] 401 return fix --- pages/api/hooks/index.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pages/api/hooks/index.ts b/pages/api/hooks/index.ts index f3f3257499..ec85ab13df 100644 --- a/pages/api/hooks/index.ts +++ b/pages/api/hooks/index.ts @@ -77,9 +77,8 @@ async function createOrlistAllWebhooks( // Team should be available and the user should be a member of the team if (!team?.members.some((membership) => membership.userId === userId)) { - throw new TRPCError({ - code: "UNAUTHORIZED", - }); + res.status(401).json({ message: "Unauthorized" }); + return; } } const data = await prisma.webhook.create({ data: { id: uuidv4(), ...safe.data, userId } }); From db6f5cad1512ac6d6efc8b4c9368634ebcde348b Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed, 8 Jun 2022 13:28:22 +0530 Subject: [PATCH 328/658] 401 message fix --- pages/api/hooks/[id].ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pages/api/hooks/[id].ts b/pages/api/hooks/[id].ts index 7debc7ac8d..8f81fc62d1 100644 --- a/pages/api/hooks/[id].ts +++ b/pages/api/hooks/[id].ts @@ -111,9 +111,8 @@ export async function WebhookById( // Team should be available and the user should be a member of the team if (!team?.members.some((membership) => membership.userId === userId)) { - throw new TRPCError({ - code: "UNAUTHORIZED", - }); + res.status(401).json({ message: "Unauthorized" }); + return; } } await prisma.webhook From 180e925bed62e037f068dc9b513b38c8b4869c7a Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 8 Jun 2022 18:52:25 +0200 Subject: [PATCH 329/658] feat: dynamic prisma almost working --- README.md | 10 ++ jest.setup.ts | 2 +- lib/helpers/customApiEndpoints.ts | 20 ---- lib/helpers/customPrisma.ts | 45 +++++++++ lib/helpers/extendRequest.ts | 6 +- lib/helpers/verifyApiKey.ts | 18 ++-- lib/helpers/withMiddleware.ts | 7 +- lib/utils/isAdmin.ts | 2 +- next.config.js | 6 ++ package.json | 4 + pages/api/users/[id]/availability.ts | 144 +++++++++++++++++++++++++++ tsconfig.json | 1 + 12 files changed, 226 insertions(+), 39 deletions(-) delete mode 100644 lib/helpers/customApiEndpoints.ts create mode 100644 lib/helpers/customPrisma.ts create mode 100644 pages/api/users/[id]/availability.ts diff --git a/README.md b/README.md index 8c39f8457f..7b9f1c7472 100644 --- a/README.md +++ b/README.md @@ -178,3 +178,13 @@ We make sure of this by not using next in dev, but next build && next start, if See . Here in dev mode OPTIONS method is hardcoded to return only GET and OPTIONS as allowed method. Running in Production mode would cause this file to be not used. This is hot-reloading logic only. To remove this limitation, we need to ensure that on local endpoints are requested by swagger at /api/v1 and not /v1 + + +## Hosted api through cal.com + +Go to console.com +Add a deployment or go to an existing one. +Activate API or Admin addon +Provide your DATABASE-URL +Store it safely, you'll get a customApiID, save it. +call api.cal.com?apiKey=your_cal_instance_apiKey&customApiId=cal_datasource_key \ No newline at end of file diff --git a/jest.setup.ts b/jest.setup.ts index d26c6b4183..b764cee58f 100644 --- a/jest.setup.ts +++ b/jest.setup.ts @@ -1,6 +1,6 @@ import prisma from "@calcom/prisma"; afterEach((done) => { - prisma().$disconnect().then(); + prisma.$disconnect().then(); done(); }); diff --git a/lib/helpers/customApiEndpoints.ts b/lib/helpers/customApiEndpoints.ts deleted file mode 100644 index 55d7dc78a2..0000000000 --- a/lib/helpers/customApiEndpoints.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { NextMiddleware } from "next-api-middleware"; - -import prisma from "@calcom/prisma"; - -// This replaces the prisma client for the cusotm one if the customApiId is valid -export const customApiEndpoints: NextMiddleware = async (req, res, next) => { - const { - query: { customApiId }, - } = req; - // If no custom api Id is provided, return the regular cal.com prisma client. - if (!customApiId) { - req.prisma = prisma(); - await next(); - } - // Hardcoded new database, this should be a dynamic call to console prisma/api? - const newDatabseUrl = process.env.DATABASE_PROD_URL; - req.prisma = prisma(newDatabseUrl); - - await next(); -}; diff --git a/lib/helpers/customPrisma.ts b/lib/helpers/customPrisma.ts new file mode 100644 index 0000000000..27bc3261e2 --- /dev/null +++ b/lib/helpers/customPrisma.ts @@ -0,0 +1,45 @@ +import { hash } from "bcryptjs"; +import cache from "memory-cache"; +import { NextMiddleware } from "next-api-middleware"; + +import { prismaAdmin } from "@calcom/console/modules/common/utils/prisma"; +import { asStringOrUndefined, asStringOrNull } from "@calcom/lib/asStringOrNull"; +import { PRISMA_CLIENT_CACHING_TIME } from "@calcom/lib/constants"; +import { prisma, customPrisma } from "@calcom/prisma"; + +// This replaces the prisma client for the cusotm one if the customCredentialsId is valid +export const customPrismaClient: NextMiddleware = async (req, res, next) => { + const { + query: { customCredentialsId }, + } = req; + // If no custom api Id is provided, attach to request the regular cal.com prisma client. + if (!customCredentialsId) { + req.prisma = prisma; + await next(); + } else { + const id = asStringOrUndefined(customCredentialsId); + + // If we have a customCredentialsId, we check if it is valid. + const dataCredentials = await prismaAdmin.dataCredentials.findUnique({ + where: { id }, + }); + if (!dataCredentials) { + res.status(400).json({ error: "Invalid custom credentials id" }); + return; + } + const credentials = dataCredentials?.credentials; + const hashedUrl = await hash(credentials, 12); + + const cachedPrisma = cache.get(hashedUrl); + + if (!cachedPrisma) { + cache.put( + hashedUrl, + customPrisma({ datasources: { db: { url: credentials } } }), + PRISMA_CLIENT_CACHING_TIME // Cache the prisma client for 24 hours + ); + } + req.prisma = cachedPrisma; + } + await next(); +}; diff --git a/lib/helpers/extendRequest.ts b/lib/helpers/extendRequest.ts index ac9e54d5ed..d0226a255c 100644 --- a/lib/helpers/extendRequest.ts +++ b/lib/helpers/extendRequest.ts @@ -3,14 +3,16 @@ import { NextMiddleware } from "next-api-middleware"; import type { PrismaClient } from ".prisma/client"; -/** @todo figure how to use the one from `@calcom/types`fi */ +/** @todo figure how to use the one from `@calcom/types` */ /** @todo: remove once `@calcom/types` is updated with it.*/ declare module "next" { export interface NextApiRequest extends IncomingMessage { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + body: any; userId: number; method: string; prisma: PrismaClient; - body: any; + session: { user: { id: number } }; query: { [key: string]: string | string[] }; } } diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index d350f4e1f3..9068f2be73 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -3,18 +3,6 @@ import { NextMiddleware } from "next-api-middleware"; import { hashAPIKey } from "@calcom/ee/lib/api/apiKeys"; -// // import prisma from "@calcom/prisma"; - -// /** @todo figure how to use the one from `@calcom/types`fi */ -// /** @todo: remove once `@calcom/types` is updated with it.*/ -// declare module "next" { -// export interface NextApiRequest extends IncomingMessage { -// userId: number; -// method: string; -// query: { [key: string]: string | string[] }; -// } -// } - // Used to check if the apiKey is not expired, could be extracted if reused. but not for now. export const dateNotInPast = function (date: Date) { const now = new Date(); @@ -27,12 +15,18 @@ export const dateNotInPast = function (date: Date) { export const verifyApiKey: NextMiddleware = async (req, res, next) => { const { prisma } = req; if (!req.query.apiKey) return res.status(401).json({ message: "No apiKey provided" }); + console.log("req.query.apiKey", req.query.apiKey); + // We remove the prefix from the user provided api_key. If no env set default to "cal_" const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "cal_", ""); + console.log("strippedApiKey", strippedApiKey); + // Hash the key again before matching against the database records. const hashedKey = hashAPIKey(strippedApiKey); + console.log("hashedKey", hashedKey); // Check if the hashed api key exists in database. const apiKey = await prisma.apiKey.findUnique({ where: { hashedKey } }); + // console.log("apiKey", apiKey); // If we cannot find any api key. Throw a 401 Unauthorized. if (!apiKey) return res.status(401).json({ error: "Your apiKey is not valid" }); if (apiKey.expiresAt && dateNotInPast(apiKey.expiresAt)) { diff --git a/lib/helpers/withMiddleware.ts b/lib/helpers/withMiddleware.ts index 73eef171f9..05b21cbf0d 100644 --- a/lib/helpers/withMiddleware.ts +++ b/lib/helpers/withMiddleware.ts @@ -2,7 +2,7 @@ import { label } from "next-api-middleware"; import { addRequestId } from "./addRequestid"; import { captureErrors } from "./captureErrors"; -import { customApiEndpoints } from "./customApiEndpoints"; +import { customPrismaClient } from "./customPrisma"; import { extendRequest } from "./extendRequest"; import { HTTP_POST, @@ -24,11 +24,12 @@ const withMiddleware = label( HTTP_DELETE, addRequestId, verifyApiKey, - customApiEndpoints, + customPrismaClient, extendRequest, sentry: captureErrors, }, - ["sentry", "customApiEndpoints", "verifyApiKey", "addRequestId", "extendRequest"] // <-- Provide a list of middleware to call automatically + // The order here, determines the order of execution, put customPrismaClient before verifyApiKey always. + ["sentry", "customPrismaClient", "verifyApiKey", "addRequestId", "extendRequest"] // <-- Provide a list of middleware to call automatically ); export { withMiddleware }; diff --git a/lib/utils/isAdmin.ts b/lib/utils/isAdmin.ts index 4991934509..64af37367f 100644 --- a/lib/utils/isAdmin.ts +++ b/lib/utils/isAdmin.ts @@ -3,6 +3,6 @@ import { UserPermissionRole } from "@prisma/client"; import prisma from "@calcom/prisma"; export const isAdminGuard = async (userId: number) => { - const user = await prisma().user.findUnique({ where: { id: userId } }); + const user = await prisma.user.findUnique({ where: { id: userId } }); return user?.role === UserPermissionRole.ADMIN; }; diff --git a/next.config.js b/next.config.js index 5e40353edf..06f2023723 100644 --- a/next.config.js +++ b/next.config.js @@ -2,8 +2,14 @@ // This makes our @calcom/prisma package from the monorepo to be transpiled and usable by API const withTM = require("next-transpile-modules")([ "@calcom/app-store", + "@calcom/console", "@calcom/prisma", + "@calcom/types", + "@calcom/core", + "@calcom/stripe", + "@calcom/emails", "@calcom/lib", + "@calcom/ui", "@calcom/ee", ]); diff --git a/package.json b/package.json index 57da05e5e6..7475fcb6bc 100644 --- a/package.json +++ b/package.json @@ -20,13 +20,17 @@ }, "devDependencies": { "@calcom/tsconfig": "*", + "@calcom/types": "*", "babel-jest": "^28.1.0", "jest": "^28.1.0", "node-mocks-http": "^1.11.0" }, "dependencies": { + "@calcom/console": "*", "@calcom/prisma": "*", "@sentry/nextjs": "^6.19.7", + "bcryptjs": "^2.4.3", + "memory-cache": "^0.2.0", "modify-response-middleware": "^1.1.0", "next": "^12.1.6", "next-api-middleware": "^1.0.1", diff --git a/pages/api/users/[id]/availability.ts b/pages/api/users/[id]/availability.ts new file mode 100644 index 0000000000..ce57c24ea1 --- /dev/null +++ b/pages/api/users/[id]/availability.ts @@ -0,0 +1,144 @@ +// import availability from "@calcom/core/availability"; +// export default availability; +import { Prisma } from "@prisma/client"; +import dayjs from "dayjs"; +import timezone from "dayjs/plugin/timezone"; +import utc from "dayjs/plugin/utc"; +import type { NextApiRequest, NextApiResponse } from "next"; + +// import prisma from "@calcom/prisma"; +import { asNumberOrThrow, asStringOrNull } from "@calcom/lib/asStringOrNull"; +import { getWorkingHours } from "@calcom/lib/availability"; +import getBusyTimes from "@calcom/lib/getBusyTimes"; + +dayjs.extend(utc); +dayjs.extend(timezone); + +export default async function handler(req: NextApiRequest, res: NextApiResponse) { + const { prisma } = req; + const id = asNumberOrThrow(req.query.id); + const dateFrom = dayjs(asStringOrNull(req.query.dateFrom)); + const dateTo = dayjs(asStringOrNull(req.query.dateTo)); + const eventTypeId = typeof req.query.eventTypeId === "string" ? parseInt(req.query.eventTypeId) : undefined; + + if (!dateFrom.isValid() || !dateTo.isValid()) { + return res.status(400).json({ message: "Invalid time range given." }); + } + + const rawUser = await prisma.user.findUnique({ + where: { + id, + }, + select: { + credentials: true, + timeZone: true, + bufferTime: true, + availability: true, + id: true, + startTime: true, + endTime: true, + selectedCalendars: true, + schedules: { + select: { + availability: true, + timeZone: true, + id: true, + }, + }, + defaultScheduleId: true, + }, + }); + + const getEventType = (id: number) => + prisma.eventType.findUnique({ + where: { id }, + select: { + seatsPerTimeSlot: true, + timeZone: true, + schedule: { + select: { + availability: true, + timeZone: true, + }, + }, + availability: { + select: { + startTime: true, + endTime: true, + days: true, + }, + }, + }, + }); + + type EventType = Prisma.PromiseReturnType; + let eventType: EventType | null = null; + if (eventTypeId) eventType = await getEventType(eventTypeId); + + if (!rawUser) throw new Error("No user found"); + + const { selectedCalendars, ...currentUser } = rawUser; + + const busyTimes = await getBusyTimes({ + credentials: currentUser.credentials, + startTime: dateFrom.format(), + endTime: dateTo.format(), + eventTypeId, + userId: currentUser.id, + selectedCalendars, + }); + + const bufferedBusyTimes = busyTimes.map((a) => ({ + start: dayjs(a.start).subtract(currentUser.bufferTime, "minute"), + end: dayjs(a.end).add(currentUser.bufferTime, "minute"), + })); + + const schedule = eventType?.schedule + ? { ...eventType?.schedule } + : { + ...currentUser.schedules.filter( + (schedule) => !currentUser.defaultScheduleId || schedule.id === currentUser.defaultScheduleId + )[0], + }; + + const timeZone = schedule.timeZone || eventType?.timeZone || currentUser.timeZone; + + const workingHours = getWorkingHours( + { + timeZone, + }, + schedule.availability || + (eventType?.availability.length ? eventType.availability : currentUser.availability) + ); + + /* Current logic is if a booking is in a time slot mark it as busy, but seats can have more than one attendee so grab + current bookings with a seats event type and display them on the calendar, even if they are full */ + let currentSeats; + if (eventType?.seatsPerTimeSlot) { + currentSeats = await prisma.booking.findMany({ + where: { + eventTypeId: eventTypeId, + startTime: { + gte: dateFrom.format(), + lte: dateTo.format(), + }, + }, + select: { + uid: true, + startTime: true, + _count: { + select: { + attendees: true, + }, + }, + }, + }); + } + + res.status(200).json({ + busy: bufferedBusyTimes, + timeZone, + workingHours, + currentSeats, + }); +} diff --git a/tsconfig.json b/tsconfig.json index 2714b86c1c..ef00959c45 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,7 @@ { "extends": "@calcom/tsconfig/nextjs.json", "compilerOptions": { + "target": "es2017", "strict": true, "baseUrl": ".", "paths": { From d569296654495621b0475a4636fa9ac937cccd56 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 9 Jun 2022 17:09:20 +0530 Subject: [PATCH 330/658] Add webhook trigger --init --- pages/api/bookings/index.ts | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 40f24283ee..1951e4475d 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -81,7 +81,31 @@ async function createOrlistAllBookings( const data = await prisma.booking.create({ data: { ...safe.data } }); const booking = schemaBookingReadPublic.parse(data); - if (booking) res.status(201).json({ booking, message: "Booking created successfully" }); + if (booking) { + res.status(201).json({ booking, message: "Booking created successfully" }); + + // Send Webhook call if hooked to BOOKING_CREATED & BOOKING_RESCHEDULED +// const eventTrigger: WebhookTriggerEvents = rescheduleUid ? "BOOKING_RESCHEDULED" : "BOOKING_CREATED"; +// const subscriberOptions = { +// userId: user.id, +// eventTypeId, +// triggerEvent: eventTrigger, +// }; + +// const subscribers = await getSubscribers(subscriberOptions); +// const bookingId = booking?.id; +// const promises = subscribers.map((sub) => +// sendPayload(eventTrigger, new Date().toISOString(), sub, { +// ...evt, +// bookingId, +// rescheduleUid, +// metadata: reqBody.metadata, +// }).catch((e) => { +// console.error(`Error executing webhook for event: ${eventTrigger}, URL: ${sub.subscriberUrl}`, e); +// }) +// ); +// await Promise.all(promises); + } else (error: Error) => { console.log(error); From cd482cd91a44a4631bb0be0bce4b82968c4c5068 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 10 Jun 2022 11:40:38 +0530 Subject: [PATCH 331/658] Add getWebhook function --- lib/utils/webhookSubscriptions.ts | 42 +++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 lib/utils/webhookSubscriptions.ts diff --git a/lib/utils/webhookSubscriptions.ts b/lib/utils/webhookSubscriptions.ts new file mode 100644 index 0000000000..bdf9d95576 --- /dev/null +++ b/lib/utils/webhookSubscriptions.ts @@ -0,0 +1,42 @@ +import { WebhookTriggerEvents } from "@prisma/client"; + +import prisma from "@calcom/prisma"; + +export type GetSubscriberOptions = { + userId: number; + eventTypeId: number; + triggerEvent: WebhookTriggerEvents; +}; + +const getWebhooks = async (options: GetSubscriberOptions) => { + const { userId, eventTypeId } = options; + const allWebhooks = await prisma.webhook.findMany({ + where: { + OR: [ + { + userId, + }, + { + eventTypeId, + }, + ], + AND: { + eventTriggers: { + has: options.triggerEvent, + }, + active: { + equals: true, + }, + }, + }, + select: { + subscriberUrl: true, + payloadTemplate: true, + appId: true, + }, + }); + + return allWebhooks; +}; + +export default getWebhooks; From 664e697d40bc24232102221ed52443562f0b01b5 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 10 Jun 2022 11:42:01 +0530 Subject: [PATCH 332/658] add sendPayload file --- lib/utils/sendPayload.ts | 77 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 lib/utils/sendPayload.ts diff --git a/lib/utils/sendPayload.ts b/lib/utils/sendPayload.ts new file mode 100644 index 0000000000..62cc3f96d2 --- /dev/null +++ b/lib/utils/sendPayload.ts @@ -0,0 +1,77 @@ +import { Webhook } from "@prisma/client"; +import { compile } from "handlebars"; + +import type { CalendarEvent } from "@calcom/types/Calendar"; + +type ContentType = "application/json" | "application/x-www-form-urlencoded"; + +function applyTemplate(template: string, data: CalendarEvent, contentType: ContentType) { + const compiled = compile(template)(data); + if (contentType === "application/json") { + return JSON.stringify(jsonParse(compiled)); + } + return compiled; +} + +function jsonParse(jsonString: string) { + try { + return JSON.parse(jsonString); + } catch (e) { + // don't do anything. + } + return false; +} + +const sendPayload = async ( + triggerEvent: string, + createdAt: string, + webhook: Pick, + data: CalendarEvent & { + metadata?: { [key: string]: string }; + rescheduleUid?: string; + bookingId?: number; + } +) => { + const { subscriberUrl, appId, payloadTemplate: template } = webhook; + if (!subscriberUrl || !data) { + throw new Error("Missing required elements to send webhook payload."); + } + + const contentType = + !template || jsonParse(template) ? "application/json" : "application/x-www-form-urlencoded"; + + data.description = data.description || data.additionalNotes; + + let body; + + /* Zapier id is hardcoded in the DB, we send the raw data for this case */ + if (appId === "zapier") { + body = JSON.stringify(data); + } else if (template) { + body = applyTemplate(template, data, contentType); + } else { + body = JSON.stringify({ + triggerEvent: triggerEvent, + createdAt: createdAt, + payload: data, + }); + } + + const response = await fetch(subscriberUrl, { + method: "POST", + headers: { + "Content-Type": contentType, + }, + body, + }); + + const text = await response.text(); + + return { + ok: response.ok, + status: response.status, + message: text, + }; +}; + +export default sendPayload; From 542beb007938450ab0365aa4c6367a27cf6b5386 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 10 Jun 2022 11:46:51 +0530 Subject: [PATCH 333/658] adjust booking file --- pages/api/bookings/index.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 1951e4475d..2ee5c2da1c 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -84,15 +84,17 @@ async function createOrlistAllBookings( if (booking) { res.status(201).json({ booking, message: "Booking created successfully" }); - // Send Webhook call if hooked to BOOKING_CREATED & BOOKING_RESCHEDULED -// const eventTrigger: WebhookTriggerEvents = rescheduleUid ? "BOOKING_RESCHEDULED" : "BOOKING_CREATED"; +// Create Calendar Event for webhook payload + +// Send Webhook call if hooked to BOOKING_CREATED & BOOKING_RESCHEDULED +// const eventTrigger = WebhookTriggerEvents.BOOKING_CREATED; // const subscriberOptions = { // userId: user.id, // eventTypeId, // triggerEvent: eventTrigger, // }; -// const subscribers = await getSubscribers(subscriberOptions); +// const subscribers = await getWebhooks(subscriberOptions); // const bookingId = booking?.id; // const promises = subscribers.map((sub) => // sendPayload(eventTrigger, new Date().toISOString(), sub, { From 804de678680f2fa991c904e1f0fb62f96a53bee5 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 10 Jun 2022 12:17:00 +0530 Subject: [PATCH 334/658] Add eventName file --- lib/utils/eventName.ts | 62 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 lib/utils/eventName.ts diff --git a/lib/utils/eventName.ts b/lib/utils/eventName.ts new file mode 100644 index 0000000000..5d7865fe94 --- /dev/null +++ b/lib/utils/eventName.ts @@ -0,0 +1,62 @@ +import { TFunction } from "next-i18next"; + +type EventNameObjectType = { + attendeeName: string; + eventType: string; + eventName?: string | null; + host: string; + location?: string; + t: TFunction; +}; + +export function getEventName(eventNameObj: EventNameObjectType, forAttendeeView = false) { + if (!eventNameObj.eventName) + return eventNameObj.t("event_between_users", { + eventName: eventNameObj.eventType, + host: eventNameObj.host, + attendeeName: eventNameObj.attendeeName, + }); + + let eventName = eventNameObj.eventName; + let locationString = ""; + + if (eventNameObj.eventName.includes("{LOCATION}")) { + switch (eventNameObj.location) { + case "inPerson": + locationString = "In Person"; + break; + case "userPhone": + case "phone": + locationString = "Phone"; + break; + case "integrations:daily": + locationString = "Cal Video"; + break; + case "integrations:zoom": + locationString = "Zoom"; + break; + case "integrations:huddle01": + locationString = "Huddle01"; + break; + case "integrations:tandem": + locationString = "Tandem"; + break; + case "integrations:office365_video": + locationString = "MS Teams"; + break; + case "integrations:jitsi": + locationString = "Jitsi"; + break; + } + eventName = eventName.replace("{LOCATION}", locationString); + } + + return ( + eventName + // Need this for compatibility with older event names + .replace("{USER}", eventNameObj.attendeeName) + .replace("{ATTENDEE}", eventNameObj.attendeeName) + .replace("{HOST}", eventNameObj.host) + .replace("{HOST/ATTENDEE}", forAttendeeView ? eventNameObj.host : eventNameObj.attendeeName) + ); +} From e3822c50d0998312929a3c6b58e9c728c16a58ed Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 10 Jun 2022 12:43:41 +0530 Subject: [PATCH 335/658] Update booking file with webhook payload --- pages/api/bookings/index.ts | 78 +++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 21 deletions(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 2ee5c2da1c..f3b9e8c027 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -2,9 +2,14 @@ import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; +import { WebhookTriggerEvents } from "@prisma/client"; + import { withMiddleware } from "@lib/helpers/withMiddleware"; +import sendPayload from "@lib/utils/sendPayload"; +import getWebhooks from "@lib/utils/webhookSubscriptions"; import { BookingResponse, BookingsResponse } from "@lib/types"; import { schemaBookingCreateBodyParams, schemaBookingReadPublic } from "@lib/validations/booking"; +import { schemaEventTypeReadPublic } from "@lib/validations/event-type"; async function createOrlistAllBookings( { method, body, userId }: NextApiRequest, @@ -84,29 +89,60 @@ async function createOrlistAllBookings( if (booking) { res.status(201).json({ booking, message: "Booking created successfully" }); -// Create Calendar Event for webhook payload + // Create Calendar Event for webhook payload + const eventType = await prisma.eventType + .findUnique({ where: { id: booking?.eventTypeId } }) + .then((data) => schemaEventTypeReadPublic.parse(data)) + .then((event_type) => res.status(200).json({ event_type })) + .catch((error: Error) => + res.status(404).json({ + message: `EventType with id: ${booking?.eventTypeId} not found`, + error, + }) + ); + const evt = { + type: eventType.title, + title: booking.title, + description: "", + additionalNotes: "", + customInputs: {}, + startTime: booking.startTime, + endTime: booking.endTime, + organizer: { + name: "", + email: "", + timezone: "", + language: { + locale: "en" + } + }, + attendees: [], + location: "", + destinationCalendar: null, + hideCalendar: false, + uid: booking.uid, + metadata: {} + }; -// Send Webhook call if hooked to BOOKING_CREATED & BOOKING_RESCHEDULED -// const eventTrigger = WebhookTriggerEvents.BOOKING_CREATED; -// const subscriberOptions = { -// userId: user.id, -// eventTypeId, -// triggerEvent: eventTrigger, -// }; + // Send Webhook call if hooked to BOOKING_CREATED + const triggerEvent = WebhookTriggerEvents.BOOKING_CREATED; + const subscriberOptions = { + userId, + eventTypeId: eventType.id, + triggerEvent, + }; -// const subscribers = await getWebhooks(subscriberOptions); -// const bookingId = booking?.id; -// const promises = subscribers.map((sub) => -// sendPayload(eventTrigger, new Date().toISOString(), sub, { -// ...evt, -// bookingId, -// rescheduleUid, -// metadata: reqBody.metadata, -// }).catch((e) => { -// console.error(`Error executing webhook for event: ${eventTrigger}, URL: ${sub.subscriberUrl}`, e); -// }) -// ); -// await Promise.all(promises); + const subscribers = await getWebhooks(subscriberOptions); + const bookingId = booking?.id; + const promises = subscribers.map((sub) => + sendPayload(eventTrigger, new Date().toISOString(), sub, { + ...evt, + bookingId, + }).catch((e) => { + console.error(`Error executing webhook for event: ${eventTrigger}, URL: ${sub.subscriberUrl}`, e); + }) + ); + await Promise.all(promises); } else (error: Error) => { From 4f3668100691dfb0f4fe8c622fd8bce513eed679 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 12:51:24 +0530 Subject: [PATCH 336/658] --fix --- pages/api/bookings/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index f3b9e8c027..2a11672e32 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -135,11 +135,11 @@ async function createOrlistAllBookings( const subscribers = await getWebhooks(subscriberOptions); const bookingId = booking?.id; const promises = subscribers.map((sub) => - sendPayload(eventTrigger, new Date().toISOString(), sub, { + sendPayload(triggerEvent, new Date().toISOString(), sub, { ...evt, bookingId, }).catch((e) => { - console.error(`Error executing webhook for event: ${eventTrigger}, URL: ${sub.subscriberUrl}`, e); + console.error(`Error executing webhook for event: ${triggerEvent}, URL: ${sub.subscriberUrl}`, e); }) ); await Promise.all(promises); From f9c20bc8ce3544508585d8bb0fece077994da833 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 12:53:59 +0530 Subject: [PATCH 337/658] --fix null estimated value --- pages/api/bookings/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 2a11672e32..73c4e8d12b 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -91,7 +91,7 @@ async function createOrlistAllBookings( // Create Calendar Event for webhook payload const eventType = await prisma.eventType - .findUnique({ where: { id: booking?.eventTypeId } }) + .findUnique({ where: { id: booking.eventTypeId as number } }) .then((data) => schemaEventTypeReadPublic.parse(data)) .then((event_type) => res.status(200).json({ event_type })) .catch((error: Error) => From 4431142d4e540b8d0135241cff16d0c7d3fbff61 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 12:58:04 +0530 Subject: [PATCH 338/658] remove unnecessary return --- pages/api/bookings/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 73c4e8d12b..322543078f 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -93,10 +93,9 @@ async function createOrlistAllBookings( const eventType = await prisma.eventType .findUnique({ where: { id: booking.eventTypeId as number } }) .then((data) => schemaEventTypeReadPublic.parse(data)) - .then((event_type) => res.status(200).json({ event_type })) .catch((error: Error) => res.status(404).json({ - message: `EventType with id: ${booking?.eventTypeId} not found`, + message: `EventType with id: ${booking.eventTypeId} not found`, error, }) ); From adab79040f37e83e8ddc5aa4b59f079a21cacbc3 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 13:06:22 +0530 Subject: [PATCH 339/658] --fix --- pages/api/bookings/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 322543078f..2db7abac29 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -100,7 +100,7 @@ async function createOrlistAllBookings( }) ); const evt = { - type: eventType.title, + type: eventType?.title || booking.title, title: booking.title, description: "", additionalNotes: "", From cd3a80006c6eb3b44a17273439f729051406f613 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 13:10:16 +0530 Subject: [PATCH 340/658] --fix --- pages/api/bookings/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 2db7abac29..1b23a5e3f3 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -127,7 +127,7 @@ async function createOrlistAllBookings( const triggerEvent = WebhookTriggerEvents.BOOKING_CREATED; const subscriberOptions = { userId, - eventTypeId: eventType.id, + eventTypeId: booking.eventTypeId as number, triggerEvent, }; From a8ad052a037246219eb15cdb82d8dee798b8b057 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 13:16:58 +0530 Subject: [PATCH 341/658] --convert date to string in calendar event --- pages/api/bookings/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 1b23a5e3f3..0a421298e1 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -105,8 +105,8 @@ async function createOrlistAllBookings( description: "", additionalNotes: "", customInputs: {}, - startTime: booking.startTime, - endTime: booking.endTime, + startTime: booking.startTime.toISOString(), + endTime: booking.endTime.toISOString(), organizer: { name: "", email: "", From ef5bbfe4f96c65480beb7bc88519464368700cdf Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 13:22:06 +0530 Subject: [PATCH 342/658] fixed timeZone key --- pages/api/bookings/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 0a421298e1..a8eaf90662 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -110,7 +110,7 @@ async function createOrlistAllBookings( organizer: { name: "", email: "", - timezone: "", + timeZone: "", language: { locale: "en" } From f1c98181d2daee95d3e16ba25406010914aa8e78 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 13:30:43 +0530 Subject: [PATCH 343/658] tfunction added --- pages/api/bookings/index.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index a8eaf90662..f5748daf67 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -1,5 +1,6 @@ -import type { NextApiRequest, NextApiResponse } from "next"; +import { getTranslation } from "@calcom/lib/server/i18n"; +import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { WebhookTriggerEvents } from "@prisma/client"; @@ -99,6 +100,7 @@ async function createOrlistAllBookings( error, }) ); + const fallbackTfunction = await getTranslation("en", "common"); const evt = { type: eventType?.title || booking.title, title: booking.title, @@ -112,6 +114,7 @@ async function createOrlistAllBookings( email: "", timeZone: "", language: { + translate: fallbackTfunction, locale: "en" } }, From 54353f99d139395826a270843ad57abd73c38d1d Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 13:32:47 +0530 Subject: [PATCH 344/658] Calendar event changed to any for loose allowance --- lib/utils/sendPayload.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/utils/sendPayload.ts b/lib/utils/sendPayload.ts index 62cc3f96d2..925be7486a 100644 --- a/lib/utils/sendPayload.ts +++ b/lib/utils/sendPayload.ts @@ -1,11 +1,11 @@ import { Webhook } from "@prisma/client"; import { compile } from "handlebars"; -import type { CalendarEvent } from "@calcom/types/Calendar"; +// import type { CalendarEvent } from "@calcom/types/Calendar"; Add this to make it strict, change data: any to CalendarEvent type type ContentType = "application/json" | "application/x-www-form-urlencoded"; -function applyTemplate(template: string, data: CalendarEvent, contentType: ContentType) { +function applyTemplate(template: string, data: any, contentType: ContentType) { const compiled = compile(template)(data); if (contentType === "application/json") { return JSON.stringify(jsonParse(compiled)); From 8339d339a1ac3f149045e7fa0a180107ea585ce7 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 13:38:45 +0530 Subject: [PATCH 345/658] prettier and payload fix --- lib/utils/sendPayload.ts | 2 +- pages/api/bookings/index.ts | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/utils/sendPayload.ts b/lib/utils/sendPayload.ts index 925be7486a..f40c0ad743 100644 --- a/lib/utils/sendPayload.ts +++ b/lib/utils/sendPayload.ts @@ -26,7 +26,7 @@ const sendPayload = async ( triggerEvent: string, createdAt: string, webhook: Pick, - data: CalendarEvent & { + data: any & { metadata?: { [key: string]: string }; rescheduleUid?: string; bookingId?: number; diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index f5748daf67..7abd8ae5e7 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -1,14 +1,14 @@ -import { getTranslation } from "@calcom/lib/server/i18n"; - -import type { NextApiRequest, NextApiResponse } from "next"; import prisma from "@calcom/prisma"; import { WebhookTriggerEvents } from "@prisma/client"; +import { getTranslation } from "@calcom/lib/server/i18n"; + +import type { NextApiRequest, NextApiResponse } from "next"; import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { BookingResponse, BookingsResponse } from "@lib/types"; import sendPayload from "@lib/utils/sendPayload"; import getWebhooks from "@lib/utils/webhookSubscriptions"; -import { BookingResponse, BookingsResponse } from "@lib/types"; import { schemaBookingCreateBodyParams, schemaBookingReadPublic } from "@lib/validations/booking"; import { schemaEventTypeReadPublic } from "@lib/validations/event-type"; @@ -115,7 +115,7 @@ async function createOrlistAllBookings( timeZone: "", language: { translate: fallbackTfunction, - locale: "en" + locale: "en", } }, attendees: [], From 5453af6d6ee189185b0c467157013d821825d7cd Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 15:57:31 +0530 Subject: [PATCH 346/658] prettier fix attempt --- pages/api/bookings/index.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 7abd8ae5e7..4db3f3051a 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -1,10 +1,9 @@ -import prisma from "@calcom/prisma"; - import { WebhookTriggerEvents } from "@prisma/client"; -import { getTranslation } from "@calcom/lib/server/i18n"; - import type { NextApiRequest, NextApiResponse } from "next"; +import { getTranslation } from "@calcom/lib/server/i18n"; +import prisma from "@calcom/prisma"; + import { withMiddleware } from "@lib/helpers/withMiddleware"; import { BookingResponse, BookingsResponse } from "@lib/types"; import sendPayload from "@lib/utils/sendPayload"; From 301c132815bd011f47efae13f21b053704664158 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 16:21:55 +0530 Subject: [PATCH 347/658] prettier fix attempt-2 --- pages/api/bookings/index.ts | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 4db3f3051a..b8ef582dc1 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -88,8 +88,7 @@ async function createOrlistAllBookings( if (booking) { res.status(201).json({ booking, message: "Booking created successfully" }); - - // Create Calendar Event for webhook payload + // Create Calendar Event for webhook payload const eventType = await prisma.eventType .findUnique({ where: { id: booking.eventTypeId as number } }) .then((data) => schemaEventTypeReadPublic.parse(data)) @@ -115,24 +114,24 @@ async function createOrlistAllBookings( language: { translate: fallbackTfunction, locale: "en", - } + }, }, attendees: [], location: "", destinationCalendar: null, hideCalendar: false, uid: booking.uid, - metadata: {} + metadata: {}, }; - - // Send Webhook call if hooked to BOOKING_CREATED + + // Send Webhook call if hooked to BOOKING_CREATED const triggerEvent = WebhookTriggerEvents.BOOKING_CREATED; const subscriberOptions = { userId, eventTypeId: booking.eventTypeId as number, triggerEvent, }; - + const subscribers = await getWebhooks(subscriberOptions); const bookingId = booking?.id; const promises = subscribers.map((sub) => From 99e58c414c0419b96d9a0fe0c6e992c62307788f Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Fri, 10 Jun 2022 16:36:28 +0530 Subject: [PATCH 348/658] prettier fix -3 --- pages/api/bookings/index.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index b8ef582dc1..90f9cf7f22 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -143,8 +143,7 @@ async function createOrlistAllBookings( }) ); await Promise.all(promises); - } - else + } else (error: Error) => { console.log(error); res.status(400).json({ From 110edd7dcce0ae07554857c7a3c18395f3440b5a Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Sat, 11 Jun 2022 16:54:30 +0530 Subject: [PATCH 349/658] removed 18next rel --- pages/api/bookings/index.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 90f9cf7f22..6f8f2ceadc 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -1,7 +1,6 @@ import { WebhookTriggerEvents } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; -import { getTranslation } from "@calcom/lib/server/i18n"; import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; @@ -98,7 +97,6 @@ async function createOrlistAllBookings( error, }) ); - const fallbackTfunction = await getTranslation("en", "common"); const evt = { type: eventType?.title || booking.title, title: booking.title, @@ -112,7 +110,6 @@ async function createOrlistAllBookings( email: "", timeZone: "", language: { - translate: fallbackTfunction, locale: "en", }, }, From 61e742ed5ef42d9d2584a92d06c9ec59e2785e5b Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Sat, 11 Jun 2022 16:57:35 +0530 Subject: [PATCH 350/658] uuid automate in booking API --- lib/validations/booking.ts | 1 - pages/api/bookings/index.ts | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index 67b4f1b35a..b61d6913fd 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -13,7 +13,6 @@ const schemaBookingBaseBodyParams = Booking.pick({ const schemaBookingCreateParams = z .object({ - uid: z.string(), eventTypeId: z.number(), title: z.string(), startTime: z.date().or(z.string()), diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 6f8f2ceadc..37fbd94262 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -1,5 +1,6 @@ import { WebhookTriggerEvents } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; +import { v4 as uuidv4 } from "uuid"; import prisma from "@calcom/prisma"; @@ -82,7 +83,7 @@ async function createOrlistAllBookings( return; } safe.data.userId = userId; - const data = await prisma.booking.create({ data: { ...safe.data } }); + const data = await prisma.booking.create({ data: { id: uuidv4(), ...safe.data } }); const booking = schemaBookingReadPublic.parse(data); if (booking) { From 3c98c5cefc4db970d674e54b14846504a2c1bf3f Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Sat, 11 Jun 2022 16:58:21 +0530 Subject: [PATCH 351/658] fixing id to uid in create body --- pages/api/bookings/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 37fbd94262..6bd220aaf5 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -83,7 +83,7 @@ async function createOrlistAllBookings( return; } safe.data.userId = userId; - const data = await prisma.booking.create({ data: { id: uuidv4(), ...safe.data } }); + const data = await prisma.booking.create({ data: { uid: uuidv4(), ...safe.data } }); const booking = schemaBookingReadPublic.parse(data); if (booking) { From 719e21497b58e4a57b6914a6c4000e9443fa5188 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Sat, 11 Jun 2022 17:03:11 +0530 Subject: [PATCH 352/658] removed invalid response --- pages/api/bookings/index.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 6bd220aaf5..af20e851fe 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -92,12 +92,9 @@ async function createOrlistAllBookings( const eventType = await prisma.eventType .findUnique({ where: { id: booking.eventTypeId as number } }) .then((data) => schemaEventTypeReadPublic.parse(data)) - .catch((error: Error) => - res.status(404).json({ - message: `EventType with id: ${booking.eventTypeId} not found`, - error, - }) - ); + .catch((e: Error) => { + console.error(`Event type with ID: ${booking.eventTypeId} not found`, e); + }); const evt = { type: eventType?.title || booking.title, title: booking.title, From 910a0f386a116b57284b6b6a99e74ed30c9df16b Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Sat, 11 Jun 2022 22:39:03 +0530 Subject: [PATCH 353/658] Debug booking API --- pages/api/bookings/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index af20e851fe..fc0030b651 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -35,6 +35,7 @@ async function createOrlistAllBookings( */ const data = await prisma.booking.findMany({ where: { userId } }); const bookings = data.map((booking) => schemaBookingReadPublic.parse(booking)); + console.log(`Bookings requested by ${userId}`); if (bookings) res.status(200).json({ bookings }); else (error: Error) => From 470c43befe7f940802fb471f38b7d296c4662446 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Sun, 12 Jun 2022 11:16:16 +0530 Subject: [PATCH 354/658] call webhook before sending booking response --- pages/api/bookings/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index fc0030b651..b99b3510d5 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -88,7 +88,6 @@ async function createOrlistAllBookings( const booking = schemaBookingReadPublic.parse(data); if (booking) { - res.status(201).json({ booking, message: "Booking created successfully" }); // Create Calendar Event for webhook payload const eventType = await prisma.eventType .findUnique({ where: { id: booking.eventTypeId as number } }) @@ -139,6 +138,9 @@ async function createOrlistAllBookings( }) ); await Promise.all(promises); + + res.status(201).json({ booking, message: "Booking created successfully" }); + } else (error: Error) => { console.log(error); From bd88bec1d2015a83261ed5cdf14802b057475539 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Sun, 12 Jun 2022 11:24:38 +0530 Subject: [PATCH 355/658] fix prettier --- pages/api/bookings/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index b99b3510d5..1bea4249b2 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -140,7 +140,6 @@ async function createOrlistAllBookings( await Promise.all(promises); res.status(201).json({ booking, message: "Booking created successfully" }); - } else (error: Error) => { console.log(error); From 935473cfcd040a178d25b7f813a5ce5acbb076d4 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Sun, 12 Jun 2022 11:25:53 +0530 Subject: [PATCH 356/658] removed comment --- pages/api/bookings/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 1bea4249b2..3336098d57 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -88,7 +88,6 @@ async function createOrlistAllBookings( const booking = schemaBookingReadPublic.parse(data); if (booking) { - // Create Calendar Event for webhook payload const eventType = await prisma.eventType .findUnique({ where: { id: booking.eventTypeId as number } }) .then((data) => schemaEventTypeReadPublic.parse(data)) From ecce02ebbf60e6b215ed980f876cb760581609c4 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz Date: Sun, 12 Jun 2022 11:43:26 +0530 Subject: [PATCH 357/658] debug logs added --- lib/utils/sendPayload.ts | 1 + pages/api/bookings/index.ts | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/lib/utils/sendPayload.ts b/lib/utils/sendPayload.ts index f40c0ad743..a6234a1d37 100644 --- a/lib/utils/sendPayload.ts +++ b/lib/utils/sendPayload.ts @@ -18,6 +18,7 @@ function jsonParse(jsonString: string) { return JSON.parse(jsonString); } catch (e) { // don't do anything. + console.error(`error jsonParsing in sendPayload`); } return false; } diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 3336098d57..e31a017801 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -94,6 +94,7 @@ async function createOrlistAllBookings( .catch((e: Error) => { console.error(`Event type with ID: ${booking.eventTypeId} not found`, e); }); + console.log(`eventType: ${eventType}`); const evt = { type: eventType?.title || booking.title, title: booking.title, @@ -117,16 +118,20 @@ async function createOrlistAllBookings( uid: booking.uid, metadata: {}, }; + console.log(`evt: ${evt}`); // Send Webhook call if hooked to BOOKING_CREATED const triggerEvent = WebhookTriggerEvents.BOOKING_CREATED; + console.log(`Trigger Event: ${triggerEvent}`); const subscriberOptions = { userId, eventTypeId: booking.eventTypeId as number, triggerEvent, }; + console.log(`subscriberOptions: ${subscriberOptions}`); const subscribers = await getWebhooks(subscriberOptions); + console.log(`subscribers: ${subscribers}`); const bookingId = booking?.id; const promises = subscribers.map((sub) => sendPayload(triggerEvent, new Date().toISOString(), sub, { From b385d3547bf487c341ab20c9a372fdf84af1da5c Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Mon, 13 Jun 2022 13:24:21 +0530 Subject: [PATCH 358/658] Adds debug console.log --- pages/api/bookings/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index e31a017801..ab85b339cd 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -142,7 +142,7 @@ async function createOrlistAllBookings( }) ); await Promise.all(promises); - + console.log("All promises resolved! About to send the response"); res.status(201).json({ booking, message: "Booking created successfully" }); } else (error: Error) => { From b1dd1b85727d3e0b9b8badfe151c513e7b48eb75 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 13 Jun 2022 23:58:15 +0200 Subject: [PATCH 359/658] fix: make jsonSchema.optional() --- lib/validations/user.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/user.ts b/lib/validations/user.ts index 528bc2e292..2385224f5a 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -93,7 +93,7 @@ const schemaUserEditParams = z.object({ .optional() .nullable(), locale: z.nativeEnum(locales).optional().nullable(), - metadata: jsonSchema, + metadata: jsonSchema.optional(), }); // @note: These are the values that are editable via PATCH method on the user Model, From ab6a99749f619df4423815244ff8785b453e6908 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 14 Jun 2022 00:32:07 +0200 Subject: [PATCH 360/658] fix: linting --- lib/helpers/customPrisma.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helpers/customPrisma.ts b/lib/helpers/customPrisma.ts index 27bc3261e2..27846f3148 100644 --- a/lib/helpers/customPrisma.ts +++ b/lib/helpers/customPrisma.ts @@ -3,7 +3,7 @@ import cache from "memory-cache"; import { NextMiddleware } from "next-api-middleware"; import { prismaAdmin } from "@calcom/console/modules/common/utils/prisma"; -import { asStringOrUndefined, asStringOrNull } from "@calcom/lib/asStringOrNull"; +import { asStringOrUndefined } from "@calcom/lib/asStringOrNull"; import { PRISMA_CLIENT_CACHING_TIME } from "@calcom/lib/constants"; import { prisma, customPrisma } from "@calcom/prisma"; From f3d7922efd3d8eca1816ac4e8237060fae997363 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 14 Jun 2022 19:48:47 +0200 Subject: [PATCH 361/658] move caching time constant to API --- lib/constants.ts | 1 + lib/helpers/customPrisma.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 lib/constants.ts diff --git a/lib/constants.ts b/lib/constants.ts new file mode 100644 index 0000000000..52c7fe0a41 --- /dev/null +++ b/lib/constants.ts @@ -0,0 +1 @@ +export const PRISMA_CLIENT_CACHING_TIME = 1000 * 60 * 60 * 24; diff --git a/lib/helpers/customPrisma.ts b/lib/helpers/customPrisma.ts index 27846f3148..dc9bbeeaa3 100644 --- a/lib/helpers/customPrisma.ts +++ b/lib/helpers/customPrisma.ts @@ -2,9 +2,9 @@ import { hash } from "bcryptjs"; import cache from "memory-cache"; import { NextMiddleware } from "next-api-middleware"; +import { PRISMA_CLIENT_CACHING_TIME } from "@calcom/api/lib/constants"; import { prismaAdmin } from "@calcom/console/modules/common/utils/prisma"; import { asStringOrUndefined } from "@calcom/lib/asStringOrNull"; -import { PRISMA_CLIENT_CACHING_TIME } from "@calcom/lib/constants"; import { prisma, customPrisma } from "@calcom/prisma"; // This replaces the prisma client for the cusotm one if the customCredentialsId is valid From 49087d858e4d7c7d6166bd8b53895b618ac1da2f Mon Sep 17 00:00:00 2001 From: zomars Date: Tue, 14 Jun 2022 14:07:23 -0600 Subject: [PATCH 362/658] Fixes hot-reload for dev --- next.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/next.config.js b/next.config.js index 5e40353edf..62b15643fa 100644 --- a/next.config.js +++ b/next.config.js @@ -10,7 +10,7 @@ const withTM = require("next-transpile-modules")([ module.exports = withTM({ async rewrites() { return { - beforeFiles: [ + afterFiles: [ // This redirects requests recieved at / the root to the /api/ folder. { source: "/v:version/:rest*", From 4d93b08e4c3e95b7f960c8fffc363aad1d660745 Mon Sep 17 00:00:00 2001 From: zomars Date: Tue, 14 Jun 2022 14:08:19 -0600 Subject: [PATCH 363/658] Scripts fixes --- package.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 57da05e5e6..48cf7b6ef9 100644 --- a/package.json +++ b/package.json @@ -8,9 +8,8 @@ "private": true, "scripts": { "build": "next build", - "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist", - "dev-real": "PORT=3002 next dev", - "dev": "next build && PORT=3002 next start", + "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next", + "dev": "PORT=3002 next dev", "lint-fix": "next lint --fix && prettier --write .", "lint": "next lint", "prebuild": "cd ../.. && yarn workspace @calcom/prisma generate-schemas", From 58e1ea9bf66bbf3f0b83ae6b0c614b798db17e73 Mon Sep 17 00:00:00 2001 From: zomars Date: Tue, 14 Jun 2022 14:08:58 -0600 Subject: [PATCH 364/658] User endpoint refactoring --- lib/validations/user.ts | 4 ++- pages/api/users/_get.ts | 37 +++++++++++++++++++++++ pages/api/users/_post.ts | 20 +++++++++++++ pages/api/users/index.ts | 64 +++++----------------------------------- 4 files changed, 67 insertions(+), 58 deletions(-) create mode 100644 pages/api/users/_get.ts create mode 100644 pages/api/users/_post.ts diff --git a/lib/validations/user.ts b/lib/validations/user.ts index 2385224f5a..c780dfbed8 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -150,4 +150,6 @@ export const schemaUserReadPublic = User.pick({ createdDate: true, verified: true, invitedTo: true, -}).merge(schemaUserEditBodyParams); +}); + +export const schemaUsersReadPublic = z.array(schemaUserReadPublic); diff --git a/pages/api/users/_get.ts b/pages/api/users/_get.ts new file mode 100644 index 0000000000..4c4aadaecd --- /dev/null +++ b/pages/api/users/_get.ts @@ -0,0 +1,37 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; +import prisma from "@calcom/prisma"; + +import { isAdminGuard } from "@lib/utils/isAdmin"; +import { schemaUsersReadPublic } from "@lib/validations/user"; + +import { Prisma } from ".prisma/client"; + +/** + * @swagger + * /users: + * get: + * operationId: listUsers + * summary: Find all users. + * tags: + * - users + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No users were found + */ +async function getHandler({ userId }: NextApiRequest) { + const isAdmin = await isAdminGuard(userId); + const where: Prisma.UserWhereInput = {}; + // If user is not ADMIN, return only his data. + if (!isAdmin) where.id = userId; + const data = await prisma.user.findMany({ where }); + const users = schemaUsersReadPublic.parse(data); + return { users }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/users/_post.ts b/pages/api/users/_post.ts new file mode 100644 index 0000000000..908a9c4bcc --- /dev/null +++ b/pages/api/users/_post.ts @@ -0,0 +1,20 @@ +import { HttpError } from "@/../../packages/lib/http-error"; +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; +import prisma from "@calcom/prisma"; + +import { isAdminGuard } from "@lib/utils/isAdmin"; +import { schemaUserCreateBodyParams } from "@lib/validations/user"; + +async function postHandler(req: NextApiRequest) { + const isAdmin = await isAdminGuard(req.userId); + // If user is not ADMIN, return unauthorized. + if (!isAdmin) throw new HttpError({ statusCode: 401, message: "You are not authorized" }); + const data = schemaUserCreateBodyParams.parse(req.body); + const user = await prisma.user.create({ data }); + req.statusCode = 201; + return { user }; +} + +export default defaultResponder(postHandler); diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 3839ae21b6..c07846423f 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -1,60 +1,10 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; +import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { UserResponse, UsersResponse } from "@lib/types"; -import { isAdminGuard } from "@lib/utils/isAdmin"; -import { schemaUserReadPublic, schemaUserCreateBodyParams } from "@lib/validations/user"; -/** - * @swagger - * /users: - * get: - * operationId: listUsers - * summary: Find all users. - * tags: - * - users - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No users were found - */ -async function getAllorCreateUser( - { userId, method, body }: NextApiRequest, - res: NextApiResponse -) { - const isAdmin = await isAdminGuard(userId); - if (method === "GET") { - if (!isAdmin) { - // If user is not ADMIN, return only his data. - const data = await prisma.user.findMany({ where: { id: userId } }); - const users = data.map((user) => schemaUserReadPublic.parse(user)); - if (users) res.status(200).json({ users }); - } else { - // If user is admin, return all users. - const data = await prisma.user.findMany({}); - const users = data.map((user) => schemaUserReadPublic.parse(user)); - if (users) res.status(200).json({ users }); - } - } else if (method === "POST") { - // If user is not ADMIN, return unauthorized. - if (!isAdmin) res.status(401).json({ message: "You are not authorized" }); - else { - const safeBody = schemaUserCreateBodyParams.safeParse(body); - if (!safeBody.success) { - res.status(400).json({ message: "Your body was invalid" }); - return; - } - const user = await prisma.user.create({ - data: safeBody.data, - }); - res.status(201).json({ user }); - } - } -} - -export default withMiddleware("HTTP_GET_OR_POST")(getAllorCreateUser); +export default withMiddleware("HTTP_GET_OR_POST")( + defaultHandler({ + GET: import("./_get"), + POST: import("./_post"), + }) +); From 7d0cef065f079c575ec8ee7c80f150f21a60cab7 Mon Sep 17 00:00:00 2001 From: zomars Date: Tue, 14 Jun 2022 14:10:59 -0600 Subject: [PATCH 365/658] Refactors user id endpoint --- pages/api/users/{[id].ts => [id]/index.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pages/api/users/{[id].ts => [id]/index.ts} (100%) diff --git a/pages/api/users/[id].ts b/pages/api/users/[id]/index.ts similarity index 100% rename from pages/api/users/[id].ts rename to pages/api/users/[id]/index.ts From 0f72a9084a789c84cf7642d1f1932de4b057e2b1 Mon Sep 17 00:00:00 2001 From: zomars Date: Tue, 14 Jun 2022 14:35:15 -0600 Subject: [PATCH 366/658] Splits user endpoints by method --- pages/api/users/[id]/_delete.ts | 43 +++++++ pages/api/users/[id]/_get.ts | 45 ++++++++ pages/api/users/[id]/_patch.ts | 82 ++++++++++++++ pages/api/users/[id]/index.ts | 194 ++------------------------------ 4 files changed, 181 insertions(+), 183 deletions(-) create mode 100644 pages/api/users/[id]/_delete.ts create mode 100644 pages/api/users/[id]/_get.ts create mode 100644 pages/api/users/[id]/_patch.ts diff --git a/pages/api/users/[id]/_delete.ts b/pages/api/users/[id]/_delete.ts new file mode 100644 index 0000000000..ce04999eea --- /dev/null +++ b/pages/api/users/[id]/_delete.ts @@ -0,0 +1,43 @@ +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; +import prisma from "@calcom/prisma"; + +import { isAdminGuard } from "@lib/utils/isAdmin"; +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /users/{id}: + * delete: + * summary: Remove an existing user + * operationId: removeUserById + * parameters: + * - in: path + * name: id + * example: 1 + * schema: + * type: integer + * required: true + * description: ID of the user to delete + * tags: + * - users + * responses: + * 201: + * description: OK, user removed successfuly + * 400: + * description: Bad request. User id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteHandler(req: NextApiRequest) { + const query = schemaQueryIdParseInt.parse(req.query); + const isAdmin = await isAdminGuard(req.userId); + // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user + if (!isAdmin && query.id !== req.userId) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + await prisma.user.delete({ where: { id: query.id } }); + return { message: `User with id: ${query.id} deleted successfully` }; +} + +export default defaultResponder(deleteHandler); diff --git a/pages/api/users/[id]/_get.ts b/pages/api/users/[id]/_get.ts new file mode 100644 index 0000000000..443b935e9c --- /dev/null +++ b/pages/api/users/[id]/_get.ts @@ -0,0 +1,45 @@ +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; +import prisma from "@calcom/prisma"; + +import { isAdminGuard } from "@lib/utils/isAdmin"; +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaUserReadPublic } from "@lib/validations/user"; + +/** + * @swagger + * /users/{id}: + * get: + * summary: Find a user, returns your user if regular user. + * operationId: getUserById + * parameters: + * - in: path + * name: id + * example: 4 + * schema: + * type: integer + * required: true + * description: ID of the user to get + * tags: + * - users + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: User was not found + */ +export async function getHandler(req: NextApiRequest) { + const query = schemaQueryIdParseInt.parse(req.query); + const isAdmin = await isAdminGuard(req.userId); + // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user + if (!isAdmin && query.id !== req.userId) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + const data = await prisma.user.findUnique({ where: { id: query.id } }); + const user = schemaUserReadPublic.parse(data); + return { user }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/users/[id]/_patch.ts b/pages/api/users/[id]/_patch.ts new file mode 100644 index 0000000000..a6551609e7 --- /dev/null +++ b/pages/api/users/[id]/_patch.ts @@ -0,0 +1,82 @@ +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; +import prisma from "@calcom/prisma"; + +import { isAdminGuard } from "@lib/utils/isAdmin"; +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations/user"; + +/** + * @swagger + * /users/{id}: + * patch: + * summary: Edit an existing user + * operationId: editUserById + * requestBody: + * description: Edit an existing attendee related to one of your bookings + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * weekStart: + * type: string + * enum: [Monday, Sunday, Saturday] + * example: Monday + * brandColor: + * type: string + * example: "#FF000F" + * darkBrandColor: + * type: string + * example: "#000000" + * timeZone: + * type: string + * example: Europe/London + * parameters: + * - in: path + * name: id + * example: 4 + * schema: + * type: integer + * required: true + * description: ID of the user to edit + * tags: + * - users + * responses: + * 201: + * description: OK, user edited successfuly + * 400: + * description: Bad request. User body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function patchHandler(req: NextApiRequest) { + const query = schemaQueryIdParseInt.parse(req.query); + const isAdmin = await isAdminGuard(req.userId); + // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user + if (!isAdmin && query.id !== req.userId) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + + const body = schemaUserEditBodyParams.parse(req.body); + const userSchedules = await prisma.schedule.findMany({ + where: { userId: req.userId }, + }); + const userSchedulesIds = userSchedules.map((schedule) => schedule.id); + // @note: here we make sure user can only make as default his own scheudles + if (body.defaultScheduleId && !userSchedulesIds.includes(Number(body.defaultScheduleId))) { + throw new HttpError({ + statusCode: 400, + message: "Bad request: Invalid default schedule id", + }); + } + const data = await prisma.user.update({ + where: { id: req.userId }, + data: body, + }); + const user = schemaUserReadPublic.parse(data); + return { user }; +} + +export default defaultResponder(patchHandler); diff --git a/pages/api/users/[id]/index.ts b/pages/api/users/[id]/index.ts index 65b864c652..7d8887e5d1 100644 --- a/pages/api/users/[id]/index.ts +++ b/pages/api/users/[id]/index.ts @@ -1,186 +1,14 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; +import { defaultHandler } from "@/../../packages/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { UserResponse } from "@lib/types"; -import { isAdminGuard } from "@lib/utils/isAdmin"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; -import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations/user"; +import { withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; -export async function userById( - { method, query, body, userId }: NextApiRequest, - res: NextApiResponse -) { - const safeQuery = schemaQueryIdParseInt.safeParse(query); - console.log(body); - if (!safeQuery.success) { - res.status(400).json({ message: "Your query was invalid" }); - return; - } - const isAdmin = await isAdminGuard(userId); - // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user - if (!isAdmin) { - if (safeQuery.data.id !== userId) res.status(401).json({ message: "Unauthorized" }); - } else { - switch (method) { - case "GET": - /** - * @swagger - * /users/{id}: - * get: - * summary: Find a user, returns your user if regular user. - * operationId: getUserById - * parameters: - * - in: path - * name: id - * example: 4 - * schema: - * type: integer - * required: true - * description: ID of the user to get - * tags: - * - users - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: User was not found - */ - - await prisma.user - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaUserReadPublic.parse(data)) - .then((user) => res.status(200).json({ user })) - .catch((error: Error) => - res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) - ); - break; - case "PATCH": - /** - * @swagger - * /users/{id}: - * patch: - * summary: Edit an existing user - * operationId: editUserById - * requestBody: - * description: Edit an existing attendee related to one of your bookings - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * weekStart: - * type: string - * enum: [Monday, Sunday, Saturday] - * example: Monday - * brandColor: - * type: string - * example: "#FF000F" - * darkBrandColor: - * type: string - * example: "#000000" - * timeZone: - * type: string - * example: Europe/London - * parameters: - * - in: path - * name: id - * example: 4 - * schema: - * type: integer - * required: true - * description: ID of the user to edit - * tags: - * - users - * responses: - * 201: - * description: OK, user edited successfuly - * 400: - * description: Bad request. User body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - - const safeBody = schemaUserEditBodyParams.safeParse(body); - if (!safeBody.success) { - res.status(400).json({ message: "Bad request", error: safeBody.error }); - - return; - } - const userSchedules = await prisma.schedule.findMany({ - where: { userId }, - }); - const userSchedulesIds = userSchedules.map((schedule) => schedule.id); - // @note: here we make sure user can only make as default his own scheudles - if ( - safeBody?.data?.defaultScheduleId && - !userSchedulesIds.includes(Number(safeBody?.data?.defaultScheduleId)) - ) { - res.status(400).json({ - message: "Bad request: Invalid default schedule id", - }); - return; - } - await prisma.user - .update({ - where: { id: userId }, - data: safeBody.data, - }) - .then((data) => schemaUserReadPublic.parse(data)) - .then((user) => res.status(200).json({ user })) - .catch((error: Error) => - res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - /** - * @swagger - * /users/{id}: - * delete: - * summary: Remove an existing user - * operationId: removeUserById - * parameters: - * - in: path - * name: id - * example: 1 - * schema: - * type: integer - * required: true - * description: ID of the user to delete - * tags: - * - users - * responses: - * 201: - * description: OK, user removed successfuly - * 400: - * description: Bad request. User id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - - case "DELETE": - await prisma.user - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ message: `User with id: ${safeQuery.data.id} deleted successfully` }) - ) - .catch((error: Error) => - res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } - } -} - -export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(userById)); +export default withMiddleware("HTTP_GET_DELETE_PATCH")( + withValidQueryIdTransformParseInt( + defaultHandler({ + GET: import("./_get"), + PATCH: import("./_patch"), + DELETE: import("./_delete"), + }) + ) +); From ae9c33ddbe0d5ec5105f59f326bf6e02edf950f3 Mon Sep 17 00:00:00 2001 From: zomars Date: Tue, 14 Jun 2022 14:44:09 -0600 Subject: [PATCH 367/658] Makes user create/update body strict --- lib/validations/user.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/validations/user.ts b/lib/validations/user.ts index c780dfbed8..1a69eb5c7c 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -122,8 +122,15 @@ const schemaUserCreateParams = z.object({ // @note: These are the values that are editable via PATCH method on the user Model, // merging both BaseBodyParams with RequiredParams, and omiting whatever we want at the end. -export const schemaUserEditBodyParams = schemaUserBaseBodyParams.merge(schemaUserEditParams).omit({}); -export const schemaUserCreateBodyParams = schemaUserBaseBodyParams.merge(schemaUserCreateParams).omit({}); +export const schemaUserEditBodyParams = schemaUserBaseBodyParams + .merge(schemaUserEditParams) + .omit({}) + .strict(); + +export const schemaUserCreateBodyParams = schemaUserBaseBodyParams + .merge(schemaUserCreateParams) + .omit({}) + .strict(); // @note: These are the values that are always returned when reading a user export const schemaUserReadPublic = User.pick({ From 1ab81fb8ee127d5fa1dce93ed1cda68ae2b651b5 Mon Sep 17 00:00:00 2001 From: zomars Date: Tue, 14 Jun 2022 14:51:02 -0600 Subject: [PATCH 368/658] Better error on user delete --- pages/api/users/[id]/_delete.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pages/api/users/[id]/_delete.ts b/pages/api/users/[id]/_delete.ts index ce04999eea..7d38d07372 100644 --- a/pages/api/users/[id]/_delete.ts +++ b/pages/api/users/[id]/_delete.ts @@ -36,8 +36,12 @@ export async function deleteHandler(req: NextApiRequest) { const isAdmin = await isAdminGuard(req.userId); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user if (!isAdmin && query.id !== req.userId) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); - await prisma.user.delete({ where: { id: query.id } }); - return { message: `User with id: ${query.id} deleted successfully` }; + + const user = await prisma.user.findUnique({ where: { id: query.id } }); + if (!user) throw new HttpError({ statusCode: 404, message: "User not found" }); + + await prisma.user.delete({ where: { id: user.id } }); + return { message: `User with id: ${user.id} deleted successfully` }; } export default defaultResponder(deleteHandler); From 3cb2a8b86607072eedcc4b09edb488879bf127b5 Mon Sep 17 00:00:00 2001 From: zomars Date: Tue, 14 Jun 2022 15:13:59 -0600 Subject: [PATCH 369/658] Matches transpilling modules to web --- next.config.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/next.config.js b/next.config.js index 62b15643fa..22ff466595 100644 --- a/next.config.js +++ b/next.config.js @@ -2,9 +2,15 @@ // This makes our @calcom/prisma package from the monorepo to be transpiled and usable by API const withTM = require("next-transpile-modules")([ "@calcom/app-store", - "@calcom/prisma", - "@calcom/lib", + "@calcom/core", "@calcom/ee", + "@calcom/lib", + "@calcom/prisma", + "@calcom/stripe", + "@calcom/ui", + "@calcom/emails", + "@calcom/embed-core", + "@calcom/embed-snippet", ]); module.exports = withTM({ From e1bcd38e61c412cc7500ab8eb453dd8c5ae1825c Mon Sep 17 00:00:00 2001 From: zomars Date: Tue, 14 Jun 2022 15:17:09 -0600 Subject: [PATCH 370/658] Adds basic availability endpoint --- pages/api/availability/_get.ts | 29 +++++++++++++++++++++++++++++ pages/api/availability/index.ts | 5 +++++ 2 files changed, 34 insertions(+) create mode 100644 pages/api/availability/_get.ts create mode 100644 pages/api/availability/index.ts diff --git a/pages/api/availability/_get.ts b/pages/api/availability/_get.ts new file mode 100644 index 0000000000..21450f005e --- /dev/null +++ b/pages/api/availability/_get.ts @@ -0,0 +1,29 @@ +import type { NextApiRequest } from "next"; +import { z } from "zod"; + +import { getUserAvailability } from "@calcom/core/getUserAvailability"; +import { defaultResponder } from "@calcom/lib/server"; +import { stringOrNumber } from "@calcom/prisma/zod-utils"; + +const availabilitySchema = z + .object({ + userId: stringOrNumber.optional(), + username: z.string().optional(), + dateFrom: z.string(), + dateTo: z.string(), + eventTypeId: stringOrNumber.optional(), + }) + .refine((data) => !!data.username || !!data.userId, "Either username or userId should be filled in."); + +async function handler(req: NextApiRequest) { + const { username, userId, eventTypeId, dateTo, dateFrom } = availabilitySchema.parse(req.query); + return getUserAvailability({ + username, + dateFrom, + dateTo, + eventTypeId, + userId, + }); +} + +export default defaultResponder(handler); diff --git a/pages/api/availability/index.ts b/pages/api/availability/index.ts new file mode 100644 index 0000000000..0fe7836697 --- /dev/null +++ b/pages/api/availability/index.ts @@ -0,0 +1,5 @@ +import { defaultHandler } from "@calcom/lib/server"; + +export default defaultHandler({ + GET: import("./_get"), +}); From ba37ae78d91598f9a6c2f7650cd3f87a02570150 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 14 Jun 2022 23:41:33 +0200 Subject: [PATCH 371/658] fix: adds middleware, makes userId not optional --- pages/api/availability/_get.ts | 2 +- pages/api/availability/index.ts | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/pages/api/availability/_get.ts b/pages/api/availability/_get.ts index 21450f005e..5289190c03 100644 --- a/pages/api/availability/_get.ts +++ b/pages/api/availability/_get.ts @@ -7,7 +7,7 @@ import { stringOrNumber } from "@calcom/prisma/zod-utils"; const availabilitySchema = z .object({ - userId: stringOrNumber.optional(), + userId: stringOrNumber, username: z.string().optional(), dateFrom: z.string(), dateTo: z.string(), diff --git a/pages/api/availability/index.ts b/pages/api/availability/index.ts index 0fe7836697..b0c4e223d5 100644 --- a/pages/api/availability/index.ts +++ b/pages/api/availability/index.ts @@ -1,5 +1,9 @@ import { defaultHandler } from "@calcom/lib/server"; -export default defaultHandler({ - GET: import("./_get"), -}); +import { withMiddleware } from "@lib/helpers/withMiddleware"; + +export default withMiddleware("HTTP_GET_OR_POST")( + defaultHandler({ + GET: import("./_get"), + }) +); From 372b20a4c937a5b3014febaf61836656e507a3fd Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 14 Jun 2022 23:42:51 +0200 Subject: [PATCH 372/658] fix: no post for now --- pages/api/availability/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/availability/index.ts b/pages/api/availability/index.ts index b0c4e223d5..fe6357f6bc 100644 --- a/pages/api/availability/index.ts +++ b/pages/api/availability/index.ts @@ -2,7 +2,7 @@ import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -export default withMiddleware("HTTP_GET_OR_POST")( +export default withMiddleware("HTTP_GET")( defaultHandler({ GET: import("./_get"), }) From 1bde5d88c105cf0357ce708a52f725dc37072be1 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 14 Jun 2022 23:43:53 +0200 Subject: [PATCH 373/658] fix: add back optional --- pages/api/availability/_get.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/availability/_get.ts b/pages/api/availability/_get.ts index 5289190c03..21450f005e 100644 --- a/pages/api/availability/_get.ts +++ b/pages/api/availability/_get.ts @@ -7,7 +7,7 @@ import { stringOrNumber } from "@calcom/prisma/zod-utils"; const availabilitySchema = z .object({ - userId: stringOrNumber, + userId: stringOrNumber.optional(), username: z.string().optional(), dateFrom: z.string(), dateTo: z.string(), From 1e80a83b1f5519fc76fdbab53456ef0fc4310cfd Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 14 Jun 2022 23:57:38 +0200 Subject: [PATCH 374/658] add session to req --- lib/helpers/verifyApiKey.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index c45f3d3c3f..481b006849 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -11,6 +11,8 @@ declare module "next" { userId: number; method: string; query: { [key: string]: string | string[] }; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + session: any; } } From ab26f35520c3c564ad39f4b9ccf7f0521caef3c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Tue, 14 Jun 2022 16:04:40 -0600 Subject: [PATCH 375/658] Update package.json --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 48cf7b6ef9..493a5929fd 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "author": "Cal.com Inc.", "private": true, "scripts": { - "build": "next build", + "app-store:generate": "yarn workspace @calcom/app-store-cli generate", + "build": "yarn app-store:generate && next build", "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next", "dev": "PORT=3002 next dev", "lint-fix": "next lint --fix && prettier --write .", From 5559e63be10e0812043d7e2e90ff54fa0f9ac97d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 15 Jun 2022 00:19:39 +0200 Subject: [PATCH 376/658] fix add app-store to deps --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 493a5929fd..6384aaa8ca 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ }, "dependencies": { "@calcom/prisma": "*", + "@calcom/app-store": "*", "@sentry/nextjs": "^6.19.7", "modify-response-middleware": "^1.1.0", "next": "^12.1.6", From ff701ffec68b4216ccbdadefe2db84c11500400b Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 15 Jun 2022 00:21:09 +0200 Subject: [PATCH 377/658] fix: no need for app store deps --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 6384aaa8ca..493a5929fd 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ }, "dependencies": { "@calcom/prisma": "*", - "@calcom/app-store": "*", "@sentry/nextjs": "^6.19.7", "modify-response-middleware": "^1.1.0", "next": "^12.1.6", From ed1bc8015acf4a02fded22856a9fd82eaade1462 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 15 Jun 2022 20:43:35 +0200 Subject: [PATCH 378/658] feat: initial isAdmin work for events and attendees --- lib/helpers/verifyApiKey.ts | 6 +++ lib/validations/booking.ts | 1 - pages/api/attendees/[id].ts | 10 +++-- pages/api/attendees/index.ts | 79 ++++++++++++++++++++++------------ pages/api/bookings/index.ts | 2 +- pages/api/event-types/[id].ts | 4 +- pages/api/event-types/index.ts | 4 +- pages/api/users/[id].ts | 4 +- pages/api/users/index.ts | 4 +- 9 files changed, 69 insertions(+), 45 deletions(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index c45f3d3c3f..c3977ca94f 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -4,12 +4,15 @@ import { NextMiddleware } from "next-api-middleware"; import { hashAPIKey } from "@calcom/ee/lib/api/apiKeys"; import prisma from "@calcom/prisma"; +import { isAdminGuard } from "@lib/utils/isAdmin"; + /** @todo figure how to use the one from `@calcom/types`fi */ /** @todo: remove once `@calcom/types` is updated with it.*/ declare module "next" { export interface NextApiRequest extends IncomingMessage { userId: number; method: string; + isAdmin: boolean; query: { [key: string]: string | string[] }; } } @@ -39,5 +42,8 @@ export const verifyApiKey: NextMiddleware = async (req, res, next) => { if (!apiKey.userId) return res.status(404).json({ error: "No user found for this apiKey" }); /* We save the user id in the request for later use */ req.userId = apiKey.userId; + /* We save the isAdmin boolean here for later use */ + req.isAdmin = await isAdminGuard(req.userId); + await next(); }; diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index b61d6913fd..a8a4b52c37 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -24,7 +24,6 @@ export const schemaBookingCreateBodyParams = schemaBookingBaseBodyParams.merge(s const schemaBookingEditParams = z .object({ - uid: z.string().optional(), title: z.string().optional(), startTime: z.date().optional(), endTime: z.date().optional(), diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index a1674d87a4..a72dbf5812 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -11,7 +11,7 @@ import { } from "@lib/validations/shared/queryIdTransformParseInt"; export async function attendeeById( - { method, query, body, userId }: NextApiRequest, + { method, query, body, userId, isAdmin }: NextApiRequest, res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); @@ -33,9 +33,11 @@ export async function attendeeById( .flat() .map((attendee) => attendee.id) ); - // @note: Here we make sure to only return attendee's of the user's own bookings. - if (!userBookingsAttendeeIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); - else { + // @note: Here we make sure to only return attendee's of the user's own bookings if the user is not an admin. + if (!isAdmin) { + if (!userBookingsAttendeeIds.includes(safeQuery.data.id)) + res.status(401).json({ message: "Unauthorized" }); + } else { switch (method) { /** * @swagger diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index eaae0b28ff..6b2c4fc415 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -1,24 +1,30 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import db from "@calcom/prisma"; +import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { AttendeeResponse, AttendeesResponse } from "@lib/types"; import { schemaAttendeeCreateBodyParams, schemaAttendeeReadPublic } from "@lib/validations/attendee"; async function createOrlistAllAttendees( - { method, userId, body }: NextApiRequest, + { method, userId, body, isAdmin }: NextApiRequest, res: NextApiResponse ) { - const userBookings = await db.booking.findMany({ - where: { - userId, - }, - include: { - attendees: true, - }, - }); - const attendees = userBookings.map((booking) => booking.attendees).flat(); + let attendees; + if (!isAdmin) { + const userBookings = await prisma.booking.findMany({ + where: { + userId, + }, + include: { + attendees: true, + }, + }); + attendees = userBookings.map((booking) => booking.attendees).flat(); + } else { + const data = await prisma.attendee.findMany(); + attendees = data.map((attendee) => schemaAttendeeReadPublic.parse(attendee)); + } if (method === "GET") { /** * @swagger @@ -37,12 +43,7 @@ async function createOrlistAllAttendees( * description: No attendees were found */ if (attendees) res.status(200).json({ attendees }); - else - (error: Error) => - res.status(404).json({ - message: "No Attendees were found", - error, - }); + else (error: Error) => res.status(400).json({ error }); } else if (method === "POST") { /** * @swagger @@ -90,16 +91,40 @@ async function createOrlistAllAttendees( res.status(400).json({ message: "Invalid request body", error: safePost.error }); return; } - const userWithBookings = await db.user.findUnique({ where: { id: userId }, include: { bookings: true } }); - if (!userWithBookings) { - res.status(404).json({ message: "User not found" }); - return; - } - const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); - // Here we make sure to only return attendee's of the user's own bookings. - if (!userBookingIds.includes(safePost.data.bookingId)) res.status(401).json({ message: "Unauthorized" }); - else { - const data = await db.attendee.create({ + if (!isAdmin) { + const userWithBookings = await prisma.user.findUnique({ + where: { id: userId }, + include: { bookings: true }, + }); + if (!userWithBookings) { + res.status(404).json({ message: "User not found" }); + return; + } + const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); + // Here we make sure to only return attendee's of the user's own bookings. + if (!userBookingIds.includes(safePost.data.bookingId)) + res.status(401).json({ message: "Unauthorized" }); + else { + const data = await prisma.attendee.create({ + data: { + email: safePost.data.email, + name: safePost.data.name, + timeZone: safePost.data.timeZone, + booking: { connect: { id: safePost.data.bookingId } }, + }, + }); + const attendee = schemaAttendeeReadPublic.parse(data); + + if (attendee) { + res.status(201).json({ + attendee, + message: "Attendee created successfully", + }); + } else (error: Error) => res.status(400).json({ error }); + } + } else { + // @todo: check real availability times before booking + const data = await prisma.attendee.create({ data: { email: safePost.data.email, name: safePost.data.name, diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index ab85b339cd..47d9b80da3 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -12,7 +12,7 @@ import { schemaBookingCreateBodyParams, schemaBookingReadPublic } from "@lib/val import { schemaEventTypeReadPublic } from "@lib/validations/event-type"; async function createOrlistAllBookings( - { method, body, userId }: NextApiRequest, + { method, body, userId, isAdmin }: NextApiRequest, res: NextApiResponse ) { console.log("userIduserId", userId); diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 19435a0bc6..013f9909be 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { EventTypeResponse } from "@lib/types"; -import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaEventTypeEditBodyParams, schemaEventTypeReadPublic } from "@lib/validations/event-type"; import { schemaQueryIdParseInt, @@ -12,10 +11,9 @@ import { } from "@lib/validations/shared/queryIdTransformParseInt"; export async function eventTypeById( - { method, query, body, userId }: NextApiRequest, + { method, query, body, userId, isAdmin }: NextApiRequest, res: NextApiResponse ) { - const isAdmin = await isAdminGuard(userId); const safeQuery = schemaQueryIdParseInt.safeParse(query); if (!safeQuery.success) { res.status(400).json({ message: "Your query was invalid" }); diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index bfe8c3e7ee..dc6844e039 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -4,14 +4,12 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { EventTypeResponse, EventTypesResponse } from "@lib/types"; -import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaEventTypeCreateBodyParams, schemaEventTypeReadPublic } from "@lib/validations/event-type"; async function createOrlistAllEventTypes( - { method, body, userId }: NextApiRequest, + { method, body, userId, isAdmin }: NextApiRequest, res: NextApiResponse ) { - const isAdmin = await isAdminGuard(userId); if (method === "GET") { /** * @swagger diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index 65b864c652..bf70a7a785 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { UserResponse } from "@lib/types"; -import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, @@ -12,7 +11,7 @@ import { import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations/user"; export async function userById( - { method, query, body, userId }: NextApiRequest, + { method, query, body, userId, isAdmin }: NextApiRequest, res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); @@ -21,7 +20,6 @@ export async function userById( res.status(400).json({ message: "Your query was invalid" }); return; } - const isAdmin = await isAdminGuard(userId); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user if (!isAdmin) { if (safeQuery.data.id !== userId) res.status(401).json({ message: "Unauthorized" }); diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 3839ae21b6..d94f198ad8 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { UserResponse, UsersResponse } from "@lib/types"; -import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaUserReadPublic, schemaUserCreateBodyParams } from "@lib/validations/user"; /** @@ -24,10 +23,9 @@ import { schemaUserReadPublic, schemaUserCreateBodyParams } from "@lib/validatio * description: No users were found */ async function getAllorCreateUser( - { userId, method, body }: NextApiRequest, + { userId, method, body, isAdmin }: NextApiRequest, res: NextApiResponse ) { - const isAdmin = await isAdminGuard(userId); if (method === "GET") { if (!isAdmin) { // If user is not ADMIN, return only his data. From 1d2e5f07ef6243f445d320c897584ecb762f338b Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 15 Jun 2022 21:10:19 +0200 Subject: [PATCH 379/658] feat: admin endpoints for bookings --- lib/validations/booking.ts | 1 - pages/api/bookings/[id].ts | 8 +++++--- pages/api/bookings/index.ts | 37 ++++++++++++++++++++++++++----------- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index a8a4b52c37..a7a8eab730 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -3,7 +3,6 @@ import { z } from "zod"; import { _BookingModel as Booking } from "@calcom/prisma/zod"; const schemaBookingBaseBodyParams = Booking.pick({ - uid: true, userId: true, eventTypeId: true, title: true, diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index 7e17c9613a..8603af73c8 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -11,7 +11,7 @@ import { } from "@lib/validations/shared/queryIdTransformParseInt"; export async function bookingById( - { method, query, body, userId }: NextApiRequest, + { method, query, body, userId, isAdmin }: NextApiRequest, res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); @@ -25,8 +25,10 @@ export async function bookingById( }); if (!userWithBookings) throw new Error("User not found"); const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); - if (!userBookingIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); - else { + + if (!isAdmin) { + if (!userBookingIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); + } else { switch (method) { /** * @swagger diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 47d9b80da3..560bca7b8e 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -33,16 +33,29 @@ async function createOrlistAllBookings( * 404: * description: No bookings were found */ - const data = await prisma.booking.findMany({ where: { userId } }); - const bookings = data.map((booking) => schemaBookingReadPublic.parse(booking)); - console.log(`Bookings requested by ${userId}`); - if (bookings) res.status(200).json({ bookings }); - else - (error: Error) => - res.status(404).json({ - message: "No Bookings were found", - error, - }); + if (!isAdmin) { + const data = await prisma.booking.findMany({ where: { userId } }); + const bookings = data.map((booking) => schemaBookingReadPublic.parse(booking)); + if (bookings) res.status(200).json({ bookings }); + else { + (error: Error) => + res.status(404).json({ + message: "No Bookings were found", + error, + }); + } + } else { + const data = await prisma.booking.findMany(); + const bookings = data.map((booking) => schemaBookingReadPublic.parse(booking)); + if (bookings) res.status(200).json({ bookings }); + else { + (error: Error) => + res.status(404).json({ + message: "No Bookings were found", + error, + }); + } + } } else if (method === "POST") { /** * @swagger @@ -83,7 +96,9 @@ async function createOrlistAllBookings( res.status(400).json({ message: "Bad request. Booking body is invalid." }); return; } - safe.data.userId = userId; + if (!isAdmin) { + safe.data.userId = userId; + } const data = await prisma.booking.create({ data: { uid: uuidv4(), ...safe.data } }); const booking = schemaBookingReadPublic.parse(data); From 8c3774e10018bd92596f5e81ca038d9670e4675a Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 15 Jun 2022 21:14:35 +0200 Subject: [PATCH 380/658] fix: remove comment --- pages/api/attendees/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index 6b2c4fc415..e4f3e54f79 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -123,7 +123,6 @@ async function createOrlistAllAttendees( } else (error: Error) => res.status(400).json({ error }); } } else { - // @todo: check real availability times before booking const data = await prisma.attendee.create({ data: { email: safePost.data.email, From 26b9e9456824f514d2e451b33cbd434ab455d02f Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 15 Jun 2022 21:16:46 +0200 Subject: [PATCH 381/658] fix: undo changes in users --- pages/api/users/[id].ts | 4 +++- pages/api/users/index.ts | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index bf70a7a785..65b864c652 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { UserResponse } from "@lib/types"; +import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, @@ -11,7 +12,7 @@ import { import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations/user"; export async function userById( - { method, query, body, userId, isAdmin }: NextApiRequest, + { method, query, body, userId }: NextApiRequest, res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); @@ -20,6 +21,7 @@ export async function userById( res.status(400).json({ message: "Your query was invalid" }); return; } + const isAdmin = await isAdminGuard(userId); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user if (!isAdmin) { if (safeQuery.data.id !== userId) res.status(401).json({ message: "Unauthorized" }); diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index d94f198ad8..3839ae21b6 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { UserResponse, UsersResponse } from "@lib/types"; +import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaUserReadPublic, schemaUserCreateBodyParams } from "@lib/validations/user"; /** @@ -23,9 +24,10 @@ import { schemaUserReadPublic, schemaUserCreateBodyParams } from "@lib/validatio * description: No users were found */ async function getAllorCreateUser( - { userId, method, body, isAdmin }: NextApiRequest, + { userId, method, body }: NextApiRequest, res: NextApiResponse ) { + const isAdmin = await isAdminGuard(userId); if (method === "GET") { if (!isAdmin) { // If user is not ADMIN, return only his data. From aadde45bb7da48ea99865df92f976432f79b8c67 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 4 Jun 2022 01:17:01 +0200 Subject: [PATCH 382/658] fix: add event-types admin endpoints --- pages/api/event-types/index.ts | 58 +++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 0e2467692f..bfe8c3e7ee 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -4,12 +4,14 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { EventTypeResponse, EventTypesResponse } from "@lib/types"; +import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaEventTypeCreateBodyParams, schemaEventTypeReadPublic } from "@lib/validations/event-type"; async function createOrlistAllEventTypes( { method, body, userId }: NextApiRequest, res: NextApiResponse ) { + const isAdmin = await isAdminGuard(userId); if (method === "GET") { /** * @swagger @@ -29,20 +31,27 @@ async function createOrlistAllEventTypes( * 404: * description: No event types were found */ - const data = await prisma.user - .findUnique({ - where: { id: userId }, - rejectOnNotFound: true, - select: { eventTypes: true }, - }) - .catch((error) => res.status(404).json({ message: "No event types were found", error })); - if (data) res.status(200).json({ event_types: data.eventTypes }); - else - (error: Error) => - res.status(404).json({ - message: "No EventTypes were found", - error, - }); + if (!isAdmin) { + const data = await prisma.user + .findUnique({ + where: { id: userId }, + rejectOnNotFound: true, + select: { eventTypes: true }, + }) + .catch((error) => res.status(404).json({ message: "No event types were found", error })); + // @todo: add validations back schemaReadEventType.parse + if (data) res.status(200).json({ event_types: data.eventTypes }); + else + (error: Error) => + res.status(404).json({ + message: "No EventTypes were found", + error, + }); + } else { + const data = await prisma.eventType.findMany({}); + const event_types = data.map((eventType) => schemaEventTypeReadPublic.parse(eventType)); + if (event_types) res.status(200).json({ event_types }); + } } else if (method === "POST") { /** * @swagger @@ -92,17 +101,16 @@ async function createOrlistAllEventTypes( res.status(400).json({ message: "Invalid request body", error: safe.error }); return; } - - const data = await prisma.eventType.create({ data: { ...safe.data, userId } }); - const event_type = schemaEventTypeReadPublic.parse(data); - - if (data) res.status(201).json({ event_type, message: "EventType created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new event type", - error, - }); + if (!isAdmin) { + const data = await prisma.eventType.create({ data: { ...safe.data, userId } }); + const event_type = schemaEventTypeReadPublic.parse(data); + if (data) res.status(201).json({ event_type, message: "EventType created successfully" }); + } else { + // if admin don't re-set userId from input + const data = await prisma.eventType.create({ data: { ...safe.data } }); + const event_type = schemaEventTypeReadPublic.parse(data); + if (data) res.status(201).json({ event_type, message: "EventType created successfully" }); + } } else res.status(405).json({ message: `Method ${method} not allowed` }); } From 514a98f9e042a79169252d227373e9dcd1d72d35 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 4 Jun 2022 01:32:05 +0200 Subject: [PATCH 383/658] feat: add admin endpoint support for event-types id --- pages/api/event-types/[id].ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 20ad84d776..81cefb3ab7 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { EventTypeResponse } from "@lib/types"; +import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaEventTypeEditBodyParams, schemaEventTypeReadPublic } from "@lib/validations/event-type"; import { schemaQueryIdParseInt, @@ -14,19 +15,21 @@ export async function eventTypeById( { method, query, body, userId }: NextApiRequest, res: NextApiResponse ) { + const isAdmin = await isAdminGuard(userId); const safeQuery = schemaQueryIdParseInt.safeParse(query); if (!safeQuery.success) { res.status(400).json({ message: "Your query was invalid" }); return; } - const data = await await prisma.user.findUnique({ + const data = await prisma.user.findUnique({ where: { id: userId }, rejectOnNotFound: true, select: { eventTypes: true }, }); const userEventTypes = data.eventTypes.map((eventType) => eventType.id); - if (!userEventTypes.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); + if (!isAdmin || !userEventTypes.includes(safeQuery.data.id)) + res.status(401).json({ message: "Unauthorized" }); else { switch (method) { /** From d8d0d42374fff2c5cbe03182967a60f8a1841a9b Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 4 Jun 2022 02:26:16 +0200 Subject: [PATCH 384/658] fix: only check event type ownership if not admin --- pages/api/event-types/[id].ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 81cefb3ab7..19435a0bc6 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -27,10 +27,9 @@ export async function eventTypeById( select: { eventTypes: true }, }); const userEventTypes = data.eventTypes.map((eventType) => eventType.id); - - if (!isAdmin || !userEventTypes.includes(safeQuery.data.id)) - res.status(401).json({ message: "Unauthorized" }); - else { + if (!isAdmin) { + if (!userEventTypes.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); + } else { switch (method) { /** * @swagger From dd94df8c97be8eb550f356c3cdce5080030fb7f9 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 15 Jun 2022 22:59:26 +0200 Subject: [PATCH 385/658] merging main to prod fixing conflicts in users --- lib/helpers/verifyApiKey.ts | 6 ++ lib/validations/booking.ts | 1 - pages/api/attendees/[id].ts | 10 +- pages/api/attendees/index.ts | 79 +++++++++----- pages/api/bookings/index.ts | 2 +- pages/api/event-types/[id].ts | 4 +- pages/api/event-types/index.ts | 4 +- pages/api/users/[id].ts | 184 +++++++++++++++++++++++++++++++++ 8 files changed, 251 insertions(+), 39 deletions(-) create mode 100644 pages/api/users/[id].ts diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 481b006849..08c0216737 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -4,12 +4,15 @@ import { NextMiddleware } from "next-api-middleware"; import { hashAPIKey } from "@calcom/ee/lib/api/apiKeys"; import prisma from "@calcom/prisma"; +import { isAdminGuard } from "@lib/utils/isAdmin"; + /** @todo figure how to use the one from `@calcom/types`fi */ /** @todo: remove once `@calcom/types` is updated with it.*/ declare module "next" { export interface NextApiRequest extends IncomingMessage { userId: number; method: string; + isAdmin: boolean; query: { [key: string]: string | string[] }; // eslint-disable-next-line @typescript-eslint/no-explicit-any session: any; @@ -41,5 +44,8 @@ export const verifyApiKey: NextMiddleware = async (req, res, next) => { if (!apiKey.userId) return res.status(404).json({ error: "No user found for this apiKey" }); /* We save the user id in the request for later use */ req.userId = apiKey.userId; + /* We save the isAdmin boolean here for later use */ + req.isAdmin = await isAdminGuard(req.userId); + await next(); }; diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index b61d6913fd..a8a4b52c37 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -24,7 +24,6 @@ export const schemaBookingCreateBodyParams = schemaBookingBaseBodyParams.merge(s const schemaBookingEditParams = z .object({ - uid: z.string().optional(), title: z.string().optional(), startTime: z.date().optional(), endTime: z.date().optional(), diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts index a1674d87a4..a72dbf5812 100644 --- a/pages/api/attendees/[id].ts +++ b/pages/api/attendees/[id].ts @@ -11,7 +11,7 @@ import { } from "@lib/validations/shared/queryIdTransformParseInt"; export async function attendeeById( - { method, query, body, userId }: NextApiRequest, + { method, query, body, userId, isAdmin }: NextApiRequest, res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); @@ -33,9 +33,11 @@ export async function attendeeById( .flat() .map((attendee) => attendee.id) ); - // @note: Here we make sure to only return attendee's of the user's own bookings. - if (!userBookingsAttendeeIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); - else { + // @note: Here we make sure to only return attendee's of the user's own bookings if the user is not an admin. + if (!isAdmin) { + if (!userBookingsAttendeeIds.includes(safeQuery.data.id)) + res.status(401).json({ message: "Unauthorized" }); + } else { switch (method) { /** * @swagger diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index eaae0b28ff..6b2c4fc415 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -1,24 +1,30 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import db from "@calcom/prisma"; +import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { AttendeeResponse, AttendeesResponse } from "@lib/types"; import { schemaAttendeeCreateBodyParams, schemaAttendeeReadPublic } from "@lib/validations/attendee"; async function createOrlistAllAttendees( - { method, userId, body }: NextApiRequest, + { method, userId, body, isAdmin }: NextApiRequest, res: NextApiResponse ) { - const userBookings = await db.booking.findMany({ - where: { - userId, - }, - include: { - attendees: true, - }, - }); - const attendees = userBookings.map((booking) => booking.attendees).flat(); + let attendees; + if (!isAdmin) { + const userBookings = await prisma.booking.findMany({ + where: { + userId, + }, + include: { + attendees: true, + }, + }); + attendees = userBookings.map((booking) => booking.attendees).flat(); + } else { + const data = await prisma.attendee.findMany(); + attendees = data.map((attendee) => schemaAttendeeReadPublic.parse(attendee)); + } if (method === "GET") { /** * @swagger @@ -37,12 +43,7 @@ async function createOrlistAllAttendees( * description: No attendees were found */ if (attendees) res.status(200).json({ attendees }); - else - (error: Error) => - res.status(404).json({ - message: "No Attendees were found", - error, - }); + else (error: Error) => res.status(400).json({ error }); } else if (method === "POST") { /** * @swagger @@ -90,16 +91,40 @@ async function createOrlistAllAttendees( res.status(400).json({ message: "Invalid request body", error: safePost.error }); return; } - const userWithBookings = await db.user.findUnique({ where: { id: userId }, include: { bookings: true } }); - if (!userWithBookings) { - res.status(404).json({ message: "User not found" }); - return; - } - const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); - // Here we make sure to only return attendee's of the user's own bookings. - if (!userBookingIds.includes(safePost.data.bookingId)) res.status(401).json({ message: "Unauthorized" }); - else { - const data = await db.attendee.create({ + if (!isAdmin) { + const userWithBookings = await prisma.user.findUnique({ + where: { id: userId }, + include: { bookings: true }, + }); + if (!userWithBookings) { + res.status(404).json({ message: "User not found" }); + return; + } + const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); + // Here we make sure to only return attendee's of the user's own bookings. + if (!userBookingIds.includes(safePost.data.bookingId)) + res.status(401).json({ message: "Unauthorized" }); + else { + const data = await prisma.attendee.create({ + data: { + email: safePost.data.email, + name: safePost.data.name, + timeZone: safePost.data.timeZone, + booking: { connect: { id: safePost.data.bookingId } }, + }, + }); + const attendee = schemaAttendeeReadPublic.parse(data); + + if (attendee) { + res.status(201).json({ + attendee, + message: "Attendee created successfully", + }); + } else (error: Error) => res.status(400).json({ error }); + } + } else { + // @todo: check real availability times before booking + const data = await prisma.attendee.create({ data: { email: safePost.data.email, name: safePost.data.name, diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index ab85b339cd..47d9b80da3 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -12,7 +12,7 @@ import { schemaBookingCreateBodyParams, schemaBookingReadPublic } from "@lib/val import { schemaEventTypeReadPublic } from "@lib/validations/event-type"; async function createOrlistAllBookings( - { method, body, userId }: NextApiRequest, + { method, body, userId, isAdmin }: NextApiRequest, res: NextApiResponse ) { console.log("userIduserId", userId); diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index 19435a0bc6..013f9909be 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -4,7 +4,6 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { EventTypeResponse } from "@lib/types"; -import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaEventTypeEditBodyParams, schemaEventTypeReadPublic } from "@lib/validations/event-type"; import { schemaQueryIdParseInt, @@ -12,10 +11,9 @@ import { } from "@lib/validations/shared/queryIdTransformParseInt"; export async function eventTypeById( - { method, query, body, userId }: NextApiRequest, + { method, query, body, userId, isAdmin }: NextApiRequest, res: NextApiResponse ) { - const isAdmin = await isAdminGuard(userId); const safeQuery = schemaQueryIdParseInt.safeParse(query); if (!safeQuery.success) { res.status(400).json({ message: "Your query was invalid" }); diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index bfe8c3e7ee..dc6844e039 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -4,14 +4,12 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { EventTypeResponse, EventTypesResponse } from "@lib/types"; -import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaEventTypeCreateBodyParams, schemaEventTypeReadPublic } from "@lib/validations/event-type"; async function createOrlistAllEventTypes( - { method, body, userId }: NextApiRequest, + { method, body, userId, isAdmin }: NextApiRequest, res: NextApiResponse ) { - const isAdmin = await isAdminGuard(userId); if (method === "GET") { /** * @swagger diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts new file mode 100644 index 0000000000..bf70a7a785 --- /dev/null +++ b/pages/api/users/[id].ts @@ -0,0 +1,184 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import prisma from "@calcom/prisma"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import type { UserResponse } from "@lib/types"; +import { + schemaQueryIdParseInt, + withValidQueryIdTransformParseInt, +} from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations/user"; + +export async function userById( + { method, query, body, userId, isAdmin }: NextApiRequest, + res: NextApiResponse +) { + const safeQuery = schemaQueryIdParseInt.safeParse(query); + console.log(body); + if (!safeQuery.success) { + res.status(400).json({ message: "Your query was invalid" }); + return; + } + // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user + if (!isAdmin) { + if (safeQuery.data.id !== userId) res.status(401).json({ message: "Unauthorized" }); + } else { + switch (method) { + case "GET": + /** + * @swagger + * /users/{id}: + * get: + * summary: Find a user, returns your user if regular user. + * operationId: getUserById + * parameters: + * - in: path + * name: id + * example: 4 + * schema: + * type: integer + * required: true + * description: ID of the user to get + * tags: + * - users + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: User was not found + */ + + await prisma.user + .findUnique({ where: { id: safeQuery.data.id } }) + .then((data) => schemaUserReadPublic.parse(data)) + .then((user) => res.status(200).json({ user })) + .catch((error: Error) => + res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) + ); + break; + case "PATCH": + /** + * @swagger + * /users/{id}: + * patch: + * summary: Edit an existing user + * operationId: editUserById + * requestBody: + * description: Edit an existing attendee related to one of your bookings + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * weekStart: + * type: string + * enum: [Monday, Sunday, Saturday] + * example: Monday + * brandColor: + * type: string + * example: "#FF000F" + * darkBrandColor: + * type: string + * example: "#000000" + * timeZone: + * type: string + * example: Europe/London + * parameters: + * - in: path + * name: id + * example: 4 + * schema: + * type: integer + * required: true + * description: ID of the user to edit + * tags: + * - users + * responses: + * 201: + * description: OK, user edited successfuly + * 400: + * description: Bad request. User body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + + const safeBody = schemaUserEditBodyParams.safeParse(body); + if (!safeBody.success) { + res.status(400).json({ message: "Bad request", error: safeBody.error }); + + return; + } + const userSchedules = await prisma.schedule.findMany({ + where: { userId }, + }); + const userSchedulesIds = userSchedules.map((schedule) => schedule.id); + // @note: here we make sure user can only make as default his own scheudles + if ( + safeBody?.data?.defaultScheduleId && + !userSchedulesIds.includes(Number(safeBody?.data?.defaultScheduleId)) + ) { + res.status(400).json({ + message: "Bad request: Invalid default schedule id", + }); + return; + } + await prisma.user + .update({ + where: { id: userId }, + data: safeBody.data, + }) + .then((data) => schemaUserReadPublic.parse(data)) + .then((user) => res.status(200).json({ user })) + .catch((error: Error) => + res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + /** + * @swagger + * /users/{id}: + * delete: + * summary: Remove an existing user + * operationId: removeUserById + * parameters: + * - in: path + * name: id + * example: 1 + * schema: + * type: integer + * required: true + * description: ID of the user to delete + * tags: + * - users + * responses: + * 201: + * description: OK, user removed successfuly + * 400: + * description: Bad request. User id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + + case "DELETE": + await prisma.user + .delete({ where: { id: safeQuery.data.id } }) + .then(() => + res.status(200).json({ message: `User with id: ${safeQuery.data.id} deleted successfully` }) + ) + .catch((error: Error) => + res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) + ); + break; + + default: + res.status(405).json({ message: "Method not allowed" }); + break; + } + } +} + +export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(userById)); From 6349491ae7d711a9134c66e4e17f92fab96cbe3f Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 15 Jun 2022 21:10:19 +0200 Subject: [PATCH 386/658] feat: admin endpoints for bookings --- lib/validations/booking.ts | 1 - pages/api/bookings/[id].ts | 8 +++++--- pages/api/bookings/index.ts | 37 ++++++++++++++++++++++++++----------- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index a8a4b52c37..a7a8eab730 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -3,7 +3,6 @@ import { z } from "zod"; import { _BookingModel as Booking } from "@calcom/prisma/zod"; const schemaBookingBaseBodyParams = Booking.pick({ - uid: true, userId: true, eventTypeId: true, title: true, diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index 7e17c9613a..8603af73c8 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -11,7 +11,7 @@ import { } from "@lib/validations/shared/queryIdTransformParseInt"; export async function bookingById( - { method, query, body, userId }: NextApiRequest, + { method, query, body, userId, isAdmin }: NextApiRequest, res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); @@ -25,8 +25,10 @@ export async function bookingById( }); if (!userWithBookings) throw new Error("User not found"); const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); - if (!userBookingIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); - else { + + if (!isAdmin) { + if (!userBookingIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); + } else { switch (method) { /** * @swagger diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index 47d9b80da3..560bca7b8e 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -33,16 +33,29 @@ async function createOrlistAllBookings( * 404: * description: No bookings were found */ - const data = await prisma.booking.findMany({ where: { userId } }); - const bookings = data.map((booking) => schemaBookingReadPublic.parse(booking)); - console.log(`Bookings requested by ${userId}`); - if (bookings) res.status(200).json({ bookings }); - else - (error: Error) => - res.status(404).json({ - message: "No Bookings were found", - error, - }); + if (!isAdmin) { + const data = await prisma.booking.findMany({ where: { userId } }); + const bookings = data.map((booking) => schemaBookingReadPublic.parse(booking)); + if (bookings) res.status(200).json({ bookings }); + else { + (error: Error) => + res.status(404).json({ + message: "No Bookings were found", + error, + }); + } + } else { + const data = await prisma.booking.findMany(); + const bookings = data.map((booking) => schemaBookingReadPublic.parse(booking)); + if (bookings) res.status(200).json({ bookings }); + else { + (error: Error) => + res.status(404).json({ + message: "No Bookings were found", + error, + }); + } + } } else if (method === "POST") { /** * @swagger @@ -83,7 +96,9 @@ async function createOrlistAllBookings( res.status(400).json({ message: "Bad request. Booking body is invalid." }); return; } - safe.data.userId = userId; + if (!isAdmin) { + safe.data.userId = userId; + } const data = await prisma.booking.create({ data: { uid: uuidv4(), ...safe.data } }); const booking = schemaBookingReadPublic.parse(data); From fe53fd92486657f3a06dadfabded89856bf4beed Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 15 Jun 2022 21:14:35 +0200 Subject: [PATCH 387/658] fix: remove comment --- pages/api/attendees/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index 6b2c4fc415..e4f3e54f79 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -123,7 +123,6 @@ async function createOrlistAllAttendees( } else (error: Error) => res.status(400).json({ error }); } } else { - // @todo: check real availability times before booking const data = await prisma.attendee.create({ data: { email: safePost.data.email, From 3310b9307de602198e2df64e8e56631ce553c794 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 15 Jun 2022 21:16:46 +0200 Subject: [PATCH 388/658] fix: undo changes in users --- pages/api/users/[id].ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts index bf70a7a785..65b864c652 100644 --- a/pages/api/users/[id].ts +++ b/pages/api/users/[id].ts @@ -4,6 +4,7 @@ import prisma from "@calcom/prisma"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { UserResponse } from "@lib/types"; +import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, @@ -11,7 +12,7 @@ import { import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations/user"; export async function userById( - { method, query, body, userId, isAdmin }: NextApiRequest, + { method, query, body, userId }: NextApiRequest, res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); @@ -20,6 +21,7 @@ export async function userById( res.status(400).json({ message: "Your query was invalid" }); return; } + const isAdmin = await isAdminGuard(userId); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user if (!isAdmin) { if (safeQuery.data.id !== userId) res.status(401).json({ message: "Unauthorized" }); From 998970c4cbe527f3c875418bd680403fac826708 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 15 Jun 2022 23:06:30 +0200 Subject: [PATCH 389/658] fix: remove duplicate users/id --- pages/api/users/[id].ts | 186 ---------------------------------------- 1 file changed, 186 deletions(-) delete mode 100644 pages/api/users/[id].ts diff --git a/pages/api/users/[id].ts b/pages/api/users/[id].ts deleted file mode 100644 index 65b864c652..0000000000 --- a/pages/api/users/[id].ts +++ /dev/null @@ -1,186 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { UserResponse } from "@lib/types"; -import { isAdminGuard } from "@lib/utils/isAdmin"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; -import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations/user"; - -export async function userById( - { method, query, body, userId }: NextApiRequest, - res: NextApiResponse -) { - const safeQuery = schemaQueryIdParseInt.safeParse(query); - console.log(body); - if (!safeQuery.success) { - res.status(400).json({ message: "Your query was invalid" }); - return; - } - const isAdmin = await isAdminGuard(userId); - // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user - if (!isAdmin) { - if (safeQuery.data.id !== userId) res.status(401).json({ message: "Unauthorized" }); - } else { - switch (method) { - case "GET": - /** - * @swagger - * /users/{id}: - * get: - * summary: Find a user, returns your user if regular user. - * operationId: getUserById - * parameters: - * - in: path - * name: id - * example: 4 - * schema: - * type: integer - * required: true - * description: ID of the user to get - * tags: - * - users - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: User was not found - */ - - await prisma.user - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaUserReadPublic.parse(data)) - .then((user) => res.status(200).json({ user })) - .catch((error: Error) => - res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) - ); - break; - case "PATCH": - /** - * @swagger - * /users/{id}: - * patch: - * summary: Edit an existing user - * operationId: editUserById - * requestBody: - * description: Edit an existing attendee related to one of your bookings - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * weekStart: - * type: string - * enum: [Monday, Sunday, Saturday] - * example: Monday - * brandColor: - * type: string - * example: "#FF000F" - * darkBrandColor: - * type: string - * example: "#000000" - * timeZone: - * type: string - * example: Europe/London - * parameters: - * - in: path - * name: id - * example: 4 - * schema: - * type: integer - * required: true - * description: ID of the user to edit - * tags: - * - users - * responses: - * 201: - * description: OK, user edited successfuly - * 400: - * description: Bad request. User body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - - const safeBody = schemaUserEditBodyParams.safeParse(body); - if (!safeBody.success) { - res.status(400).json({ message: "Bad request", error: safeBody.error }); - - return; - } - const userSchedules = await prisma.schedule.findMany({ - where: { userId }, - }); - const userSchedulesIds = userSchedules.map((schedule) => schedule.id); - // @note: here we make sure user can only make as default his own scheudles - if ( - safeBody?.data?.defaultScheduleId && - !userSchedulesIds.includes(Number(safeBody?.data?.defaultScheduleId)) - ) { - res.status(400).json({ - message: "Bad request: Invalid default schedule id", - }); - return; - } - await prisma.user - .update({ - where: { id: userId }, - data: safeBody.data, - }) - .then((data) => schemaUserReadPublic.parse(data)) - .then((user) => res.status(200).json({ user })) - .catch((error: Error) => - res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - /** - * @swagger - * /users/{id}: - * delete: - * summary: Remove an existing user - * operationId: removeUserById - * parameters: - * - in: path - * name: id - * example: 1 - * schema: - * type: integer - * required: true - * description: ID of the user to delete - * tags: - * - users - * responses: - * 201: - * description: OK, user removed successfuly - * 400: - * description: Bad request. User id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - - case "DELETE": - await prisma.user - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ message: `User with id: ${safeQuery.data.id} deleted successfully` }) - ) - .catch((error: Error) => - res.status(404).json({ message: `User with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } - } -} - -export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(userById)); From 4389288e699796c67e51dd2706ea003ff6161bed Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 16 Jun 2022 00:04:04 +0200 Subject: [PATCH 390/658] feat: adds users/id/availability endpoint --- pages/api/users/[id]/availability/_get.ts | 29 ++++++++++++++++++++++ pages/api/users/[id]/availability/index.ts | 9 +++++++ 2 files changed, 38 insertions(+) create mode 100644 pages/api/users/[id]/availability/_get.ts create mode 100644 pages/api/users/[id]/availability/index.ts diff --git a/pages/api/users/[id]/availability/_get.ts b/pages/api/users/[id]/availability/_get.ts new file mode 100644 index 0000000000..11c9b3d586 --- /dev/null +++ b/pages/api/users/[id]/availability/_get.ts @@ -0,0 +1,29 @@ +import type { NextApiRequest } from "next"; +import { z } from "zod"; + +import { getUserAvailability } from "@calcom/core/getUserAvailability"; +import { defaultResponder } from "@calcom/lib/server"; +import { stringOrNumber } from "@calcom/prisma/zod-utils"; + +const availabilitySchema = z + .object({ + id: stringOrNumber, + username: z.string().optional(), + dateFrom: z.string(), + dateTo: z.string(), + eventTypeId: stringOrNumber.optional(), + }) + .refine((data) => !!data.username || !!data.id, "Either username or userId should be filled in."); + +async function handler(req: NextApiRequest) { + const { username, id, eventTypeId, dateTo, dateFrom } = availabilitySchema.parse(req.query); + return getUserAvailability({ + username, + dateFrom, + dateTo, + eventTypeId, + userId: id, + }); +} + +export default defaultResponder(handler); diff --git a/pages/api/users/[id]/availability/index.ts b/pages/api/users/[id]/availability/index.ts new file mode 100644 index 0000000000..fe6357f6bc --- /dev/null +++ b/pages/api/users/[id]/availability/index.ts @@ -0,0 +1,9 @@ +import { defaultHandler } from "@calcom/lib/server"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; + +export default withMiddleware("HTTP_GET")( + defaultHandler({ + GET: import("./_get"), + }) +); From 11f3d411b3fbfdecf7a17e32a0e783e7d49c3042 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 16 Jun 2022 00:18:40 +0200 Subject: [PATCH 391/658] fix: rename users id to users userId to easier availability sharing _get endpoint --- lib/validations/shared/queryUserId.ts | 15 ++++++++++ pages/api/availability/_get.ts | 2 +- pages/api/users/[id]/availability/_get.ts | 29 ------------------- pages/api/users/{[id] => [userId]}/_delete.ts | 7 +++-- pages/api/users/{[id] => [userId]}/_get.ts | 9 +++--- pages/api/users/{[id] => [userId]}/_patch.ts | 7 +++-- .../{[id] => [userId]}/availability/index.ts | 2 +- pages/api/users/{[id] => [userId]}/index.ts | 0 8 files changed, 30 insertions(+), 41 deletions(-) create mode 100644 lib/validations/shared/queryUserId.ts delete mode 100644 pages/api/users/[id]/availability/_get.ts rename pages/api/users/{[id] => [userId]}/_delete.ts (84%) rename pages/api/users/{[id] => [userId]}/_get.ts (82%) rename pages/api/users/{[id] => [userId]}/_patch.ts (90%) rename pages/api/users/{[id] => [userId]}/availability/index.ts (81%) rename pages/api/users/{[id] => [userId]}/index.ts (100%) diff --git a/lib/validations/shared/queryUserId.ts b/lib/validations/shared/queryUserId.ts new file mode 100644 index 0000000000..cbe6e282d2 --- /dev/null +++ b/lib/validations/shared/queryUserId.ts @@ -0,0 +1,15 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +import { baseApiParams } from "./baseApiParams"; + +// Extracted out as utility function so can be reused +// at different endpoints that require this validation. +export const schemaQueryUserId = baseApiParams + .extend({ + userId: z + .string() + .regex(/^\d+$/) + .transform((id) => parseInt(id)), + }) + .strict(); diff --git a/pages/api/availability/_get.ts b/pages/api/availability/_get.ts index 21450f005e..5289190c03 100644 --- a/pages/api/availability/_get.ts +++ b/pages/api/availability/_get.ts @@ -7,7 +7,7 @@ import { stringOrNumber } from "@calcom/prisma/zod-utils"; const availabilitySchema = z .object({ - userId: stringOrNumber.optional(), + userId: stringOrNumber, username: z.string().optional(), dateFrom: z.string(), dateTo: z.string(), diff --git a/pages/api/users/[id]/availability/_get.ts b/pages/api/users/[id]/availability/_get.ts deleted file mode 100644 index 11c9b3d586..0000000000 --- a/pages/api/users/[id]/availability/_get.ts +++ /dev/null @@ -1,29 +0,0 @@ -import type { NextApiRequest } from "next"; -import { z } from "zod"; - -import { getUserAvailability } from "@calcom/core/getUserAvailability"; -import { defaultResponder } from "@calcom/lib/server"; -import { stringOrNumber } from "@calcom/prisma/zod-utils"; - -const availabilitySchema = z - .object({ - id: stringOrNumber, - username: z.string().optional(), - dateFrom: z.string(), - dateTo: z.string(), - eventTypeId: stringOrNumber.optional(), - }) - .refine((data) => !!data.username || !!data.id, "Either username or userId should be filled in."); - -async function handler(req: NextApiRequest) { - const { username, id, eventTypeId, dateTo, dateFrom } = availabilitySchema.parse(req.query); - return getUserAvailability({ - username, - dateFrom, - dateTo, - eventTypeId, - userId: id, - }); -} - -export default defaultResponder(handler); diff --git a/pages/api/users/[id]/_delete.ts b/pages/api/users/[userId]/_delete.ts similarity index 84% rename from pages/api/users/[id]/_delete.ts rename to pages/api/users/[userId]/_delete.ts index 7d38d07372..3478c44789 100644 --- a/pages/api/users/[id]/_delete.ts +++ b/pages/api/users/[userId]/_delete.ts @@ -5,7 +5,7 @@ import { defaultResponder } from "@calcom/lib/server"; import prisma from "@calcom/prisma"; import { isAdminGuard } from "@lib/utils/isAdmin"; -import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryUserId } from "@lib/validations/shared/queryUserId"; /** * @swagger @@ -32,10 +32,11 @@ import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformP * description: Authorization information is missing or invalid. */ export async function deleteHandler(req: NextApiRequest) { - const query = schemaQueryIdParseInt.parse(req.query); + const query = schemaQueryUserId.parse(req.query); const isAdmin = await isAdminGuard(req.userId); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user - if (!isAdmin && query.id !== req.userId) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + if (!isAdmin && query.userId !== req.userId) + throw new HttpError({ statusCode: 401, message: "Unauthorized" }); const user = await prisma.user.findUnique({ where: { id: query.id } }); if (!user) throw new HttpError({ statusCode: 404, message: "User not found" }); diff --git a/pages/api/users/[id]/_get.ts b/pages/api/users/[userId]/_get.ts similarity index 82% rename from pages/api/users/[id]/_get.ts rename to pages/api/users/[userId]/_get.ts index 443b935e9c..5c76c4e315 100644 --- a/pages/api/users/[id]/_get.ts +++ b/pages/api/users/[userId]/_get.ts @@ -5,7 +5,7 @@ import { defaultResponder } from "@calcom/lib/server"; import prisma from "@calcom/prisma"; import { isAdminGuard } from "@lib/utils/isAdmin"; -import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryUserId } from "@lib/validations/shared/queryUserId"; import { schemaUserReadPublic } from "@lib/validations/user"; /** @@ -33,11 +33,12 @@ import { schemaUserReadPublic } from "@lib/validations/user"; * description: User was not found */ export async function getHandler(req: NextApiRequest) { - const query = schemaQueryIdParseInt.parse(req.query); + const query = schemaQueryUserId.parse(req.query); const isAdmin = await isAdminGuard(req.userId); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user - if (!isAdmin && query.id !== req.userId) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); - const data = await prisma.user.findUnique({ where: { id: query.id } }); + if (!isAdmin && query.userId !== req.userId) + throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + const data = await prisma.user.findUnique({ where: { id: query.userId } }); const user = schemaUserReadPublic.parse(data); return { user }; } diff --git a/pages/api/users/[id]/_patch.ts b/pages/api/users/[userId]/_patch.ts similarity index 90% rename from pages/api/users/[id]/_patch.ts rename to pages/api/users/[userId]/_patch.ts index a6551609e7..9f32e920c4 100644 --- a/pages/api/users/[id]/_patch.ts +++ b/pages/api/users/[userId]/_patch.ts @@ -5,7 +5,7 @@ import { defaultResponder } from "@calcom/lib/server"; import prisma from "@calcom/prisma"; import { isAdminGuard } from "@lib/utils/isAdmin"; -import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { schemaQueryUserId } from "@lib/validations/shared/queryUserId"; import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations/user"; /** @@ -54,10 +54,11 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations * description: Authorization information is missing or invalid. */ export async function patchHandler(req: NextApiRequest) { - const query = schemaQueryIdParseInt.parse(req.query); + const query = schemaQueryUserId.parse(req.query); const isAdmin = await isAdminGuard(req.userId); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user - if (!isAdmin && query.id !== req.userId) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + if (!isAdmin && query.userId !== req.userId) + throw new HttpError({ statusCode: 401, message: "Unauthorized" }); const body = schemaUserEditBodyParams.parse(req.body); const userSchedules = await prisma.schedule.findMany({ diff --git a/pages/api/users/[id]/availability/index.ts b/pages/api/users/[userId]/availability/index.ts similarity index 81% rename from pages/api/users/[id]/availability/index.ts rename to pages/api/users/[userId]/availability/index.ts index fe6357f6bc..1a27360f81 100644 --- a/pages/api/users/[id]/availability/index.ts +++ b/pages/api/users/[userId]/availability/index.ts @@ -4,6 +4,6 @@ import { withMiddleware } from "@lib/helpers/withMiddleware"; export default withMiddleware("HTTP_GET")( defaultHandler({ - GET: import("./_get"), + GET: import("@api/availability/_get"), }) ); diff --git a/pages/api/users/[id]/index.ts b/pages/api/users/[userId]/index.ts similarity index 100% rename from pages/api/users/[id]/index.ts rename to pages/api/users/[userId]/index.ts From 1889ececf8a7e42eddb1370df18b3ecc7cbfc671 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 16 Jun 2022 01:27:26 +0200 Subject: [PATCH 392/658] feat: improve deployment docs for api --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index 8c39f8457f..ad6c3a78ab 100644 --- a/README.md +++ b/README.md @@ -178,3 +178,20 @@ We make sure of this by not using next in dev, but next build && next start, if See . Here in dev mode OPTIONS method is hardcoded to return only GET and OPTIONS as allowed method. Running in Production mode would cause this file to be not used. This is hot-reloading logic only. To remove this limitation, we need to ensure that on local endpoints are requested by swagger at /api/v1 and not /v1 + + +## Deployment + +We recommend deploying API in vercel. + +There's some settings that you'll need to setup. + +Under Vercel > Your API Deployment > Settings + +In General > Build & Development Settings +BUILD COMMAND: `yarn turbo run build --scope=@calcom/api --include-dependencies --no-deps` +OUTPUT DIRECTORY: `apps/api/.next` + +See `scripts/vercel-deploy.sh` for more info on how the deployment is done. +## Environment variables +Lastly API requires an env var for `DATABASE_URL` \ No newline at end of file From 8b87cde733acef43660e7105e5f67eb4f2d86d20 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 16 Jun 2022 01:48:29 +0200 Subject: [PATCH 393/658] fix: _delete missing userId rename --- pages/api/users/[userId]/_delete.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/users/[userId]/_delete.ts b/pages/api/users/[userId]/_delete.ts index 3478c44789..c2d8d5db29 100644 --- a/pages/api/users/[userId]/_delete.ts +++ b/pages/api/users/[userId]/_delete.ts @@ -38,7 +38,7 @@ export async function deleteHandler(req: NextApiRequest) { if (!isAdmin && query.userId !== req.userId) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); - const user = await prisma.user.findUnique({ where: { id: query.id } }); + const user = await prisma.user.findUnique({ where: { id: query.userId } }); if (!user) throw new HttpError({ statusCode: 404, message: "User not found" }); await prisma.user.delete({ where: { id: user.id } }); From 29be8f52667576b5090e58e84b9be08b3688f72a Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 16 Jun 2022 21:50:41 +0200 Subject: [PATCH 394/658] fix: makes id optional in availability --- pages/api/availability/_get.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/availability/_get.ts b/pages/api/availability/_get.ts index 5289190c03..21450f005e 100644 --- a/pages/api/availability/_get.ts +++ b/pages/api/availability/_get.ts @@ -7,7 +7,7 @@ import { stringOrNumber } from "@calcom/prisma/zod-utils"; const availabilitySchema = z .object({ - userId: stringOrNumber, + userId: stringOrNumber.optional(), username: z.string().optional(), dateFrom: z.string(), dateTo: z.string(), From 2682db8fcd0239868a11bfbc34cfd95bb615e6f0 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 16 Jun 2022 23:38:36 +0200 Subject: [PATCH 395/658] fix: remove user metadta from validations --- lib/validations/user.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/lib/validations/user.ts b/lib/validations/user.ts index 1a69eb5c7c..dcaafdf8d2 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -59,7 +59,6 @@ export const schemaUserBaseBodyParams = User.pick({ timeZone: true, weekStart: true, endTime: true, - metadata: true, bufferTime: true, theme: true, defaultScheduleId: true, @@ -93,7 +92,6 @@ const schemaUserEditParams = z.object({ .optional() .nullable(), locale: z.nativeEnum(locales).optional().nullable(), - metadata: jsonSchema.optional(), }); // @note: These are the values that are editable via PATCH method on the user Model, @@ -116,7 +114,6 @@ const schemaUserCreateParams = z.object({ .optional() .nullable(), locale: z.nativeEnum(locales).optional(), - metadata: jsonSchema, createdDate: z.string().or(z.date()).optional(), }); @@ -141,7 +138,6 @@ export const schemaUserReadPublic = User.pick({ emailVerified: true, bio: true, avatar: true, - metadata: true, timeZone: true, weekStart: true, endTime: true, From 374a6e087ae4b7c86659172c34601540b937f621 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 17 Jun 2022 23:23:28 +0200 Subject: [PATCH 396/658] feat: remove datacredentials, move to deployment.databaseUrl --- lib/helpers/customPrisma.ts | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/lib/helpers/customPrisma.ts b/lib/helpers/customPrisma.ts index dc9bbeeaa3..f106ce36f2 100644 --- a/lib/helpers/customPrisma.ts +++ b/lib/helpers/customPrisma.ts @@ -7,27 +7,31 @@ import { prismaAdmin } from "@calcom/console/modules/common/utils/prisma"; import { asStringOrUndefined } from "@calcom/lib/asStringOrNull"; import { prisma, customPrisma } from "@calcom/prisma"; -// This replaces the prisma client for the cusotm one if the customCredentialsId is valid +// This replaces the prisma client for the cusotm one if the key is valid export const customPrismaClient: NextMiddleware = async (req, res, next) => { const { - query: { customCredentialsId }, - } = req; + query: { key }, + }: { query: { key?: string } } = req; // If no custom api Id is provided, attach to request the regular cal.com prisma client. - if (!customCredentialsId) { + if (!key) { req.prisma = prisma; await next(); } else { - const id = asStringOrUndefined(customCredentialsId); + const id = asStringOrUndefined(key); - // If we have a customCredentialsId, we check if it is valid. - const dataCredentials = await prismaAdmin.dataCredentials.findUnique({ - where: { id }, + // If we have a key, we check if it is valid. + const deployment = await prismaAdmin.deployment.findUnique({ + where: { key }, }); - if (!dataCredentials) { + if (!deployment) { res.status(400).json({ error: "Invalid custom credentials id" }); return; } - const credentials = dataCredentials?.credentials; + const credentials = deployment.databaseUrl; + if (!credentials) { + res.status(400).json({ error: "no databaseUrl set up at your instance yet" }); + return; + } const hashedUrl = await hash(credentials, 12); const cachedPrisma = cache.get(hashedUrl); From 5b28e9ec1c8ce6c53172f725a2da6f8d509e6adf Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 18 Jun 2022 02:16:15 +0200 Subject: [PATCH 397/658] fix: main merging issues --- lib/helpers/extendRequest.ts | 1 - lib/helpers/withMiddleware.ts | 2 +- next.config.js | 1 + pages/api/availabilities/[id].ts | 2 +- pages/api/users/index.ts | 58 -------------------------------- 5 files changed, 3 insertions(+), 61 deletions(-) diff --git a/lib/helpers/extendRequest.ts b/lib/helpers/extendRequest.ts index 52af6da544..8ed3ee0571 100644 --- a/lib/helpers/extendRequest.ts +++ b/lib/helpers/extendRequest.ts @@ -18,6 +18,5 @@ declare module "next" { } } export const extendRequest: NextMiddleware = async (req, res, next) => { - // @note: just an empty middleware, we care about extending the next api request types only. await next(); }; diff --git a/lib/helpers/withMiddleware.ts b/lib/helpers/withMiddleware.ts index 05b21cbf0d..ab6d5cb79e 100644 --- a/lib/helpers/withMiddleware.ts +++ b/lib/helpers/withMiddleware.ts @@ -29,7 +29,7 @@ const withMiddleware = label( sentry: captureErrors, }, // The order here, determines the order of execution, put customPrismaClient before verifyApiKey always. - ["sentry", "customPrismaClient", "verifyApiKey", "addRequestId", "extendRequest"] // <-- Provide a list of middleware to call automatically + ["extendRequest", "sentry", "customPrismaClient", "verifyApiKey", "addRequestId"] // <-- Provide a list of middleware to call automatically ); export { withMiddleware }; diff --git a/next.config.js b/next.config.js index 22ff466595..939eba2374 100644 --- a/next.config.js +++ b/next.config.js @@ -3,6 +3,7 @@ const withTM = require("next-transpile-modules")([ "@calcom/app-store", "@calcom/core", + "@calcom/console", "@calcom/ee", "@calcom/lib", "@calcom/prisma", diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index fe62182978..1d4b6ed4a1 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -1,6 +1,6 @@ import type { NextApiRequest, NextApiResponse } from "next"; -// import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { AvailabilityResponse } from "@lib/types"; import { schemaAvailabilityEditBodyParams, diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 28231b487a..c07846423f 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -1,68 +1,10 @@ -<<<<<<< HEAD -import type { NextApiRequest, NextApiResponse } from "next"; -======= import { defaultHandler } from "@calcom/lib/server"; ->>>>>>> main import { withMiddleware } from "@lib/helpers/withMiddleware"; -<<<<<<< HEAD -/** - * @swagger - * /users: - * get: - * operationId: listUsers - * summary: Find all users. - * tags: - * - users - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No users were found - */ -async function getAllorCreateUser( - { userId, method, body, prisma }: NextApiRequest, - res: NextApiResponse -) { - const isAdmin = await isAdminGuard(userId); - if (method === "GET") { - if (!isAdmin) { - // If user is not ADMIN, return only his data. - const data = await prisma.user.findMany({ where: { id: userId } }); - const users = data.map((user) => schemaUserReadPublic.parse(user)); - if (users) res.status(200).json({ users }); - } else { - // If user is admin, return all users. - const data = await prisma.user.findMany({}); - const users = data.map((user) => schemaUserReadPublic.parse(user)); - if (users) res.status(200).json({ users }); - } - } else if (method === "POST") { - // If user is not ADMIN, return unauthorized. - if (!isAdmin) res.status(401).json({ message: "You are not authorized" }); - else { - const safeBody = schemaUserCreateBodyParams.safeParse(body); - if (!safeBody.success) { - res.status(400).json({ message: "Your body was invalid" }); - return; - } - const user = await prisma.user.create({ - data: safeBody.data, - }); - res.status(201).json({ user }); - } - } -} - -export default withMiddleware("HTTP_GET_OR_POST")(getAllorCreateUser); -======= export default withMiddleware("HTTP_GET_OR_POST")( defaultHandler({ GET: import("./_get"), POST: import("./_post"), }) ); ->>>>>>> main From cc534a2914403f3a23475efdb1dc5d8c339bffb7 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 18 Jun 2022 02:35:39 +0200 Subject: [PATCH 398/658] fix: remove console from api deps --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index dd21735779..94c4c7a2a2 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ "node-mocks-http": "^1.11.0" }, "dependencies": { - "@calcom/console": "*", "@calcom/prisma": "*", "@sentry/nextjs": "^6.19.7", "bcryptjs": "^2.4.3", From 60688e2e9110cc3cc07028d2fc9e69d4d731678c Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 18 Jun 2022 03:03:13 +0200 Subject: [PATCH 399/658] fix: make isAdmin require req.prisma too --- lib/helpers/verifyApiKey.ts | 2 +- lib/utils/isAdmin.ts | 6 ++---- lib/utils/webhookSubscriptions.ts | 2 +- pages/api/users/[userId]/_delete.ts | 2 +- pages/api/users/[userId]/_get.ts | 2 +- pages/api/users/[userId]/_patch.ts | 2 +- pages/api/users/_get.ts | 4 ++-- pages/api/users/_post.ts | 2 +- 8 files changed, 10 insertions(+), 12 deletions(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index ec6aaf1179..8c11cdb492 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -34,7 +34,7 @@ export const verifyApiKey: NextMiddleware = async (req, res, next) => { /* We save the user id in the request for later use */ req.userId = apiKey.userId; /* We save the isAdmin boolean here for later use */ - req.isAdmin = await isAdminGuard(req.userId); + req.isAdmin = await isAdminGuard(req.userId, prisma); await next(); }; diff --git a/lib/utils/isAdmin.ts b/lib/utils/isAdmin.ts index 64af37367f..aab1454b62 100644 --- a/lib/utils/isAdmin.ts +++ b/lib/utils/isAdmin.ts @@ -1,8 +1,6 @@ -import { UserPermissionRole } from "@prisma/client"; +import { PrismaClient, UserPermissionRole } from "@prisma/client"; -import prisma from "@calcom/prisma"; - -export const isAdminGuard = async (userId: number) => { +export const isAdminGuard = async (userId: number, prisma: PrismaClient) => { const user = await prisma.user.findUnique({ where: { id: userId } }); return user?.role === UserPermissionRole.ADMIN; }; diff --git a/lib/utils/webhookSubscriptions.ts b/lib/utils/webhookSubscriptions.ts index bdf9d95576..e53b15e7c5 100644 --- a/lib/utils/webhookSubscriptions.ts +++ b/lib/utils/webhookSubscriptions.ts @@ -7,7 +7,7 @@ export type GetSubscriberOptions = { eventTypeId: number; triggerEvent: WebhookTriggerEvents; }; - +/** @note will this not work with custom prisma? since we're importing prisma directly and not passing it from request here **/ const getWebhooks = async (options: GetSubscriberOptions) => { const { userId, eventTypeId } = options; const allWebhooks = await prisma.webhook.findMany({ diff --git a/pages/api/users/[userId]/_delete.ts b/pages/api/users/[userId]/_delete.ts index c2d8d5db29..ac15975931 100644 --- a/pages/api/users/[userId]/_delete.ts +++ b/pages/api/users/[userId]/_delete.ts @@ -33,7 +33,7 @@ import { schemaQueryUserId } from "@lib/validations/shared/queryUserId"; */ export async function deleteHandler(req: NextApiRequest) { const query = schemaQueryUserId.parse(req.query); - const isAdmin = await isAdminGuard(req.userId); + const isAdmin = await isAdminGuard(req.userId, req.prisma); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user if (!isAdmin && query.userId !== req.userId) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); diff --git a/pages/api/users/[userId]/_get.ts b/pages/api/users/[userId]/_get.ts index 5c76c4e315..2fda8ddc91 100644 --- a/pages/api/users/[userId]/_get.ts +++ b/pages/api/users/[userId]/_get.ts @@ -34,7 +34,7 @@ import { schemaUserReadPublic } from "@lib/validations/user"; */ export async function getHandler(req: NextApiRequest) { const query = schemaQueryUserId.parse(req.query); - const isAdmin = await isAdminGuard(req.userId); + const isAdmin = await isAdminGuard(req.userId, req.prisma); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user if (!isAdmin && query.userId !== req.userId) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); diff --git a/pages/api/users/[userId]/_patch.ts b/pages/api/users/[userId]/_patch.ts index 9f32e920c4..58efa5773b 100644 --- a/pages/api/users/[userId]/_patch.ts +++ b/pages/api/users/[userId]/_patch.ts @@ -55,7 +55,7 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations */ export async function patchHandler(req: NextApiRequest) { const query = schemaQueryUserId.parse(req.query); - const isAdmin = await isAdminGuard(req.userId); + const isAdmin = await isAdminGuard(req.userId, req.prisma); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user if (!isAdmin && query.userId !== req.userId) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); diff --git a/pages/api/users/_get.ts b/pages/api/users/_get.ts index 4c4aadaecd..7f90ba8a27 100644 --- a/pages/api/users/_get.ts +++ b/pages/api/users/_get.ts @@ -24,8 +24,8 @@ import { Prisma } from ".prisma/client"; * 404: * description: No users were found */ -async function getHandler({ userId }: NextApiRequest) { - const isAdmin = await isAdminGuard(userId); +async function getHandler({ userId, prisma }: NextApiRequest) { + const isAdmin = await isAdminGuard(userId, prisma); const where: Prisma.UserWhereInput = {}; // If user is not ADMIN, return only his data. if (!isAdmin) where.id = userId; diff --git a/pages/api/users/_post.ts b/pages/api/users/_post.ts index 908a9c4bcc..2217c49127 100644 --- a/pages/api/users/_post.ts +++ b/pages/api/users/_post.ts @@ -8,7 +8,7 @@ import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaUserCreateBodyParams } from "@lib/validations/user"; async function postHandler(req: NextApiRequest) { - const isAdmin = await isAdminGuard(req.userId); + const isAdmin = await isAdminGuard(req.userId, req.prisma); // If user is not ADMIN, return unauthorized. if (!isAdmin) throw new HttpError({ statusCode: 401, message: "You are not authorized" }); const data = schemaUserCreateBodyParams.parse(req.body); From 39ce6287fcb29543ab6288309e9d9ddc01c97659 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 18 Jun 2022 22:30:27 +0200 Subject: [PATCH 400/658] fix: no need to target 2017 --- tsconfig.json | 1 - 1 file changed, 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index ef00959c45..2714b86c1c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,6 @@ { "extends": "@calcom/tsconfig/nextjs.json", "compilerOptions": { - "target": "es2017", "strict": true, "baseUrl": ".", "paths": { From c3bed7ba8fa4669f73c9bddbdfd19c672cc275c4 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 20 Jun 2022 02:26:20 +0200 Subject: [PATCH 401/658] fix: add console to package --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 94c4c7a2a2..dd21735779 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "node-mocks-http": "^1.11.0" }, "dependencies": { + "@calcom/console": "*", "@calcom/prisma": "*", "@sentry/nextjs": "^6.19.7", "bcryptjs": "^2.4.3", From 4626b3dffa2b5deb9271e040033deb08c8ed6ebd Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 20 Jun 2022 02:29:18 +0200 Subject: [PATCH 402/658] fix: --- lib/helpers/customPrisma.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helpers/customPrisma.ts b/lib/helpers/customPrisma.ts index f106ce36f2..98d1e3b2b2 100644 --- a/lib/helpers/customPrisma.ts +++ b/lib/helpers/customPrisma.ts @@ -3,7 +3,7 @@ import cache from "memory-cache"; import { NextMiddleware } from "next-api-middleware"; import { PRISMA_CLIENT_CACHING_TIME } from "@calcom/api/lib/constants"; -import { prismaAdmin } from "@calcom/console/modules/common/utils/prisma"; +import prismaAdmin from "@calcom/console/modules/common/utils/prisma"; import { asStringOrUndefined } from "@calcom/lib/asStringOrNull"; import { prisma, customPrisma } from "@calcom/prisma"; From e68e6d11652f291365b437c51bf11b45cf4df1d5 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 20 Jun 2022 02:30:51 +0200 Subject: [PATCH 403/658] no console in package --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index dd21735779..94c4c7a2a2 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ "node-mocks-http": "^1.11.0" }, "dependencies": { - "@calcom/console": "*", "@calcom/prisma": "*", "@sentry/nextjs": "^6.19.7", "bcryptjs": "^2.4.3", From 48675f4e7a3e51d6c775a1e08d3e813da546b9d6 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 20 Jun 2022 03:10:10 +0200 Subject: [PATCH 404/658] fix add back console --- next.config.js | 2 +- package.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/next.config.js b/next.config.js index 939eba2374..f1d3bace86 100644 --- a/next.config.js +++ b/next.config.js @@ -3,7 +3,6 @@ const withTM = require("next-transpile-modules")([ "@calcom/app-store", "@calcom/core", - "@calcom/console", "@calcom/ee", "@calcom/lib", "@calcom/prisma", @@ -12,6 +11,7 @@ const withTM = require("next-transpile-modules")([ "@calcom/emails", "@calcom/embed-core", "@calcom/embed-snippet", + "@calcom/console", ]); module.exports = withTM({ diff --git a/package.json b/package.json index 94c4c7a2a2..e1fed1bdb9 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ }, "dependencies": { "@calcom/prisma": "*", + "@calcom/console": "*", "@sentry/nextjs": "^6.19.7", "bcryptjs": "^2.4.3", "memory-cache": "^0.2.0", From 312664d881220c981e2ff7500fc73f004c71869b Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 20 Jun 2022 03:13:03 +0200 Subject: [PATCH 405/658] fix generate schemas console --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e1fed1bdb9..627c6d4565 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "dev": "PORT=3002 next dev", "lint-fix": "next lint --fix && prettier --write .", "lint": "next lint", - "prebuild": "cd ../.. && yarn workspace @calcom/prisma generate-schemas", + "prebuild": "cd ../.. && yarn workspace @calcom/prisma generate-schemas && yarn workspace @calcom/console generate-schemas", "start": "PORT=3002 next start", "test": "jest --detectOpenHandles --passWithNoTests", "type-check": "tsc --pretty --noEmit" From f0f27857fa974fd6db9f10b71f1814acef15ed80 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 20 Jun 2022 03:14:24 +0200 Subject: [PATCH 406/658] no package console --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 627c6d4565..9a3ee1b877 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ }, "dependencies": { "@calcom/prisma": "*", - "@calcom/console": "*", "@sentry/nextjs": "^6.19.7", "bcryptjs": "^2.4.3", "memory-cache": "^0.2.0", From 7558a73ab77b3b120a5e45fcf34698a5bf16fec6 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 20 Jun 2022 03:18:13 +0200 Subject: [PATCH 407/658] fix: dont generate schemas for console --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 9a3ee1b877..94c4c7a2a2 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "dev": "PORT=3002 next dev", "lint-fix": "next lint --fix && prettier --write .", "lint": "next lint", - "prebuild": "cd ../.. && yarn workspace @calcom/prisma generate-schemas && yarn workspace @calcom/console generate-schemas", + "prebuild": "cd ../.. && yarn workspace @calcom/prisma generate-schemas", "start": "PORT=3002 next start", "test": "jest --detectOpenHandles --passWithNoTests", "type-check": "tsc --pretty --noEmit" From 6e78bf15f0e8af3689eeef8be5f50ba54e84da78 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 21 Jun 2022 23:02:43 +0200 Subject: [PATCH 408/658] feat: databaseUrl customPrisma --- lib/helpers/customPrisma.ts | 29 +++++++++++++++++------------ next.config.js | 1 - 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/lib/helpers/customPrisma.ts b/lib/helpers/customPrisma.ts index 98d1e3b2b2..f9da8ebe1e 100644 --- a/lib/helpers/customPrisma.ts +++ b/lib/helpers/customPrisma.ts @@ -3,7 +3,7 @@ import cache from "memory-cache"; import { NextMiddleware } from "next-api-middleware"; import { PRISMA_CLIENT_CACHING_TIME } from "@calcom/api/lib/constants"; -import prismaAdmin from "@calcom/console/modules/common/utils/prisma"; +// import prismaAdmin from "@calcom/console/modules/common/utils/prisma"; import { asStringOrUndefined } from "@calcom/lib/asStringOrNull"; import { prisma, customPrisma } from "@calcom/prisma"; @@ -20,26 +20,31 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { const id = asStringOrUndefined(key); // If we have a key, we check if it is valid. - const deployment = await prismaAdmin.deployment.findUnique({ - where: { key }, - }); - if (!deployment) { - res.status(400).json({ error: "Invalid custom credentials id" }); - return; - } - const credentials = deployment.databaseUrl; - if (!credentials) { + // const deployment = await prismaAdmin.deployment.findUnique({ + // where: { key }, + // }); + const databaseUrl = await fetch(`https://console.cal.com/api/deployments/database?key=${id}`) + .then((res) => res.json()) + .then((res) => res.databaseUrl); + + console.log(databaseUrl); + // if (!databaseUrl) { + // res.status(400).json({ error: "Invalid custom credentials id" }); + // return; + // } + // const credentials = deployment.databaseUrl; + if (!databaseUrl) { res.status(400).json({ error: "no databaseUrl set up at your instance yet" }); return; } - const hashedUrl = await hash(credentials, 12); + const hashedUrl = await hash(databaseUrl, 12); const cachedPrisma = cache.get(hashedUrl); if (!cachedPrisma) { cache.put( hashedUrl, - customPrisma({ datasources: { db: { url: credentials } } }), + customPrisma({ datasources: { db: { url: databaseUrl } } }), PRISMA_CLIENT_CACHING_TIME // Cache the prisma client for 24 hours ); } diff --git a/next.config.js b/next.config.js index f1d3bace86..22ff466595 100644 --- a/next.config.js +++ b/next.config.js @@ -11,7 +11,6 @@ const withTM = require("next-transpile-modules")([ "@calcom/emails", "@calcom/embed-core", "@calcom/embed-snippet", - "@calcom/console", ]); module.exports = withTM({ From b6729d8b82d9ceb7988006e3a5c28fdcf56e29ea Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 22 Jun 2022 05:49:24 +0200 Subject: [PATCH 409/658] fix custom prisma works --- lib/helpers/customPrisma.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/helpers/customPrisma.ts b/lib/helpers/customPrisma.ts index f9da8ebe1e..5082de68da 100644 --- a/lib/helpers/customPrisma.ts +++ b/lib/helpers/customPrisma.ts @@ -5,6 +5,7 @@ import { NextMiddleware } from "next-api-middleware"; import { PRISMA_CLIENT_CACHING_TIME } from "@calcom/api/lib/constants"; // import prismaAdmin from "@calcom/console/modules/common/utils/prisma"; import { asStringOrUndefined } from "@calcom/lib/asStringOrNull"; +import { CONSOLE_URL } from "@calcom/lib/constants"; import { prisma, customPrisma } from "@calcom/prisma"; // This replaces the prisma client for the cusotm one if the key is valid @@ -23,16 +24,12 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { // const deployment = await prismaAdmin.deployment.findUnique({ // where: { key }, // }); - const databaseUrl = await fetch(`https://console.cal.com/api/deployments/database?key=${id}`) + const databaseUrl = await fetch( + `${process.env.NEXT_PUBLIC_CONSOLE_URL || CONSOLE_URL}/api/deployments/database?key=${id}` + ) .then((res) => res.json()) .then((res) => res.databaseUrl); - console.log(databaseUrl); - // if (!databaseUrl) { - // res.status(400).json({ error: "Invalid custom credentials id" }); - // return; - // } - // const credentials = deployment.databaseUrl; if (!databaseUrl) { res.status(400).json({ error: "no databaseUrl set up at your instance yet" }); return; @@ -48,7 +45,7 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { PRISMA_CLIENT_CACHING_TIME // Cache the prisma client for 24 hours ); } - req.prisma = cachedPrisma; + req.prisma = customPrisma({ datasources: { db: { url: databaseUrl } } }); } await next(); }; From 0830abf057033642aaad19cac398bbe7dc2d5bd5 Mon Sep 17 00:00:00 2001 From: zomars Date: Wed, 22 Jun 2022 13:30:02 -0600 Subject: [PATCH 410/658] Scripts should be as pure as possible --- package.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index 493a5929fd..efd55309d7 100644 --- a/package.json +++ b/package.json @@ -7,13 +7,11 @@ "author": "Cal.com Inc.", "private": true, "scripts": { - "app-store:generate": "yarn workspace @calcom/app-store-cli generate", - "build": "yarn app-store:generate && next build", + "build": "next build", "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next", "dev": "PORT=3002 next dev", "lint-fix": "next lint --fix && prettier --write .", "lint": "next lint", - "prebuild": "cd ../.. && yarn workspace @calcom/prisma generate-schemas", "start": "PORT=3002 next start", "test": "jest --detectOpenHandles --passWithNoTests", "type-check": "tsc --pretty --noEmit" @@ -25,6 +23,7 @@ "node-mocks-http": "^1.11.0" }, "dependencies": { + "@calcom/app-store-cli": "*", "@calcom/prisma": "*", "@sentry/nextjs": "^6.19.7", "modify-response-middleware": "^1.1.0", From c3996221e17e582b3ab532309a46e0510821e687 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 23 Jun 2022 19:16:12 +0200 Subject: [PATCH 411/658] fix: don't require apiKey if already using customPrisma with calcom license key --- lib/helpers/customPrisma.ts | 20 +++++++++++--------- lib/helpers/verifyApiKey.ts | 16 ++++++++-------- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/lib/helpers/customPrisma.ts b/lib/helpers/customPrisma.ts index 5082de68da..d5aeaf9749 100644 --- a/lib/helpers/customPrisma.ts +++ b/lib/helpers/customPrisma.ts @@ -4,7 +4,6 @@ import { NextMiddleware } from "next-api-middleware"; import { PRISMA_CLIENT_CACHING_TIME } from "@calcom/api/lib/constants"; // import prismaAdmin from "@calcom/console/modules/common/utils/prisma"; -import { asStringOrUndefined } from "@calcom/lib/asStringOrNull"; import { CONSOLE_URL } from "@calcom/lib/constants"; import { prisma, customPrisma } from "@calcom/prisma"; @@ -18,14 +17,9 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { req.prisma = prisma; await next(); } else { - const id = asStringOrUndefined(key); - - // If we have a key, we check if it is valid. - // const deployment = await prismaAdmin.deployment.findUnique({ - // where: { key }, - // }); + // If we have a key, we check if the deployment matching the key, has a databaseUrl value set. const databaseUrl = await fetch( - `${process.env.NEXT_PUBLIC_CONSOLE_URL || CONSOLE_URL}/api/deployments/database?key=${id}` + `${process.env.NEXT_PUBLIC_CONSOLE_URL || CONSOLE_URL}/api/deployments/database?key=${key}` ) .then((res) => res.json()) .then((res) => res.databaseUrl); @@ -34,10 +28,11 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { res.status(400).json({ error: "no databaseUrl set up at your instance yet" }); return; } + // FIXME: Add some checks for the databaseUrl to make sure it is valid. (e.g. not a localhost) const hashedUrl = await hash(databaseUrl, 12); const cachedPrisma = cache.get(hashedUrl); - + /* We cache each cusotm prisma client for 24h to avoid too many requests to the database. */ if (!cachedPrisma) { cache.put( hashedUrl, @@ -46,6 +41,13 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { ); } req.prisma = customPrisma({ datasources: { db: { url: databaseUrl } } }); + /* @note: + In order to skip verifyApiKey for customPrisma requests, + we pass isAdmin true, and userId 0, if we detect them later, + we skip verifyApiKey logic and pass onto next middleware instead. + */ + req.isAdmin = true; + req.userId = 0; } await next(); }; diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 8c11cdb492..3ee1fad862 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -14,26 +14,26 @@ export const dateNotInPast = function (date: Date) { // This verifies the apiKey and sets the user if it is valid. export const verifyApiKey: NextMiddleware = async (req, res, next) => { - const { prisma } = req; + const { prisma, userId, isAdmin } = req; + // If the user is an admin and using a license key (from customPrisma), skip the apiKey check. + if (userId === 0 && isAdmin) await next(); + // Check if the apiKey query param is provided. if (!req.query.apiKey) return res.status(401).json({ message: "No apiKey provided" }); - - // We remove the prefix from the user provided api_key. If no env set default to "cal_" + // remove the prefix from the user provided api_key. If no env set default to "cal_" const strippedApiKey = `${req.query.apiKey}`.replace(process.env.API_KEY_PREFIX || "cal_", ""); - // Hash the key again before matching against the database records. const hashedKey = hashAPIKey(strippedApiKey); // Check if the hashed api key exists in database. const apiKey = await prisma.apiKey.findUnique({ where: { hashedKey } }); - // console.log("apiKey", apiKey); - // If we cannot find any api key. Throw a 401 Unauthorized. + // If cannot find any api key. Throw a 401 Unauthorized. if (!apiKey) return res.status(401).json({ error: "Your apiKey is not valid" }); if (apiKey.expiresAt && dateNotInPast(apiKey.expiresAt)) { return res.status(401).json({ error: "This apiKey is expired" }); } if (!apiKey.userId) return res.status(404).json({ error: "No user found for this apiKey" }); - /* We save the user id in the request for later use */ + // save the user id in the request for later use req.userId = apiKey.userId; - /* We save the isAdmin boolean here for later use */ + // save the isAdmin boolean here for later use req.isAdmin = await isAdminGuard(req.userId, prisma); await next(); From aa64f3237843cab292c843ac0471033934863b85 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 23 Jun 2022 23:20:07 +0200 Subject: [PATCH 412/658] fix set headers error by adding missing return --- lib/helpers/verifyApiKey.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 3ee1fad862..4a375aee26 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -16,7 +16,10 @@ export const dateNotInPast = function (date: Date) { export const verifyApiKey: NextMiddleware = async (req, res, next) => { const { prisma, userId, isAdmin } = req; // If the user is an admin and using a license key (from customPrisma), skip the apiKey check. - if (userId === 0 && isAdmin) await next(); + if (userId === 0 && isAdmin) { + await next(); + return; + } // Check if the apiKey query param is provided. if (!req.query.apiKey) return res.status(401).json({ message: "No apiKey provided" }); // remove the prefix from the user provided api_key. If no env set default to "cal_" From 04b9b71310f29ef93fc8c03ed1a47941c9066e20 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 24 Jun 2022 00:09:23 +0200 Subject: [PATCH 413/658] fix: userId not, id remove templates stall --- lib/utils/webhookSubscriptions.ts | 6 +- lib/validations/shared/queryUserId.ts | 5 ++ pages/api/bookings/index.ts | 2 +- pages/api/users/[userId]/_delete.ts | 2 +- pages/api/users/[userId]/_get.ts | 3 +- pages/api/users/[userId]/_patch.ts | 2 +- pages/api/users/[userId]/index.ts | 6 +- pages/api/users/_get.ts | 1 - pages/api/users/_post.ts | 4 +- templates/README.md | 49 ---------------- templates/endpoints/[id]/delete.ts | 50 ----------------- templates/endpoints/[id]/edit.ts | 58 ------------------- templates/endpoints/[id]/index.ts | 52 ----------------- templates/endpoints/get_all.ts | 38 ------------- templates/endpoints/get_all_and_post.ts | 75 ------------------------- templates/endpoints/post.ts | 51 ----------------- templates/zod-validation.ts | 16 ------ 17 files changed, 17 insertions(+), 403 deletions(-) delete mode 100644 templates/README.md delete mode 100644 templates/endpoints/[id]/delete.ts delete mode 100644 templates/endpoints/[id]/edit.ts delete mode 100644 templates/endpoints/[id]/index.ts delete mode 100644 templates/endpoints/get_all.ts delete mode 100644 templates/endpoints/get_all_and_post.ts delete mode 100644 templates/endpoints/post.ts delete mode 100644 templates/zod-validation.ts diff --git a/lib/utils/webhookSubscriptions.ts b/lib/utils/webhookSubscriptions.ts index e53b15e7c5..af185248b3 100644 --- a/lib/utils/webhookSubscriptions.ts +++ b/lib/utils/webhookSubscriptions.ts @@ -1,6 +1,4 @@ -import { WebhookTriggerEvents } from "@prisma/client"; - -import prisma from "@calcom/prisma"; +import { WebhookTriggerEvents, PrismaClient } from "@prisma/client"; export type GetSubscriberOptions = { userId: number; @@ -8,7 +6,7 @@ export type GetSubscriberOptions = { triggerEvent: WebhookTriggerEvents; }; /** @note will this not work with custom prisma? since we're importing prisma directly and not passing it from request here **/ -const getWebhooks = async (options: GetSubscriberOptions) => { +const getWebhooks = async (options: GetSubscriberOptions, prisma: PrismaClient) => { const { userId, eventTypeId } = options; const allWebhooks = await prisma.webhook.findMany({ where: { diff --git a/lib/validations/shared/queryUserId.ts b/lib/validations/shared/queryUserId.ts index cbe6e282d2..94a7700003 100644 --- a/lib/validations/shared/queryUserId.ts +++ b/lib/validations/shared/queryUserId.ts @@ -13,3 +13,8 @@ export const schemaQueryUserId = baseApiParams .transform((id) => parseInt(id)), }) .strict(); +export const withValidQueryUserId = withValidation({ + schema: schemaQueryUserId, + type: "Zod", + mode: "query", +}); diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index fb1fd347aa..b70e059d8b 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -142,7 +142,7 @@ async function createOrlistAllBookings( }; console.log(`subscriberOptions: ${subscriberOptions}`); - const subscribers = await getWebhooks(subscriberOptions); + const subscribers = await getWebhooks(subscriberOptions, prisma); console.log(`subscribers: ${subscribers}`); const bookingId = booking?.id; const promises = subscribers.map((sub) => diff --git a/pages/api/users/[userId]/_delete.ts b/pages/api/users/[userId]/_delete.ts index ac15975931..0f5c208e2a 100644 --- a/pages/api/users/[userId]/_delete.ts +++ b/pages/api/users/[userId]/_delete.ts @@ -2,7 +2,6 @@ import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import prisma from "@calcom/prisma"; import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaQueryUserId } from "@lib/validations/shared/queryUserId"; @@ -32,6 +31,7 @@ import { schemaQueryUserId } from "@lib/validations/shared/queryUserId"; * description: Authorization information is missing or invalid. */ export async function deleteHandler(req: NextApiRequest) { + const { prisma } = req; const query = schemaQueryUserId.parse(req.query); const isAdmin = await isAdminGuard(req.userId, req.prisma); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user diff --git a/pages/api/users/[userId]/_get.ts b/pages/api/users/[userId]/_get.ts index 2fda8ddc91..76b2603a89 100644 --- a/pages/api/users/[userId]/_get.ts +++ b/pages/api/users/[userId]/_get.ts @@ -2,7 +2,6 @@ import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import prisma from "@calcom/prisma"; import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaQueryUserId } from "@lib/validations/shared/queryUserId"; @@ -33,6 +32,8 @@ import { schemaUserReadPublic } from "@lib/validations/user"; * description: User was not found */ export async function getHandler(req: NextApiRequest) { + const { prisma } = req; + const query = schemaQueryUserId.parse(req.query); const isAdmin = await isAdminGuard(req.userId, req.prisma); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user diff --git a/pages/api/users/[userId]/_patch.ts b/pages/api/users/[userId]/_patch.ts index 58efa5773b..b7bf27c47f 100644 --- a/pages/api/users/[userId]/_patch.ts +++ b/pages/api/users/[userId]/_patch.ts @@ -2,7 +2,6 @@ import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import prisma from "@calcom/prisma"; import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaQueryUserId } from "@lib/validations/shared/queryUserId"; @@ -54,6 +53,7 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations * description: Authorization information is missing or invalid. */ export async function patchHandler(req: NextApiRequest) { + const { prisma } = req; const query = schemaQueryUserId.parse(req.query); const isAdmin = await isAdminGuard(req.userId, req.prisma); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user diff --git a/pages/api/users/[userId]/index.ts b/pages/api/users/[userId]/index.ts index 7d8887e5d1..66c0e9b25c 100644 --- a/pages/api/users/[userId]/index.ts +++ b/pages/api/users/[userId]/index.ts @@ -1,10 +1,10 @@ -import { defaultHandler } from "@/../../packages/lib/server"; +import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { withValidQueryIdTransformParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; +import { withValidQueryUserId } from "@lib/validations/shared/queryUserId"; export default withMiddleware("HTTP_GET_DELETE_PATCH")( - withValidQueryIdTransformParseInt( + withValidQueryUserId( defaultHandler({ GET: import("./_get"), PATCH: import("./_patch"), diff --git a/pages/api/users/_get.ts b/pages/api/users/_get.ts index 7f90ba8a27..42ec41ecfb 100644 --- a/pages/api/users/_get.ts +++ b/pages/api/users/_get.ts @@ -1,7 +1,6 @@ import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; -import prisma from "@calcom/prisma"; import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaUsersReadPublic } from "@lib/validations/user"; diff --git a/pages/api/users/_post.ts b/pages/api/users/_post.ts index 2217c49127..8809aa7e8a 100644 --- a/pages/api/users/_post.ts +++ b/pages/api/users/_post.ts @@ -1,13 +1,13 @@ -import { HttpError } from "@/../../packages/lib/http-error"; import type { NextApiRequest } from "next"; +import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import prisma from "@calcom/prisma"; import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaUserCreateBodyParams } from "@lib/validations/user"; async function postHandler(req: NextApiRequest) { + const { prisma } = req; const isAdmin = await isAdminGuard(req.userId, req.prisma); // If user is not ADMIN, return unauthorized. if (!isAdmin) throw new HttpError({ statusCode: 401, message: "You are not authorized" }); diff --git a/templates/README.md b/templates/README.md deleted file mode 100644 index 3a171b9318..0000000000 --- a/templates/README.md +++ /dev/null @@ -1,49 +0,0 @@ -# How to add a new model or endpoint - -Basically there's three places of the codebase you need to think about for each feature. - -/pages/api/ - -- This is the most important one, and where your endpoint will live. You will leverage nextjs dynamic routes and expose one file for each endpoint you want to support ideally. - -## How the codebase is organized. - -## The example resource -model- and it's endpoints - -### `pages/api/endpoint/` - -| Method | route | action | -| ------ | --------------------------- | ------------------------- | -| GET | pages/api/endpoint/index.ts | Read All of your resource | -| POST | pages/api/endpoint/new.ts | Create new resource | - -### `pages/api/endpoint/[id]/` - -| Method | route | action | -| ------ | --------------------------------- | ------------------------- | -| GET | pages/api/endpoint/[id]/index.ts | Read All of your resource | -| PATCH | pages/api/endpoint/[id]/edit.ts | Create new resource | -| DELETE | pages/api/endpoint/[id]/delete.ts | Create new resource | - -## `/tests/` - -This is where all your endpoint's tests live, we mock prisma calls. We aim for at least 50% global coverage. Please test each of your endpoints. - -### `/tests/endpoint/` - -| route | action | -| -------------------------------------- | ---------------------------------------------- | -| /tests/endpoint/resource.index.test.ts | Test for your pages/api/endpoint/index.ts file | -| tests/endpoint/resource.new.test.ts | Create new resource | - -### `/tests/endpoint/[id]/` - -| route | action | -| ---------------------------------------------- | ------------------------- | -| `/tests/endpoint/[id]/resource.index.test.ts` | Read All of your resource | -| `/tests/endpoint/[id]/resource.edit.test.ts` | Create new resource | -| `/tests/endpoint/[id]/resource.delete.test.ts` | Create new resource | - -## `/lib/validations/yourEndpoint.ts` - -- This is where our model validations, live, we try to make a 1:1 for db models, and also extract out any re-usable code into the /lib/validations/shared/ sub-folder. diff --git a/templates/endpoints/[id]/delete.ts b/templates/endpoints/[id]/delete.ts deleted file mode 100644 index 39e026f418..0000000000 --- a/templates/endpoints/[id]/delete.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BaseResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /v1/resources/{id}/delete: - * delete: - * summary: Remove an existing resource - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the resource to delete - - * tags: - * - resources - * responses: - * 201: - * description: OK, resource removed successfuly - * 400: - * description: Bad request. Resource id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function deleteResource({ query }: NextApiRequest, res: NextApiResponse) { - const safe = schemaQueryIdParseInt.safeParse(query); - if (!safe.success) throw new Error("Invalid request query"); - - const data = await prisma.resource.delete({ where: { id: safe.data.id } }); - - if (data) res.status(200).json({ message: `Resource with id: ${safe.data.id} deleted successfully` }); - else - (error: Error) => - res.status(400).json({ - message: `Resource with id: ${safe.data.id} was not able to be processed`, - error, - }); -} - -export default withMiddleware("HTTP_DELETE")(withValidQueryIdTransformParseInt(deleteResource)); diff --git a/templates/endpoints/[id]/edit.ts b/templates/endpoints/[id]/edit.ts deleted file mode 100644 index cb4b1f05c5..0000000000 --- a/templates/endpoints/[id]/edit.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { ResourceResponse } from "@lib/types"; -import { schemaResourceBodyParams, schemaResourcePublic, withValidResource } from "@lib/validations/resource"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /v1/resources/{id}/edit: - * patch: - * summary: Edit an existing resource - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the resource to edit - - * tags: - * - resources - * responses: - * 201: - * description: OK, resource edited successfuly - * 400: - * description: Bad request. Resource body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function editResource({ query, body }: NextApiRequest, res: NextApiResponse) { - const safeQuery = schemaQueryIdParseInt.safeParse(query); - const safeBody = schemaResourceBodyParams.safeParse(body); - - if (!safeQuery.success || !safeBody.success) throw new Error("Invalid request"); - const resource = await prisma.resource.update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }); - const data = schemaResourcePublic.parse(resource); - - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: `Event type with ID ${safeQuery.data.id} not found and wasn't updated`, - error, - }); -} - -export default withMiddleware("HTTP_PATCH")( - withValidQueryIdTransformParseInt(withValidResource(editResource)) -); diff --git a/templates/endpoints/[id]/index.ts b/templates/endpoints/[id]/index.ts deleted file mode 100644 index da3a2fd2dd..0000000000 --- a/templates/endpoints/[id]/index.ts +++ /dev/null @@ -1,52 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { ResourceResponse } from "@lib/types"; -import { schemaResourcePublic } from "@lib/validations/resource"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /v1/resources/{id}: - * get: - * summary: Find a resource - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the resource to get - - * tags: - * - resources - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Resource was not found - */ -export async function resourceById({ query }: NextApiRequest, res: NextApiResponse) { - const safe = schemaQueryIdParseInt.safeParse(query); - if (!safe.success) throw new Error("Invalid request query"); - - const resource = await prisma.resource.findUnique({ where: { id: safe.data.id } }); - const data = schemaResourcePublic.parse(resource); - - if (resource) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "Resource was not found", - error, - }); -} - -export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(resourceById)); diff --git a/templates/endpoints/get_all.ts b/templates/endpoints/get_all.ts deleted file mode 100644 index e925133346..0000000000 --- a/templates/endpoints/get_all.ts +++ /dev/null @@ -1,38 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { ResourcesResponse } from "@lib/types"; -import { schemaResourcePublic } from "@lib/validations/resource"; - -/** - * @swagger - * /v1/resources: - * get: - * summary: Find all resources - - * tags: - * - resources - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No resources were found - */ -async function allResources(_: NextApiRequest, res: NextApiResponse) { - const resources = await prisma.resource.findMany(); - const data = resources.map((resource) => schemaResourcePublic.parse(resource)); - - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "No Resources were found", - error, - }); -} - -export default withMiddleware("HTTP_GET")(allResources); diff --git a/templates/endpoints/get_all_and_post.ts b/templates/endpoints/get_all_and_post.ts deleted file mode 100644 index d1cc4ea665..0000000000 --- a/templates/endpoints/get_all_and_post.ts +++ /dev/null @@ -1,75 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { PaymentResponse, PaymentsResponse } from "@lib/types"; -import { schemaPaymentBodyParams, schemaPaymentPublic } from "@lib/validations/payment"; - -async function createOrlistAllPayments( - { method, body }: NextApiRequest, - res: NextApiResponse -) { - if (method === "GET") { - /** - * @swagger - * /v1/payments: - * get: - * summary: Find all payments - - * tags: - * - payments - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No payments were found - */ - const payments = await prisma.payment.findMany(); - const data = payments.map((payment) => schemaPaymentPublic.parse(payment)); - if (data) res.status(200).json({ data }); - else - (error: Error) => - res.status(404).json({ - message: "No Payments were found", - error, - }); - } else if (method === "POST") { - /** - * @swagger - * /v1/payments: - * post: - * summary: Creates a new payment - - * tags: - * - payments - * responses: - * 201: - * description: OK, payment created - * 400: - * description: Bad request. Payment body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - const safe = schemaPaymentBodyParams.safeParse(body); - if (!safe.success) { - res.status(400).json({ message: "Invalid request body" }); - return; - } - - const payment = await prisma.payment.create({ data: safe.data }); - const data = schemaPaymentPublic.parse(payment); - - if (data) res.status(201).json({ data, message: "Payment created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new payment", - error, - }); - } else res.status(405).json({ message: `Method ${method} not allowed` }); -} - -export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllPayments); diff --git a/templates/endpoints/post.ts b/templates/endpoints/post.ts deleted file mode 100644 index 2b91522c62..0000000000 --- a/templates/endpoints/post.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import prisma from "@calcom/prisma"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { ResourceResponse } from "@lib/types"; -import { schemaResourceBodyParams, schemaResourcePublic, withValidResource } from "@lib/validations/resource"; - -/** - * @swagger - * /v1/resources/new: - * post: - * summary: Creates a new resource - * requestBody: - * description: Optional description in *Markdown* - * required: true - * content: - * application/json: - * schema: - * $ref: '#/components/schemas/Resource' - - * tags: - * - resources - * responses: - * 201: - * description: OK, resource created - * 400: - * description: Bad request. Resource body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function createResource({ body }: NextApiRequest, res: NextApiResponse) { - const safe = schemaResourceBodyParams.safeParse(body); - if (!safe.success) { - res.status(400).json({ message: "Invalid request body" }); - return; - } - - const resource = await prisma.resource.create({ data: safe.data }); - const data = schemaResourcePublic.parse(resource); - - if (data) res.status(201).json({ data, message: "Resource created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new resource", - error, - }); -} - -export default withMiddleware("HTTP_POST")(withValidResource(createResource)); diff --git a/templates/zod-validation.ts b/templates/zod-validation.ts deleted file mode 100644 index 82a95a97d1..0000000000 --- a/templates/zod-validation.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { z } from "zod"; - -import { _ModelModel as Model } from "@calcom/prisma/zod"; - -export const schemaModelBaseBodyParams = Model.omit({ id: true, userId: true, createdAt: true }).partial(); - -const schemaModelRequiredParams = z.object({ - email: z.string().email(), -}); - -export const schemaModelBodyParams = schemaModelBaseBodyParams.merge(schemaModelRequiredParams); - -export const schemaModelPublic = Model.omit({ - id: true, - userId: true, -}); From 61c82eb1971bd8a9a89127cd16c66e254e086fe0 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 24 Jun 2022 00:26:40 +0200 Subject: [PATCH 414/658] fix: address issues raised in preview PR --- README.md | 5 ++--- lib/constants.ts | 2 +- lib/helpers/customPrisma.ts | 2 +- lib/helpers/verifyApiKey.ts | 2 +- lib/utils/isAdmin.ts | 5 +++-- lib/utils/webhookSubscriptions.ts | 2 +- pages/api/users/[userId]/_delete.ts | 2 +- pages/api/users/[userId]/_get.ts | 2 +- pages/api/users/[userId]/_patch.ts | 2 +- pages/api/users/_get.ts | 5 +++-- pages/api/users/_post.ts | 2 +- 11 files changed, 16 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 009ac0dd0d..da64d6178d 100644 --- a/README.md +++ b/README.md @@ -179,13 +179,12 @@ We make sure of this by not using next in dev, but next build && next start, if See . Here in dev mode OPTIONS method is hardcoded to return only GET and OPTIONS as allowed method. Running in Production mode would cause this file to be not used. This is hot-reloading logic only. To remove this limitation, we need to ensure that on local endpoints are requested by swagger at /api/v1 and not /v1 - ## Hosted api through cal.com -Go to console.com +Go to console.cal.com Add a deployment or go to an existing one. Activate API or Admin addon -Provide your DATABASE-URL +Provide your `DATABASE_URL` Store it safely, you'll get a customApiID, save it. call api.cal.com?apiKey=your_cal_instance_apiKey&customApiId=cal_datasource_key ## How to deploy diff --git a/lib/constants.ts b/lib/constants.ts index 52c7fe0a41..96af470397 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -1 +1 @@ -export const PRISMA_CLIENT_CACHING_TIME = 1000 * 60 * 60 * 24; +export const PRISMA_CLIENT_CACHING_TIME = 1000 * 60 * 60 * 24; // = 86_400_000 ms, 24 hours / 1 day. diff --git a/lib/helpers/customPrisma.ts b/lib/helpers/customPrisma.ts index d5aeaf9749..61edbfd221 100644 --- a/lib/helpers/customPrisma.ts +++ b/lib/helpers/customPrisma.ts @@ -3,7 +3,6 @@ import cache from "memory-cache"; import { NextMiddleware } from "next-api-middleware"; import { PRISMA_CLIENT_CACHING_TIME } from "@calcom/api/lib/constants"; -// import prismaAdmin from "@calcom/console/modules/common/utils/prisma"; import { CONSOLE_URL } from "@calcom/lib/constants"; import { prisma, customPrisma } from "@calcom/prisma"; @@ -16,6 +15,7 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { if (!key) { req.prisma = prisma; await next(); + return; } else { // If we have a key, we check if the deployment matching the key, has a databaseUrl value set. const databaseUrl = await fetch( diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 4a375aee26..e5cf0332a3 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -37,7 +37,7 @@ export const verifyApiKey: NextMiddleware = async (req, res, next) => { // save the user id in the request for later use req.userId = apiKey.userId; // save the isAdmin boolean here for later use - req.isAdmin = await isAdminGuard(req.userId, prisma); + req.isAdmin = await isAdminGuard(req); await next(); }; diff --git a/lib/utils/isAdmin.ts b/lib/utils/isAdmin.ts index aab1454b62..b068ebe12f 100644 --- a/lib/utils/isAdmin.ts +++ b/lib/utils/isAdmin.ts @@ -1,6 +1,7 @@ -import { PrismaClient, UserPermissionRole } from "@prisma/client"; +import { UserPermissionRole } from "@prisma/client"; -export const isAdminGuard = async (userId: number, prisma: PrismaClient) => { +export const isAdminGuard = async (req: NextApiRequest) => { + const { userId, prisma } = req; const user = await prisma.user.findUnique({ where: { id: userId } }); return user?.role === UserPermissionRole.ADMIN; }; diff --git a/lib/utils/webhookSubscriptions.ts b/lib/utils/webhookSubscriptions.ts index af185248b3..51de834f2d 100644 --- a/lib/utils/webhookSubscriptions.ts +++ b/lib/utils/webhookSubscriptions.ts @@ -5,7 +5,7 @@ export type GetSubscriberOptions = { eventTypeId: number; triggerEvent: WebhookTriggerEvents; }; -/** @note will this not work with custom prisma? since we're importing prisma directly and not passing it from request here **/ + const getWebhooks = async (options: GetSubscriberOptions, prisma: PrismaClient) => { const { userId, eventTypeId } = options; const allWebhooks = await prisma.webhook.findMany({ diff --git a/pages/api/users/[userId]/_delete.ts b/pages/api/users/[userId]/_delete.ts index 0f5c208e2a..d03c569709 100644 --- a/pages/api/users/[userId]/_delete.ts +++ b/pages/api/users/[userId]/_delete.ts @@ -33,7 +33,7 @@ import { schemaQueryUserId } from "@lib/validations/shared/queryUserId"; export async function deleteHandler(req: NextApiRequest) { const { prisma } = req; const query = schemaQueryUserId.parse(req.query); - const isAdmin = await isAdminGuard(req.userId, req.prisma); + const isAdmin = await isAdminGuard(req); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user if (!isAdmin && query.userId !== req.userId) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); diff --git a/pages/api/users/[userId]/_get.ts b/pages/api/users/[userId]/_get.ts index 76b2603a89..36320e1636 100644 --- a/pages/api/users/[userId]/_get.ts +++ b/pages/api/users/[userId]/_get.ts @@ -35,7 +35,7 @@ export async function getHandler(req: NextApiRequest) { const { prisma } = req; const query = schemaQueryUserId.parse(req.query); - const isAdmin = await isAdminGuard(req.userId, req.prisma); + const isAdmin = await isAdminGuard(req); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user if (!isAdmin && query.userId !== req.userId) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); diff --git a/pages/api/users/[userId]/_patch.ts b/pages/api/users/[userId]/_patch.ts index b7bf27c47f..9d12d178bc 100644 --- a/pages/api/users/[userId]/_patch.ts +++ b/pages/api/users/[userId]/_patch.ts @@ -55,7 +55,7 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations export async function patchHandler(req: NextApiRequest) { const { prisma } = req; const query = schemaQueryUserId.parse(req.query); - const isAdmin = await isAdminGuard(req.userId, req.prisma); + const isAdmin = await isAdminGuard(req); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user if (!isAdmin && query.userId !== req.userId) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); diff --git a/pages/api/users/_get.ts b/pages/api/users/_get.ts index 42ec41ecfb..703760adb5 100644 --- a/pages/api/users/_get.ts +++ b/pages/api/users/_get.ts @@ -23,8 +23,9 @@ import { Prisma } from ".prisma/client"; * 404: * description: No users were found */ -async function getHandler({ userId, prisma }: NextApiRequest) { - const isAdmin = await isAdminGuard(userId, prisma); +async function getHandler(req: NextApiRequest) { + const { userId, prisma } = req; + const isAdmin = await isAdminGuard(req); const where: Prisma.UserWhereInput = {}; // If user is not ADMIN, return only his data. if (!isAdmin) where.id = userId; diff --git a/pages/api/users/_post.ts b/pages/api/users/_post.ts index 8809aa7e8a..4ff41bde62 100644 --- a/pages/api/users/_post.ts +++ b/pages/api/users/_post.ts @@ -8,7 +8,7 @@ import { schemaUserCreateBodyParams } from "@lib/validations/user"; async function postHandler(req: NextApiRequest) { const { prisma } = req; - const isAdmin = await isAdminGuard(req.userId, req.prisma); + const isAdmin = await isAdminGuard(req); // If user is not ADMIN, return unauthorized. if (!isAdmin) throw new HttpError({ statusCode: 401, message: "You are not authorized" }); const data = schemaUserCreateBodyParams.parse(req.body); From 4e738cf80c0c33ad2535e667edac06062720b85d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 24 Jun 2022 00:31:55 +0200 Subject: [PATCH 415/658] fix: minor readme update --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index da64d6178d..c806ecc3e4 100644 --- a/README.md +++ b/README.md @@ -185,8 +185,7 @@ Go to console.cal.com Add a deployment or go to an existing one. Activate API or Admin addon Provide your `DATABASE_URL` -Store it safely, you'll get a customApiID, save it. -call api.cal.com?apiKey=your_cal_instance_apiKey&customApiId=cal_datasource_key +Now you can call api.cal.com?key=CALCOM_LICENSE_KEY, which will connect to your own databaseUrl. ## How to deploy We recommend deploying API in vercel. From bfe27057a02c52c9f63f82d2368823527cf5b3c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Thu, 23 Jun 2022 16:40:01 -0600 Subject: [PATCH 416/658] Update lib/constants.ts --- lib/constants.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/constants.ts b/lib/constants.ts index 96af470397..fb04db4a1c 100644 --- a/lib/constants.ts +++ b/lib/constants.ts @@ -1 +1 @@ -export const PRISMA_CLIENT_CACHING_TIME = 1000 * 60 * 60 * 24; // = 86_400_000 ms, 24 hours / 1 day. +export const PRISMA_CLIENT_CACHING_TIME = 1000 * 60 * 60 * 24; // one day in ms From 3c32bc8528654981bee28eb944b79278133d29ad Mon Sep 17 00:00:00 2001 From: zomars Date: Thu, 23 Jun 2022 16:42:22 -0600 Subject: [PATCH 417/658] Update customPrisma.ts --- lib/helpers/customPrisma.ts | 54 ++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/lib/helpers/customPrisma.ts b/lib/helpers/customPrisma.ts index 61edbfd221..f2d038c5e5 100644 --- a/lib/helpers/customPrisma.ts +++ b/lib/helpers/customPrisma.ts @@ -16,38 +16,38 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { req.prisma = prisma; await next(); return; - } else { - // If we have a key, we check if the deployment matching the key, has a databaseUrl value set. - const databaseUrl = await fetch( - `${process.env.NEXT_PUBLIC_CONSOLE_URL || CONSOLE_URL}/api/deployments/database?key=${key}` - ) - .then((res) => res.json()) - .then((res) => res.databaseUrl); + } + // If we have a key, we check if the deployment matching the key, has a databaseUrl value set. + const databaseUrl = await fetch( + `${process.env.NEXT_PUBLIC_CONSOLE_URL || CONSOLE_URL}/api/deployments/database?key=${key}` + ) + .then((res) => res.json()) + .then((res) => res.databaseUrl); - if (!databaseUrl) { - res.status(400).json({ error: "no databaseUrl set up at your instance yet" }); - return; - } - // FIXME: Add some checks for the databaseUrl to make sure it is valid. (e.g. not a localhost) - const hashedUrl = await hash(databaseUrl, 12); + if (!databaseUrl) { + res.status(400).json({ error: "no databaseUrl set up at your instance yet" }); + return; + } + // FIXME: Add some checks for the databaseUrl to make sure it is valid. (e.g. not a localhost) + const hashedUrl = await hash(databaseUrl, 12); - const cachedPrisma = cache.get(hashedUrl); - /* We cache each cusotm prisma client for 24h to avoid too many requests to the database. */ - if (!cachedPrisma) { - cache.put( - hashedUrl, - customPrisma({ datasources: { db: { url: databaseUrl } } }), - PRISMA_CLIENT_CACHING_TIME // Cache the prisma client for 24 hours - ); - } - req.prisma = customPrisma({ datasources: { db: { url: databaseUrl } } }); - /* @note: + const cachedPrisma = cache.get(hashedUrl); + /* We cache each cusotm prisma client for 24h to avoid too many requests to the database. */ + if (!cachedPrisma) { + cache.put( + hashedUrl, + customPrisma({ datasources: { db: { url: databaseUrl } } }), + PRISMA_CLIENT_CACHING_TIME // Cache the prisma client for 24 hours + ); + } + req.prisma = customPrisma({ datasources: { db: { url: databaseUrl } } }); + /* @note: In order to skip verifyApiKey for customPrisma requests, we pass isAdmin true, and userId 0, if we detect them later, we skip verifyApiKey logic and pass onto next middleware instead. */ - req.isAdmin = true; - req.userId = 0; - } + req.isAdmin = true; + req.userId = 0; + await next(); }; From f85b00507a18319c27063a6003c5e41bc026e849 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 24 Jun 2022 00:46:42 +0200 Subject: [PATCH 418/658] fix: add type import for NextApiRequest --- lib/utils/isAdmin.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/utils/isAdmin.ts b/lib/utils/isAdmin.ts index b068ebe12f..c07086fbd6 100644 --- a/lib/utils/isAdmin.ts +++ b/lib/utils/isAdmin.ts @@ -1,4 +1,5 @@ import { UserPermissionRole } from "@prisma/client"; +import type { NextApiRequest } from "next/types"; export const isAdminGuard = async (req: NextApiRequest) => { const { userId, prisma } = req; From 561271f3f626c57fb668e4f08ab46dff1de72fcc Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 24 Jun 2022 00:53:15 +0200 Subject: [PATCH 419/658] fix: isAdmin from req, no isAdminGuard everywhere --- pages/api/users/[userId]/_delete.ts | 4 +--- pages/api/users/[userId]/_get.ts | 4 +--- pages/api/users/[userId]/_patch.ts | 4 +--- pages/api/users/_get.ts | 4 +--- pages/api/users/_post.ts | 4 +--- 5 files changed, 5 insertions(+), 15 deletions(-) diff --git a/pages/api/users/[userId]/_delete.ts b/pages/api/users/[userId]/_delete.ts index d03c569709..391e341244 100644 --- a/pages/api/users/[userId]/_delete.ts +++ b/pages/api/users/[userId]/_delete.ts @@ -3,7 +3,6 @@ import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaQueryUserId } from "@lib/validations/shared/queryUserId"; /** @@ -31,9 +30,8 @@ import { schemaQueryUserId } from "@lib/validations/shared/queryUserId"; * description: Authorization information is missing or invalid. */ export async function deleteHandler(req: NextApiRequest) { - const { prisma } = req; + const { prisma, isAdmin } = req; const query = schemaQueryUserId.parse(req.query); - const isAdmin = await isAdminGuard(req); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user if (!isAdmin && query.userId !== req.userId) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); diff --git a/pages/api/users/[userId]/_get.ts b/pages/api/users/[userId]/_get.ts index 36320e1636..e379c5fbf1 100644 --- a/pages/api/users/[userId]/_get.ts +++ b/pages/api/users/[userId]/_get.ts @@ -3,7 +3,6 @@ import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaQueryUserId } from "@lib/validations/shared/queryUserId"; import { schemaUserReadPublic } from "@lib/validations/user"; @@ -32,10 +31,9 @@ import { schemaUserReadPublic } from "@lib/validations/user"; * description: User was not found */ export async function getHandler(req: NextApiRequest) { - const { prisma } = req; + const { prisma, isAdmin } = req; const query = schemaQueryUserId.parse(req.query); - const isAdmin = await isAdminGuard(req); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user if (!isAdmin && query.userId !== req.userId) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); diff --git a/pages/api/users/[userId]/_patch.ts b/pages/api/users/[userId]/_patch.ts index 9d12d178bc..9e6fee7f91 100644 --- a/pages/api/users/[userId]/_patch.ts +++ b/pages/api/users/[userId]/_patch.ts @@ -3,7 +3,6 @@ import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaQueryUserId } from "@lib/validations/shared/queryUserId"; import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations/user"; @@ -53,9 +52,8 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations * description: Authorization information is missing or invalid. */ export async function patchHandler(req: NextApiRequest) { - const { prisma } = req; + const { prisma, isAdmin } = req; const query = schemaQueryUserId.parse(req.query); - const isAdmin = await isAdminGuard(req); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user if (!isAdmin && query.userId !== req.userId) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); diff --git a/pages/api/users/_get.ts b/pages/api/users/_get.ts index 703760adb5..67bb53e2d1 100644 --- a/pages/api/users/_get.ts +++ b/pages/api/users/_get.ts @@ -2,7 +2,6 @@ import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; -import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaUsersReadPublic } from "@lib/validations/user"; import { Prisma } from ".prisma/client"; @@ -24,8 +23,7 @@ import { Prisma } from ".prisma/client"; * description: No users were found */ async function getHandler(req: NextApiRequest) { - const { userId, prisma } = req; - const isAdmin = await isAdminGuard(req); + const { userId, prisma, isAdmin } = req; const where: Prisma.UserWhereInput = {}; // If user is not ADMIN, return only his data. if (!isAdmin) where.id = userId; diff --git a/pages/api/users/_post.ts b/pages/api/users/_post.ts index 4ff41bde62..03ab696e96 100644 --- a/pages/api/users/_post.ts +++ b/pages/api/users/_post.ts @@ -3,12 +3,10 @@ import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import { isAdminGuard } from "@lib/utils/isAdmin"; import { schemaUserCreateBodyParams } from "@lib/validations/user"; async function postHandler(req: NextApiRequest) { - const { prisma } = req; - const isAdmin = await isAdminGuard(req); + const { prisma, isAdmin } = req; // If user is not ADMIN, return unauthorized. if (!isAdmin) throw new HttpError({ statusCode: 401, message: "You are not authorized" }); const data = schemaUserCreateBodyParams.parse(req.body); From be2647790c39ec95280f5cd489dd8e139e879b0d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 30 Jun 2022 00:01:14 +0200 Subject: [PATCH 420/658] feat: refactor teams and add team availability --- lib/validations/shared/queryTeamId.ts | 21 +++ lib/validations/team.ts | 2 +- pages/api/teams/[id].ts | 146 ------------------ pages/api/teams/[teamId]/_delete.ts | 57 +++++++ pages/api/teams/[teamId]/_get.ts | 48 ++++++ pages/api/teams/[teamId]/_patch.ts | 62 ++++++++ .../api/teams/[teamId]/availability/index.ts | 9 ++ pages/api/teams/[teamId]/index.ts | 14 ++ pages/api/teams/_get.ts | 43 ++++++ pages/api/teams/_post.ts | 47 ++++++ pages/api/teams/index.ts | 91 +---------- pages/api/users/_post.ts | 16 ++ 12 files changed, 325 insertions(+), 231 deletions(-) create mode 100644 lib/validations/shared/queryTeamId.ts delete mode 100644 pages/api/teams/[id].ts create mode 100644 pages/api/teams/[teamId]/_delete.ts create mode 100644 pages/api/teams/[teamId]/_get.ts create mode 100644 pages/api/teams/[teamId]/_patch.ts create mode 100644 pages/api/teams/[teamId]/availability/index.ts create mode 100644 pages/api/teams/[teamId]/index.ts create mode 100644 pages/api/teams/_get.ts create mode 100644 pages/api/teams/_post.ts diff --git a/lib/validations/shared/queryTeamId.ts b/lib/validations/shared/queryTeamId.ts new file mode 100644 index 0000000000..f2a80361eb --- /dev/null +++ b/lib/validations/shared/queryTeamId.ts @@ -0,0 +1,21 @@ +import { withValidation } from "next-validations"; +import { z } from "zod"; + +import { baseApiParams } from "./baseApiParams"; + +// Extracted out as utility function so can be reused +// at different endpoints that require this validation. +export const schemaQueryTeamId = baseApiParams + .extend({ + teamId: z + .string() + .regex(/^\d+$/) + .transform((id) => parseInt(id)), + }) + .strict(); + +export const withValidQueryTeamId = withValidation({ + schema: schemaQueryTeamId, + type: "Zod", + mode: "query", +}); diff --git a/lib/validations/team.ts b/lib/validations/team.ts index d980607f87..1efa3e84df 100644 --- a/lib/validations/team.ts +++ b/lib/validations/team.ts @@ -8,4 +8,4 @@ const schemaTeamRequiredParams = z.object({}); export const schemaTeamBodyParams = schemaTeamBaseBodyParams.merge(schemaTeamRequiredParams); -export const schemaTeamPublic = Team.omit({}); +export const schemaTeamReadPublic = Team.omit({}); diff --git a/pages/api/teams/[id].ts b/pages/api/teams/[id].ts deleted file mode 100644 index 65dd8d116e..0000000000 --- a/pages/api/teams/[id].ts +++ /dev/null @@ -1,146 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { TeamResponse } from "@lib/types"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; -import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; - -/** - * @swagger - * /teams/{id}: - * get: - * operationId: getTeamById - * summary: Find a team - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the team to get - * tags: - * - teams - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Team was not found - * patch: - * operationId: editTeamById - * summary: Edit an existing team - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the team to edit - * tags: - * - teams - * responses: - * 201: - * description: OK, team edited successfuly - * 400: - * description: Bad request. Team body is invalid. - * 401: - * description: Authorization information is missing or invalid. - * delete: - * operationId: removeTeamById - * summary: Remove an existing team - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the team to delete - * tags: - * - teams - * responses: - * 201: - * description: OK, team removed successfuly - * 400: - * description: Bad request. Team id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -export async function teamById( - { method, query, body, userId, prisma }: NextApiRequest, - res: NextApiResponse -) { - const safeQuery = schemaQueryIdParseInt.safeParse(query); - const safeBody = schemaTeamBodyParams.safeParse(body); - if (!safeQuery.success) { - res.status(400).json({ message: "Your query was invalid" }); - return; - } - const userWithMemberships = await prisma.membership.findMany({ - where: { userId: userId }, - }); - //FIXME: This is a hack to get the teamId from the user's membership - console.log(userWithMemberships); - const userTeamIds = userWithMemberships.map((membership) => membership.teamId); - if (!userTeamIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); - else { - switch (method) { - case "GET": - await prisma.team - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaTeamPublic.parse(data)) - .then((team) => res.status(200).json({ team })) - .catch((error: Error) => - res.status(404).json({ - message: `Team with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - - case "PATCH": - if (!safeBody.success) { - { - res.status(400).json({ message: "Invalid request body" }); - return; - } - } - await prisma.team - .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) - .then((team) => schemaTeamPublic.parse(team)) - .then((team) => res.status(200).json({ team })) - .catch((error: Error) => - res.status(404).json({ - message: `Team with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - - case "DELETE": - await prisma.team - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ - message: `Team with id: ${safeQuery.data.id} deleted successfully`, - }) - ) - .catch((error: Error) => - res.status(404).json({ - message: `Team with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } - } -} - -export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(teamById)); diff --git a/pages/api/teams/[teamId]/_delete.ts b/pages/api/teams/[teamId]/_delete.ts new file mode 100644 index 0000000000..39b982caff --- /dev/null +++ b/pages/api/teams/[teamId]/_delete.ts @@ -0,0 +1,57 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaQueryTeamId } from "@lib/validations/shared/queryTeamId"; + +/** + * @swagger + * /users/{teamId}: + * delete: + * operationId: removeTeamById + * summary: Remove an existing team + * parameters: + * - in: path + * name: teamId + * schema: + * type: integer + * required: true + * description: ID of the team to delete + * tags: + * - teams + * responses: + * 201: + * description: OK, team removed successfuly + * 400: + * description: Bad request. Team id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteHandler(req: NextApiRequest, res: NextApiResponse) { + const { prisma, isAdmin, userId } = req; + + const query = schemaQueryTeamId.parse(req.query); + const userWithMemberships = await prisma.membership.findMany({ + where: { userId: userId }, + }); + const userTeamIds = userWithMemberships.map((membership) => membership.teamId); + // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user + if (!isAdmin && !userTeamIds.includes(query.teamId)) + throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + await prisma.team + .delete({ where: { id: query.teamId } }) + .then(() => + res.status(200).json({ + message: `Team with id: ${query.teamId} deleted successfully`, + }) + ) + .catch((error: Error) => + res.status(404).json({ + message: `Team with id: ${query.teamId} not found`, + error, + }) + ); +} + +export default defaultResponder(deleteHandler); diff --git a/pages/api/teams/[teamId]/_get.ts b/pages/api/teams/[teamId]/_get.ts new file mode 100644 index 0000000000..b2295d40fa --- /dev/null +++ b/pages/api/teams/[teamId]/_get.ts @@ -0,0 +1,48 @@ +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaQueryTeamId } from "@lib/validations/shared/queryTeamId"; +import { schemaTeamReadPublic } from "@lib/validations/team"; + +/** + * @swagger + * /teams/{teamId}: + * get: + * operationId: getTeamById + * summary: Find a team + * parameters: + * - in: path + * name: teamId + * schema: + * type: integer + * required: true + * description: ID of the team to get + * tags: + * - teams + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Team was not found + */ +export async function getHandler(req: NextApiRequest) { + const { prisma, isAdmin, userId } = req; + + const query = schemaQueryTeamId.parse(req.query); + const userWithMemberships = await prisma.membership.findMany({ + where: { userId: userId }, + }); + const userTeamIds = userWithMemberships.map((membership) => membership.teamId); + // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user + if (!isAdmin && !userTeamIds.includes(query.teamId)) + throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + const data = await prisma.team.findUnique({ where: { id: query.teamId } }); + const team = schemaTeamReadPublic.parse(data); + return { team }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/teams/[teamId]/_patch.ts b/pages/api/teams/[teamId]/_patch.ts new file mode 100644 index 0000000000..7550cd49b5 --- /dev/null +++ b/pages/api/teams/[teamId]/_patch.ts @@ -0,0 +1,62 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaQueryTeamId } from "@lib/validations/shared/queryTeamId"; +import { schemaTeamBodyParams, schemaTeamReadPublic } from "@lib/validations/team"; + +/** + * @swagger + * /teams/{teamId}: + * patch: + * operationId: editTeamById + * summary: Edit an existing team + * parameters: + * - in: path + * name: teamId + * schema: + * type: integer + * required: true + * description: ID of the team to edit + * tags: + * - teams + * responses: + * 201: + * description: OK, team edited successfuly + * 400: + * description: Bad request. Team body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function patchHandler(req: NextApiRequest, res: NextApiResponse) { + const { prisma, isAdmin, userId, body } = req; + const safeBody = schemaTeamBodyParams.safeParse(body); + + const query = schemaQueryTeamId.parse(req.query); + const userWithMemberships = await prisma.membership.findMany({ + where: { userId: userId }, + }); + const userTeamIds = userWithMemberships.map((membership) => membership.teamId); + // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user + if (!isAdmin && !userTeamIds.includes(query.teamId)) + throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + if (!safeBody.success) { + { + res.status(400).json({ message: "Invalid request body" }); + return; + } + } + await prisma.team + .update({ where: { id: query.teamId }, data: safeBody.data }) + .then((team) => schemaTeamReadPublic.parse(team)) + .then((team) => res.status(200).json({ team })) + .catch((error: Error) => + res.status(404).json({ + message: `Team with id: ${query.teamId} not found`, + error, + }) + ); +} + +export default defaultResponder(patchHandler); diff --git a/pages/api/teams/[teamId]/availability/index.ts b/pages/api/teams/[teamId]/availability/index.ts new file mode 100644 index 0000000000..1a27360f81 --- /dev/null +++ b/pages/api/teams/[teamId]/availability/index.ts @@ -0,0 +1,9 @@ +import { defaultHandler } from "@calcom/lib/server"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; + +export default withMiddleware("HTTP_GET")( + defaultHandler({ + GET: import("@api/availability/_get"), + }) +); diff --git a/pages/api/teams/[teamId]/index.ts b/pages/api/teams/[teamId]/index.ts new file mode 100644 index 0000000000..ed397498d4 --- /dev/null +++ b/pages/api/teams/[teamId]/index.ts @@ -0,0 +1,14 @@ +import { defaultHandler } from "@calcom/lib/server"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { withValidQueryTeamId } from "@lib/validations/shared/queryTeamId"; + +export default withMiddleware("HTTP_GET_DELETE_PATCH")( + withValidQueryTeamId( + defaultHandler({ + GET: import("./_get"), + PATCH: import("./_patch"), + DELETE: import("./_delete"), + }) + ) +); diff --git a/pages/api/teams/_get.ts b/pages/api/teams/_get.ts new file mode 100644 index 0000000000..4a175c899b --- /dev/null +++ b/pages/api/teams/_get.ts @@ -0,0 +1,43 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaTeamReadPublic } from "@lib/validations/team"; + +import { Prisma } from ".prisma/client"; + +/** + * @swagger + * /teams: + * get: + * operationId: listTeams + * summary: Find all teams + * tags: + * - teams + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No teams were found + */ +async function getHandler(req: NextApiRequest) { + const { userId, prisma, isAdmin } = req; + const membershipWhere: Prisma.MembershipWhereInput = {}; + // If user is not ADMIN, return only his data. + if (!isAdmin) membershipWhere.userId = userId; + const userWithMemberships = await prisma.membership.findMany({ + where: membershipWhere, + }); + const teamIds = userWithMemberships.map((membership) => membership.teamId); + const teamWhere: Prisma.TeamWhereInput = {}; + + if (!isAdmin) teamWhere.id = { in: teamIds }; + + const data = await prisma.team.findMany({ where: teamWhere }); + const teams = schemaTeamReadPublic.parse(data); + return { teams }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/teams/_post.ts b/pages/api/teams/_post.ts new file mode 100644 index 0000000000..53f66d7746 --- /dev/null +++ b/pages/api/teams/_post.ts @@ -0,0 +1,47 @@ +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaMembershipPublic } from "@lib/validations/membership"; +import { schemaTeamBodyParams, schemaTeamReadPublic } from "@lib/validations/team"; + +/** + * @swagger + * /teams: + * post: + * operationId: addTeam + * summary: Creates a new team + * tags: + * - teams + * responses: + * 201: + * description: OK, team created + * 400: + * description: Bad request. Team body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function postHandler(req: NextApiRequest) { + const { prisma, body, userId } = req; + const safe = schemaTeamBodyParams.safeParse(body); + if (!safe.success) throw new HttpError({ statusCode: 400, message: "Invalid request body" }); + const data = await prisma.team.create({ data: safe.data }); + // We're also creating the relation membership of team ownership in this call. + const owner = await prisma.membership + .create({ + data: { userId, teamId: data.id, role: "OWNER", accepted: true }, + }) + .then((owner) => schemaMembershipPublic.parse(owner)); + const team = schemaTeamReadPublic.parse(data); + if (!team) throw new HttpError({ statusCode: 400, message: "We were not able to create your team" }); + req.statusCode = 201; + // We are also returning the new ownership relation as owner besides team. + return { + team, + owner, + message: "Team created successfully, we also made you the owner of this team", + }; +} + +export default defaultResponder(postHandler); diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index 1dcc046f6e..c07846423f 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -1,87 +1,10 @@ -import type { NextApiRequest, NextApiResponse } from "next"; +import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { TeamResponse, TeamsResponse } from "@lib/types"; -import { schemaMembershipPublic } from "@lib/validations/membership"; -import { schemaTeamBodyParams, schemaTeamPublic } from "@lib/validations/team"; -async function createOrlistAllTeams( - { method, body, userId, prisma }: NextApiRequest, - res: NextApiResponse -) { - if (method === "GET") { - /** - * @swagger - * /teams: - * get: - * operationId: listTeams - * summary: Find all teams - * tags: - * - teams - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No teams were found - */ - const userWithMemberships = await prisma.membership.findMany({ - where: { userId: userId }, - }); - const teamIds = userWithMemberships.map((membership) => membership.teamId); - const teams = await prisma.team.findMany({ where: { id: { in: teamIds } } }); - if (teams) res.status(200).json({ teams }); - else - (error: Error) => - res.status(404).json({ - message: "No Teams were found", - error, - }); - } else if (method === "POST") { - /** - * @swagger - * /teams: - * post: - * operationId: addTeam - * summary: Creates a new team - * tags: - * - teams - * responses: - * 201: - * description: OK, team created - * 400: - * description: Bad request. Team body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - const safe = schemaTeamBodyParams.safeParse(body); - if (!safe.success) { - res.status(400).json({ message: "Invalid request body" }); - return; - } - const team = await prisma.team.create({ data: safe.data }); - // We're also creating the relation membership of team ownership in this call. - const membership = await prisma.membership - .create({ - data: { userId, teamId: team.id, role: "OWNER", accepted: true }, - }) - .then((membership) => schemaMembershipPublic.parse(membership)); - const data = schemaTeamPublic.parse(team); - // We are also returning the new ownership relation as owner besides team. - if (data) - res.status(201).json({ - team: data, - owner: membership, - message: "Team created successfully, we also made you the owner of this team", - }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new team", - error, - }); - } else res.status(405).json({ message: `Method ${method} not allowed` }); -} - -export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllTeams); +export default withMiddleware("HTTP_GET_OR_POST")( + defaultHandler({ + GET: import("./_get"), + POST: import("./_post"), + }) +); diff --git a/pages/api/users/_post.ts b/pages/api/users/_post.ts index 03ab696e96..268931b122 100644 --- a/pages/api/users/_post.ts +++ b/pages/api/users/_post.ts @@ -5,6 +5,22 @@ import { defaultResponder } from "@calcom/lib/server"; import { schemaUserCreateBodyParams } from "@lib/validations/user"; +/** + * @swagger + * /users: + * post: + * operationId: addUser + * summary: Creates a new user + * tags: + * - users + * responses: + * 201: + * description: OK, user created + * 400: + * description: Bad request. user body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ async function postHandler(req: NextApiRequest) { const { prisma, isAdmin } = req; // If user is not ADMIN, return unauthorized. From 571f3fda4ee1062c898754beed50cb0d2d9b7475 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 2 Jul 2022 04:49:09 +0200 Subject: [PATCH 421/658] fix: transpile new @calcom/dayjs package in API --- next.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/next.config.js b/next.config.js index 22ff466595..a423307a4b 100644 --- a/next.config.js +++ b/next.config.js @@ -8,6 +8,7 @@ const withTM = require("next-transpile-modules")([ "@calcom/prisma", "@calcom/stripe", "@calcom/ui", + "calcom/dayjs", "@calcom/emails", "@calcom/embed-core", "@calcom/embed-snippet", From 517749812d486f969c2429900d5e7f1072d1a878 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Sat, 2 Jul 2022 05:04:21 +0200 Subject: [PATCH 422/658] fix: missing @ --- next.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/next.config.js b/next.config.js index a423307a4b..f8491c9904 100644 --- a/next.config.js +++ b/next.config.js @@ -8,7 +8,7 @@ const withTM = require("next-transpile-modules")([ "@calcom/prisma", "@calcom/stripe", "@calcom/ui", - "calcom/dayjs", + "@calcom/dayjs", "@calcom/emails", "@calcom/embed-core", "@calcom/embed-snippet", From a63b623a7da87a66acbc2b870dff2bfbe0e29b0f Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 5 Jul 2022 20:12:14 +0200 Subject: [PATCH 423/658] feat: teamId availability in API --- lib/helpers/extendRequest.ts | 5 +++++ lib/helpers/withMiddleware.ts | 3 +++ lib/helpers/withPagination.ts | 12 +++++++++++ lib/validations/user.ts | 1 + next.config.js | 1 + pages/api/availability/_get.ts | 39 ++++++++++++++++++++++++++-------- pages/api/users/_get.ts | 14 +++++++++--- 7 files changed, 63 insertions(+), 12 deletions(-) create mode 100644 lib/helpers/withPagination.ts diff --git a/lib/helpers/extendRequest.ts b/lib/helpers/extendRequest.ts index 8ed3ee0571..14de404418 100644 --- a/lib/helpers/extendRequest.ts +++ b/lib/helpers/extendRequest.ts @@ -15,8 +15,13 @@ declare module "next" { session: { user: { id: number } }; query: { [key: string]: string | string[] }; isAdmin: boolean; + pagination: { take: number; skip: number }; } } export const extendRequest: NextMiddleware = async (req, res, next) => { + req.pagination = { + take: 100, + skip: 0, + }; await next(); }; diff --git a/lib/helpers/withMiddleware.ts b/lib/helpers/withMiddleware.ts index ab6d5cb79e..9ce21233fb 100644 --- a/lib/helpers/withMiddleware.ts +++ b/lib/helpers/withMiddleware.ts @@ -1,4 +1,5 @@ import { label } from "next-api-middleware"; +import PagesManifestPlugin from "next/dist/build/webpack/plugins/pages-manifest-plugin"; import { addRequestId } from "./addRequestid"; import { captureErrors } from "./captureErrors"; @@ -13,6 +14,7 @@ import { HTTP_GET_DELETE_PATCH, } from "./httpMethods"; import { verifyApiKey } from "./verifyApiKey"; +import { withPagination } from "./withPagination"; const withMiddleware = label( { @@ -26,6 +28,7 @@ const withMiddleware = label( verifyApiKey, customPrismaClient, extendRequest, + pagination: withPagination, sentry: captureErrors, }, // The order here, determines the order of execution, put customPrismaClient before verifyApiKey always. diff --git a/lib/helpers/withPagination.ts b/lib/helpers/withPagination.ts new file mode 100644 index 0000000000..6d76c680f1 --- /dev/null +++ b/lib/helpers/withPagination.ts @@ -0,0 +1,12 @@ +import { NextMiddleware } from "next-api-middleware"; + +export const withPagination: NextMiddleware = async (req, res, next) => { + const { page } = req.query; + const pageNumber = parseInt(page as string); + const skip = pageNumber * 10; + req.pagination = { + take: 10, + skip: skip || 0, + }; + await next(); +}; diff --git a/lib/validations/user.ts b/lib/validations/user.ts index dcaafdf8d2..15a66ed371 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -153,6 +153,7 @@ export const schemaUserReadPublic = User.pick({ createdDate: true, verified: true, invitedTo: true, + role: true, }); export const schemaUsersReadPublic = z.array(schemaUserReadPublic); diff --git a/next.config.js b/next.config.js index 22ff466595..344d6fdef8 100644 --- a/next.config.js +++ b/next.config.js @@ -10,6 +10,7 @@ const withTM = require("next-transpile-modules")([ "@calcom/ui", "@calcom/emails", "@calcom/embed-core", + "@calcom/dayjs", "@calcom/embed-snippet", ]); diff --git a/pages/api/availability/_get.ts b/pages/api/availability/_get.ts index 21450f005e..c3edc816c4 100644 --- a/pages/api/availability/_get.ts +++ b/pages/api/availability/_get.ts @@ -1,3 +1,4 @@ +import { HttpError } from "@/../../packages/lib/http-error"; import type { NextApiRequest } from "next"; import { z } from "zod"; @@ -8,22 +9,42 @@ import { stringOrNumber } from "@calcom/prisma/zod-utils"; const availabilitySchema = z .object({ userId: stringOrNumber.optional(), + teamId: stringOrNumber.optional(), username: z.string().optional(), dateFrom: z.string(), dateTo: z.string(), eventTypeId: stringOrNumber.optional(), }) - .refine((data) => !!data.username || !!data.userId, "Either username or userId should be filled in."); + .refine( + (data) => !!data.username || !!data.userId || !!data.teamId, + "Either username or userId or teamId should be filled in." + ); async function handler(req: NextApiRequest) { - const { username, userId, eventTypeId, dateTo, dateFrom } = availabilitySchema.parse(req.query); - return getUserAvailability({ - username, - dateFrom, - dateTo, - eventTypeId, - userId, - }); + const { prisma, isAdmin } = req; + const { username, userId, eventTypeId, dateTo, dateFrom, teamId } = availabilitySchema.parse(req.query); + if (!teamId) + return getUserAvailability({ + username, + dateFrom, + dateTo, + eventTypeId, + userId, + }); + const team = await prisma.team.findUnique({ where: { id: teamId }, select: { members: true } }); + if (!team) throw new HttpError({ statusCode: 404, message: "teamId not found" }); + if (!team.members) throw new HttpError({ statusCode: 404, message: "teamId not found" }); + if (!isAdmin) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + return team.members.map( + async (user) => + await getUserAvailability({ + username, + dateFrom, + dateTo, + eventTypeId, + userId: user.userId, + }) + ); } export default defaultResponder(handler); diff --git a/pages/api/users/_get.ts b/pages/api/users/_get.ts index 67bb53e2d1..90a03e11d0 100644 --- a/pages/api/users/_get.ts +++ b/pages/api/users/_get.ts @@ -2,6 +2,7 @@ import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; +import { withMiddleware } from "@lib/helpers/withMiddleware"; import { schemaUsersReadPublic } from "@lib/validations/user"; import { Prisma } from ".prisma/client"; @@ -23,13 +24,20 @@ import { Prisma } from ".prisma/client"; * description: No users were found */ async function getHandler(req: NextApiRequest) { - const { userId, prisma, isAdmin } = req; + const { + userId, + prisma, + isAdmin, + pagination: { take, skip }, + } = req; const where: Prisma.UserWhereInput = {}; // If user is not ADMIN, return only his data. if (!isAdmin) where.id = userId; - const data = await prisma.user.findMany({ where }); + const data = await prisma.user.findMany({ where, take, skip }); + console.log(data); const users = schemaUsersReadPublic.parse(data); + console.log(users); return { users }; } -export default defaultResponder(getHandler); +export default withMiddleware("pagination")(defaultResponder(getHandler)); From 9b5c7c51209997ad39300900568055e5c6ed441a Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 5 Jul 2022 20:13:13 +0200 Subject: [PATCH 424/658] fix: remove unused import --- lib/helpers/withMiddleware.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/helpers/withMiddleware.ts b/lib/helpers/withMiddleware.ts index 9ce21233fb..6f7d7927c0 100644 --- a/lib/helpers/withMiddleware.ts +++ b/lib/helpers/withMiddleware.ts @@ -1,5 +1,4 @@ import { label } from "next-api-middleware"; -import PagesManifestPlugin from "next/dist/build/webpack/plugins/pages-manifest-plugin"; import { addRequestId } from "./addRequestid"; import { captureErrors } from "./captureErrors"; From 5dbb2066e02df2b3e4917058ae6ad118d7efb88d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo <6601142+agustif@users.noreply.github.com> Date: Tue, 5 Jul 2022 20:34:53 +0200 Subject: [PATCH 425/658] Update pages/api/availability/_get.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add initialData: {user} Co-authored-by: Omar López --- pages/api/availability/_get.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/availability/_get.ts b/pages/api/availability/_get.ts index c3edc816c4..4d6d3559b1 100644 --- a/pages/api/availability/_get.ts +++ b/pages/api/availability/_get.ts @@ -43,7 +43,7 @@ async function handler(req: NextApiRequest) { dateTo, eventTypeId, userId: user.userId, - }) + }, {initialData: { user }}) ); } From 2263e042173ed47cac05181619cd3196e513af79 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo <6601142+agustif@users.noreply.github.com> Date: Tue, 5 Jul 2022 20:35:30 +0200 Subject: [PATCH 426/658] Update pages/api/availability/_get.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit add select: availabilitUserSelect Co-authored-by: Omar López --- pages/api/availability/_get.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/availability/_get.ts b/pages/api/availability/_get.ts index 4d6d3559b1..85e198feb0 100644 --- a/pages/api/availability/_get.ts +++ b/pages/api/availability/_get.ts @@ -31,7 +31,7 @@ async function handler(req: NextApiRequest) { eventTypeId, userId, }); - const team = await prisma.team.findUnique({ where: { id: teamId }, select: { members: true } }); + const team = await prisma.team.findUnique({ where: { id: teamId }, select: { members: { select: availabilityUserSelect } } }); if (!team) throw new HttpError({ statusCode: 404, message: "teamId not found" }); if (!team.members) throw new HttpError({ statusCode: 404, message: "teamId not found" }); if (!isAdmin) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); From f1ee03f297b8e113f22459d96b09d56f432507f1 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 5 Jul 2022 20:58:26 +0200 Subject: [PATCH 427/658] fix: add teams memberships users --- pages/api/availability/_get.ts | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/pages/api/availability/_get.ts b/pages/api/availability/_get.ts index 85e198feb0..1a461c0039 100644 --- a/pages/api/availability/_get.ts +++ b/pages/api/availability/_get.ts @@ -1,11 +1,14 @@ -import { HttpError } from "@/../../packages/lib/http-error"; import type { NextApiRequest } from "next"; import { z } from "zod"; import { getUserAvailability } from "@calcom/core/getUserAvailability"; +import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; +import { availabilityUserSelect } from "@calcom/prisma"; import { stringOrNumber } from "@calcom/prisma/zod-utils"; +import { User } from ".prisma/client"; + const availabilitySchema = z .object({ userId: stringOrNumber.optional(), @@ -31,19 +34,28 @@ async function handler(req: NextApiRequest) { eventTypeId, userId, }); - const team = await prisma.team.findUnique({ where: { id: teamId }, select: { members: { select: availabilityUserSelect } } }); + const team = await prisma.team.findUnique({ + where: { id: teamId }, + select: { members: true }, + }); if (!team) throw new HttpError({ statusCode: 404, message: "teamId not found" }); if (!team.members) throw new HttpError({ statusCode: 404, message: "teamId not found" }); + const allMemberIds = team.members.map((membership) => membership.userId); + const members = await prisma.user.findMany({ + where: { id: { in: allMemberIds } }, + select: availabilityUserSelect, + }); if (!isAdmin) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); - return team.members.map( + return members.map( async (user) => - await getUserAvailability({ - username, - dateFrom, - dateTo, - eventTypeId, - userId: user.userId, - }, {initialData: { user }}) + await getUserAvailability( + { + dateFrom, + dateTo, + eventTypeId, + }, + { user } + ) ); } From a6e199be670fbc6252399133e3620996ebf3055b Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 5 Jul 2022 23:05:29 +0200 Subject: [PATCH 428/658] fix: make availability for teamId work --- pages/api/availability/_get.ts | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/pages/api/availability/_get.ts b/pages/api/availability/_get.ts index 1a461c0039..0d9afa6100 100644 --- a/pages/api/availability/_get.ts +++ b/pages/api/availability/_get.ts @@ -7,8 +7,6 @@ import { defaultResponder } from "@calcom/lib/server"; import { availabilityUserSelect } from "@calcom/prisma"; import { stringOrNumber } from "@calcom/prisma/zod-utils"; -import { User } from ".prisma/client"; - const availabilitySchema = z .object({ userId: stringOrNumber.optional(), @@ -46,17 +44,27 @@ async function handler(req: NextApiRequest) { select: availabilityUserSelect, }); if (!isAdmin) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); - return members.map( - async (user) => - await getUserAvailability( + const availabilities = members.map(async (user) => { + return { + userId: user.id, + availability: await getUserAvailability( { + userId: user.id, dateFrom, dateTo, eventTypeId, }, { user } - ) - ); + ), + }; + }); + const settled = await Promise.all(availabilities); + if (!settled) + throw new HttpError({ + statusCode: 401, + message: "We had an issue retrieving all your members availabilities", + }); + if (settled) return settled; } export default defaultResponder(handler); From 44ce77f814aab331395439f4bd7a3db9ce0ff13d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 6 Jul 2022 01:17:59 +0200 Subject: [PATCH 429/658] fix: test return booking get --- pages/api/bookings/[id].ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index f4f11b143f..6897cb0464 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -52,7 +52,7 @@ export async function bookingById( * description: Booking was not found */ case "GET": - await prisma.booking + return await prisma.booking .findUnique({ where: { id: safeQuery.data.id } }) .then((data) => schemaBookingReadPublic.parse(data)) .then((booking) => res.status(200).json({ booking })) @@ -170,4 +170,4 @@ export async function bookingById( } } -export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(bookingById)); +export default withMiddleware("HTTP_GET_DELETE_PATCH")(bookingById); From ab78c0b9ec6216d36ff9f92c559ee705d0c98e8e Mon Sep 17 00:00:00 2001 From: Leo Giovanetti Date: Wed, 6 Jul 2022 17:21:12 -0300 Subject: [PATCH 430/658] Upgrading nextjs --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c806055f00..a02580eb97 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "bcryptjs": "^2.4.3", "memory-cache": "^0.2.0", "modify-response-middleware": "^1.1.0", - "next": "^12.1.6", + "next": "^12.2.0", "next-api-middleware": "^1.0.1", "next-swagger-doc": "^0.3.4", "next-transpile-modules": "^9.0.0", From f93cb48d4d354e458f2810b8d49a5ce64d771183 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 7 Jul 2022 18:56:27 +0200 Subject: [PATCH 431/658] fix: query partial type --- lib/helpers/extendRequest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helpers/extendRequest.ts b/lib/helpers/extendRequest.ts index 8ed3ee0571..5ae84596d1 100644 --- a/lib/helpers/extendRequest.ts +++ b/lib/helpers/extendRequest.ts @@ -13,7 +13,7 @@ declare module "next" { method: string; prisma: PrismaClient; session: { user: { id: number } }; - query: { [key: string]: string | string[] }; + query: Partial<{ [key: string]: string | string[] }>; isAdmin: boolean; } } From 599dccdcce8e6e578fdc9cca38766f5bab334d23 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 8 Jul 2022 02:00:00 +0200 Subject: [PATCH 432/658] feat: add axiom --- next.config.js | 55 ++++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/next.config.js b/next.config.js index f8491c9904..8c5749db55 100644 --- a/next.config.js +++ b/next.config.js @@ -13,30 +13,33 @@ const withTM = require("next-transpile-modules")([ "@calcom/embed-core", "@calcom/embed-snippet", ]); +const { withAxiom } = require("next-axiom"); -module.exports = withTM({ - async rewrites() { - return { - afterFiles: [ - // This redirects requests recieved at / the root to the /api/ folder. - { - source: "/v:version/:rest*", - destination: "/api/v:version/:rest*", - }, - // This redirects requests to api/v*/ to /api/ passing version as a query parameter. - { - source: "/api/v:version/:rest*", - destination: "/api/:rest*?version=:version", - }, - ], - fallback: [ - // These rewrites are checked after both pages/public files - // and dynamic routes are checked - { - source: "/:path*", - destination: `/api/:path*`, - }, - ], - }; - }, -}); +module.exports = withAxiom( + withTM({ + async rewrites() { + return { + afterFiles: [ + // This redirects requests recieved at / the root to the /api/ folder. + { + source: "/v:version/:rest*", + destination: "/api/v:version/:rest*", + }, + // This redirects requests to api/v*/ to /api/ passing version as a query parameter. + { + source: "/api/v:version/:rest*", + destination: "/api/:rest*?version=:version", + }, + ], + fallback: [ + // These rewrites are checked after both pages/public files + // and dynamic routes are checked + { + source: "/:path*", + destination: `/api/:path*`, + }, + ], + }; + }, + }) +); From cef2768725d21b3362637f31791953d67ebfb5b6 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 8 Jul 2022 02:05:38 +0200 Subject: [PATCH 433/658] fix: add next-axiom to package.json --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index a02580eb97..7ab3bb2db3 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "modify-response-middleware": "^1.1.0", "next": "^12.2.0", "next-api-middleware": "^1.0.1", + "next-axiom": "^0.10.0", "next-swagger-doc": "^0.3.4", "next-transpile-modules": "^9.0.0", "next-validations": "^0.2.0", From 6b09fb24ab5d09efba0953f6458f6bc72631c2f7 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 8 Jul 2022 17:23:06 +0200 Subject: [PATCH 434/658] fix: adds returns, no breaks --- pages/api/bookings/[id].ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index 6897cb0464..f24a90bad0 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -62,7 +62,6 @@ export async function bookingById( error, }) ); - break; /** * @swagger * /bookings/{id}: @@ -110,12 +109,12 @@ export async function bookingById( res.status(400).json({ message: "Bad request", error: safeBody.error }); return; } - await prisma.booking + return await prisma.booking .update({ where: { id: safeQuery.data.id }, data: safeBody.data, }) - // .then((data) => schemaBookingReadPublic.parse(data)) + .then((data) => schemaBookingReadPublic.parse(data)) .then((booking) => res.status(200).json({ booking })) .catch((error: Error) => res.status(404).json({ @@ -123,7 +122,6 @@ export async function bookingById( error, }) ); - break; /** * @swagger * /bookings/{id}: @@ -148,7 +146,7 @@ export async function bookingById( * description: Authorization information is missing or invalid. */ case "DELETE": - await prisma.booking + return await prisma.booking .delete({ where: { id: safeQuery.data.id } }) .then(() => res.status(200).json({ @@ -161,13 +159,11 @@ export async function bookingById( error, }) ); - break; default: - res.status(405).json({ message: "Method not allowed" }); - break; + return res.status(405).json({ message: "Method not allowed" }); } } } -export default withMiddleware("HTTP_GET_DELETE_PATCH")(bookingById); +export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(bookingById)); From c28e96045c8250812eeb41da21b5e7c3fc990154 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 8 Jul 2022 17:23:06 +0200 Subject: [PATCH 435/658] fix: adds returns, no breaks --- pages/api/bookings/[id].ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index f4f11b143f..fa0b9760af 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -62,7 +62,6 @@ export async function bookingById( error, }) ); - break; /** * @swagger * /bookings/{id}: @@ -110,12 +109,12 @@ export async function bookingById( res.status(400).json({ message: "Bad request", error: safeBody.error }); return; } - await prisma.booking + return await prisma.booking .update({ where: { id: safeQuery.data.id }, data: safeBody.data, }) - // .then((data) => schemaBookingReadPublic.parse(data)) + .then((data) => schemaBookingReadPublic.parse(data)) .then((booking) => res.status(200).json({ booking })) .catch((error: Error) => res.status(404).json({ @@ -123,7 +122,6 @@ export async function bookingById( error, }) ); - break; /** * @swagger * /bookings/{id}: @@ -148,7 +146,7 @@ export async function bookingById( * description: Authorization information is missing or invalid. */ case "DELETE": - await prisma.booking + return await prisma.booking .delete({ where: { id: safeQuery.data.id } }) .then(() => res.status(200).json({ @@ -161,11 +159,9 @@ export async function bookingById( error, }) ); - break; default: - res.status(405).json({ message: "Method not allowed" }); - break; + return res.status(405).json({ message: "Method not allowed" }); } } } From 8425f8846441ee0eba13c1b4700da632171fa408 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 8 Jul 2022 17:58:18 +0200 Subject: [PATCH 436/658] fix: add calcom dayjs transpile --- next.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/next.config.js b/next.config.js index 22ff466595..00dca6e9fa 100644 --- a/next.config.js +++ b/next.config.js @@ -9,6 +9,7 @@ const withTM = require("next-transpile-modules")([ "@calcom/stripe", "@calcom/ui", "@calcom/emails", + "@calcom/dayjs", "@calcom/embed-core", "@calcom/embed-snippet", ]); From dfa4c06e54ac59243919e1a1aa1e72ba5138291b Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 8 Jul 2022 18:27:13 +0200 Subject: [PATCH 437/658] fix: remove old middlewares in bookingId --- pages/api/bookings/[id].ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index fa0b9760af..d8a951026d 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -166,4 +166,4 @@ export async function bookingById( } } -export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(bookingById)); +export default bookingById; From 54b36b9624ce4981af5fa720a2bc45b38545c06d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 8 Jul 2022 18:49:55 +0200 Subject: [PATCH 438/658] fix: bookings:id fix bad isAdmin double if adding missing return replace with || OR instead --- pages/api/bookings/[id].ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index fa0b9760af..32379cb231 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -23,10 +23,9 @@ export async function bookingById( }); if (!userWithBookings) throw new Error("User not found"); const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); - - if (!isAdmin) { - if (!userBookingIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); - } else { + if (!isAdmin || !userBookingIds.includes(safeQuery.data.id)) + res.status(401).json({ message: "Unauthorized" }); + else { switch (method) { /** * @swagger From c2816815ccc56a63e31ab259423a557b1e221645 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 8 Jul 2022 18:58:29 +0200 Subject: [PATCH 439/658] fix: add middlewares back --- pages/api/bookings/[id].ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts index 34f7f62db7..32379cb231 100644 --- a/pages/api/bookings/[id].ts +++ b/pages/api/bookings/[id].ts @@ -165,4 +165,4 @@ export async function bookingById( } } -export default bookingById; +export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(bookingById)); From 2f032cee47cd0e31584f0992fd557bcf81dfbfa9 Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 8 Jul 2022 11:21:40 -0600 Subject: [PATCH 440/658] Splits booking/[id] endpoint --- pages/api/bookings/[id].ts | 168 -------------------- pages/api/bookings/[id]/_auth-middleware.ts | 25 +++ pages/api/bookings/[id]/_delete.ts | 37 +++++ pages/api/bookings/[id]/_get.ts | 38 +++++ pages/api/bookings/[id]/_patch.ts | 56 +++++++ pages/api/bookings/[id]/index.ts | 16 ++ 6 files changed, 172 insertions(+), 168 deletions(-) delete mode 100644 pages/api/bookings/[id].ts create mode 100644 pages/api/bookings/[id]/_auth-middleware.ts create mode 100644 pages/api/bookings/[id]/_delete.ts create mode 100644 pages/api/bookings/[id]/_get.ts create mode 100644 pages/api/bookings/[id]/_patch.ts create mode 100644 pages/api/bookings/[id]/index.ts diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts deleted file mode 100644 index 32379cb231..0000000000 --- a/pages/api/bookings/[id].ts +++ /dev/null @@ -1,168 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BookingResponse } from "@lib/types"; -import { schemaBookingEditBodyParams, schemaBookingReadPublic } from "@lib/validations/booking"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -export async function bookingById( - { method, query, body, userId, prisma, isAdmin }: NextApiRequest, - res: NextApiResponse -) { - const safeQuery = schemaQueryIdParseInt.safeParse(query); - if (!safeQuery.success) { - res.status(400).json({ message: "Your query was invalid" }); - return; - } - const userWithBookings = await prisma.user.findUnique({ - where: { id: userId }, - include: { bookings: true }, - }); - if (!userWithBookings) throw new Error("User not found"); - const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); - if (!isAdmin || !userBookingIds.includes(safeQuery.data.id)) - res.status(401).json({ message: "Unauthorized" }); - else { - switch (method) { - /** - * @swagger - * /bookings/{id}: - * get: - * summary: Find a booking - * operationId: getBookingById - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the booking to get - * tags: - * - bookings - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Booking was not found - */ - case "GET": - await prisma.booking - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaBookingReadPublic.parse(data)) - .then((booking) => res.status(200).json({ booking })) - .catch((error: Error) => - res.status(404).json({ - message: `Booking with id: ${safeQuery.data.id} not found`, - error, - }) - ); - /** - * @swagger - * /bookings/{id}: - * patch: - * summary: Edit an existing booking - * operationId: editBookingById - * requestBody: - * description: Edit an existing booking related to one of your event-types - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * title: - * type: string - * example: 15min - * startTime: - * type: string - * example: 1970-01-01T17:00:00.000Z - * endTime: - * type: string - * example: 1970-01-01T17:00:00.000Z - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the booking to edit - * tags: - * - bookings - * responses: - * 201: - * description: OK, booking edited successfuly - * 400: - * description: Bad request. Booking body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - case "PATCH": - const safeBody = schemaBookingEditBodyParams.safeParse(body); - if (!safeBody.success) { - console.log(safeBody.error); - res.status(400).json({ message: "Bad request", error: safeBody.error }); - return; - } - return await prisma.booking - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((data) => schemaBookingReadPublic.parse(data)) - .then((booking) => res.status(200).json({ booking })) - .catch((error: Error) => - res.status(404).json({ - message: `Booking with id: ${safeQuery.data.id} not found`, - error, - }) - ); - /** - * @swagger - * /bookings/{id}: - * delete: - * summary: Remove an existing booking - * operationId: removeBookingById - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the booking to delete - * tags: - * - bookings - * responses: - * 201: - * description: OK, booking removed successfuly - * 400: - * description: Bad request. Booking id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - case "DELETE": - return await prisma.booking - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ - message: `Booking with id: ${safeQuery.data.id} deleted successfully`, - }) - ) - .catch((error: Error) => - res.status(404).json({ - message: `Booking with id: ${safeQuery.data.id} not found`, - error, - }) - ); - - default: - return res.status(405).json({ message: "Method not allowed" }); - } - } -} - -export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(bookingById)); diff --git a/pages/api/bookings/[id]/_auth-middleware.ts b/pages/api/bookings/[id]/_auth-middleware.ts new file mode 100644 index 0000000000..ead390f413 --- /dev/null +++ b/pages/api/bookings/[id]/_auth-middleware.ts @@ -0,0 +1,25 @@ +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +export async function authMiddleware(req: NextApiRequest) { + const { userId, prisma, isAdmin, query } = req; + const { id } = schemaQueryIdParseInt.parse(query); + const userWithBookings = await prisma.user.findUnique({ + where: { id: userId }, + include: { bookings: true }, + }); + + if (!userWithBookings) throw new HttpError({ statusCode: 404, message: "User not found" }); + + const userBookingIds = userWithBookings.bookings.map((booking) => booking.id); + + if (!isAdmin && !userBookingIds.includes(id)) { + throw new HttpError({ statusCode: 401, message: "You are not authorized" }); + } +} + +export default defaultResponder(authMiddleware); diff --git a/pages/api/bookings/[id]/_delete.ts b/pages/api/bookings/[id]/_delete.ts new file mode 100644 index 0000000000..46014f5785 --- /dev/null +++ b/pages/api/bookings/[id]/_delete.ts @@ -0,0 +1,37 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /bookings/{id}: + * delete: + * summary: Remove an existing booking + * operationId: removeBookingById + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the booking to delete + * tags: + * - bookings + * responses: + * 201: + * description: OK, booking removed successfuly + * 400: + * description: Bad request. Booking id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdParseInt.parse(query); + await prisma.booking.delete({ where: { id } }); + return { message: `Booking with id: ${id} deleted successfully` }; +} + +export default defaultResponder(deleteHandler); diff --git a/pages/api/bookings/[id]/_get.ts b/pages/api/bookings/[id]/_get.ts new file mode 100644 index 0000000000..567312261a --- /dev/null +++ b/pages/api/bookings/[id]/_get.ts @@ -0,0 +1,38 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaBookingReadPublic } from "@lib/validations/booking"; +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /bookings/{id}: + * get: + * summary: Find a booking + * operationId: getBookingById + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the booking to get + * tags: + * - bookings + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Booking was not found + */ +export async function getHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdParseInt.parse(query); + const booking = await prisma.booking.findUnique({ where: { id } }); + return { booking: schemaBookingReadPublic.parse(booking) }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/bookings/[id]/_patch.ts b/pages/api/bookings/[id]/_patch.ts new file mode 100644 index 0000000000..d2700ae229 --- /dev/null +++ b/pages/api/bookings/[id]/_patch.ts @@ -0,0 +1,56 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaBookingEditBodyParams, schemaBookingReadPublic } from "@lib/validations/booking"; +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /bookings/{id}: + * patch: + * summary: Edit an existing booking + * operationId: editBookingById + * requestBody: + * description: Edit an existing booking related to one of your event-types + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * title: + * type: string + * example: 15min + * startTime: + * type: string + * example: 1970-01-01T17:00:00.000Z + * endTime: + * type: string + * example: 1970-01-01T17:00:00.000Z + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the booking to edit + * tags: + * - bookings + * responses: + * 201: + * description: OK, booking edited successfuly + * 400: + * description: Bad request. Booking body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function patchHandler(req: NextApiRequest) { + const { prisma, query, body } = req; + const { id } = schemaQueryIdParseInt.parse(query); + const data = schemaBookingEditBodyParams.parse(body); + const booking = await prisma.booking.update({ where: { id }, data }); + return { booking: schemaBookingReadPublic.parse(booking) }; +} + +export default defaultResponder(patchHandler); diff --git a/pages/api/bookings/[id]/index.ts b/pages/api/bookings/[id]/index.ts new file mode 100644 index 0000000000..4b740bcbb5 --- /dev/null +++ b/pages/api/bookings/[id]/index.ts @@ -0,0 +1,16 @@ +import { NextApiRequest, NextApiResponse } from "next"; + +import { defaultHandler } from "@calcom/lib/server"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; + +import authMiddleware from "./_auth-middleware"; + +export default withMiddleware("HTTP_GET_DELETE_PATCH")(async (req: NextApiRequest, res: NextApiResponse) => { + await authMiddleware(req, res); + return defaultHandler({ + GET: import("./_get"), + PATCH: import("./_patch"), + DELETE: import("./_delete"), + })(req, res); +}); From 308c192912a2a774d572240ed4865bafacda9ee5 Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 8 Jul 2022 11:21:40 -0600 Subject: [PATCH 441/658] Splits booking/[id] endpoint # Conflicts: # pages/api/bookings/[id].ts --- pages/api/bookings/[id].ts | 169 -------------------- pages/api/bookings/[id]/_auth-middleware.ts | 25 +++ pages/api/bookings/[id]/_delete.ts | 37 +++++ pages/api/bookings/[id]/_get.ts | 38 +++++ pages/api/bookings/[id]/_patch.ts | 56 +++++++ pages/api/bookings/[id]/index.ts | 16 ++ 6 files changed, 172 insertions(+), 169 deletions(-) delete mode 100644 pages/api/bookings/[id].ts create mode 100644 pages/api/bookings/[id]/_auth-middleware.ts create mode 100644 pages/api/bookings/[id]/_delete.ts create mode 100644 pages/api/bookings/[id]/_get.ts create mode 100644 pages/api/bookings/[id]/_patch.ts create mode 100644 pages/api/bookings/[id]/index.ts diff --git a/pages/api/bookings/[id].ts b/pages/api/bookings/[id].ts deleted file mode 100644 index f24a90bad0..0000000000 --- a/pages/api/bookings/[id].ts +++ /dev/null @@ -1,169 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BookingResponse } from "@lib/types"; -import { schemaBookingEditBodyParams, schemaBookingReadPublic } from "@lib/validations/booking"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -export async function bookingById( - { method, query, body, userId, prisma, isAdmin }: NextApiRequest, - res: NextApiResponse -) { - const safeQuery = schemaQueryIdParseInt.safeParse(query); - if (!safeQuery.success) { - res.status(400).json({ message: "Your query was invalid" }); - return; - } - const userWithBookings = await prisma.user.findUnique({ - where: { id: userId }, - include: { bookings: true }, - }); - if (!userWithBookings) throw new Error("User not found"); - const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); - - if (!isAdmin) { - if (!userBookingIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); - } else { - switch (method) { - /** - * @swagger - * /bookings/{id}: - * get: - * summary: Find a booking - * operationId: getBookingById - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the booking to get - * tags: - * - bookings - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Booking was not found - */ - case "GET": - return await prisma.booking - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaBookingReadPublic.parse(data)) - .then((booking) => res.status(200).json({ booking })) - .catch((error: Error) => - res.status(404).json({ - message: `Booking with id: ${safeQuery.data.id} not found`, - error, - }) - ); - /** - * @swagger - * /bookings/{id}: - * patch: - * summary: Edit an existing booking - * operationId: editBookingById - * requestBody: - * description: Edit an existing booking related to one of your event-types - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * title: - * type: string - * example: 15min - * startTime: - * type: string - * example: 1970-01-01T17:00:00.000Z - * endTime: - * type: string - * example: 1970-01-01T17:00:00.000Z - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the booking to edit - * tags: - * - bookings - * responses: - * 201: - * description: OK, booking edited successfuly - * 400: - * description: Bad request. Booking body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - case "PATCH": - const safeBody = schemaBookingEditBodyParams.safeParse(body); - if (!safeBody.success) { - console.log(safeBody.error); - res.status(400).json({ message: "Bad request", error: safeBody.error }); - return; - } - return await prisma.booking - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((data) => schemaBookingReadPublic.parse(data)) - .then((booking) => res.status(200).json({ booking })) - .catch((error: Error) => - res.status(404).json({ - message: `Booking with id: ${safeQuery.data.id} not found`, - error, - }) - ); - /** - * @swagger - * /bookings/{id}: - * delete: - * summary: Remove an existing booking - * operationId: removeBookingById - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the booking to delete - * tags: - * - bookings - * responses: - * 201: - * description: OK, booking removed successfuly - * 400: - * description: Bad request. Booking id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - case "DELETE": - return await prisma.booking - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ - message: `Booking with id: ${safeQuery.data.id} deleted successfully`, - }) - ) - .catch((error: Error) => - res.status(404).json({ - message: `Booking with id: ${safeQuery.data.id} not found`, - error, - }) - ); - - default: - return res.status(405).json({ message: "Method not allowed" }); - } - } -} - -export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(bookingById)); diff --git a/pages/api/bookings/[id]/_auth-middleware.ts b/pages/api/bookings/[id]/_auth-middleware.ts new file mode 100644 index 0000000000..ead390f413 --- /dev/null +++ b/pages/api/bookings/[id]/_auth-middleware.ts @@ -0,0 +1,25 @@ +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +export async function authMiddleware(req: NextApiRequest) { + const { userId, prisma, isAdmin, query } = req; + const { id } = schemaQueryIdParseInt.parse(query); + const userWithBookings = await prisma.user.findUnique({ + where: { id: userId }, + include: { bookings: true }, + }); + + if (!userWithBookings) throw new HttpError({ statusCode: 404, message: "User not found" }); + + const userBookingIds = userWithBookings.bookings.map((booking) => booking.id); + + if (!isAdmin && !userBookingIds.includes(id)) { + throw new HttpError({ statusCode: 401, message: "You are not authorized" }); + } +} + +export default defaultResponder(authMiddleware); diff --git a/pages/api/bookings/[id]/_delete.ts b/pages/api/bookings/[id]/_delete.ts new file mode 100644 index 0000000000..46014f5785 --- /dev/null +++ b/pages/api/bookings/[id]/_delete.ts @@ -0,0 +1,37 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /bookings/{id}: + * delete: + * summary: Remove an existing booking + * operationId: removeBookingById + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the booking to delete + * tags: + * - bookings + * responses: + * 201: + * description: OK, booking removed successfuly + * 400: + * description: Bad request. Booking id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdParseInt.parse(query); + await prisma.booking.delete({ where: { id } }); + return { message: `Booking with id: ${id} deleted successfully` }; +} + +export default defaultResponder(deleteHandler); diff --git a/pages/api/bookings/[id]/_get.ts b/pages/api/bookings/[id]/_get.ts new file mode 100644 index 0000000000..567312261a --- /dev/null +++ b/pages/api/bookings/[id]/_get.ts @@ -0,0 +1,38 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaBookingReadPublic } from "@lib/validations/booking"; +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /bookings/{id}: + * get: + * summary: Find a booking + * operationId: getBookingById + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the booking to get + * tags: + * - bookings + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Booking was not found + */ +export async function getHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdParseInt.parse(query); + const booking = await prisma.booking.findUnique({ where: { id } }); + return { booking: schemaBookingReadPublic.parse(booking) }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/bookings/[id]/_patch.ts b/pages/api/bookings/[id]/_patch.ts new file mode 100644 index 0000000000..d2700ae229 --- /dev/null +++ b/pages/api/bookings/[id]/_patch.ts @@ -0,0 +1,56 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaBookingEditBodyParams, schemaBookingReadPublic } from "@lib/validations/booking"; +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /bookings/{id}: + * patch: + * summary: Edit an existing booking + * operationId: editBookingById + * requestBody: + * description: Edit an existing booking related to one of your event-types + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * title: + * type: string + * example: 15min + * startTime: + * type: string + * example: 1970-01-01T17:00:00.000Z + * endTime: + * type: string + * example: 1970-01-01T17:00:00.000Z + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the booking to edit + * tags: + * - bookings + * responses: + * 201: + * description: OK, booking edited successfuly + * 400: + * description: Bad request. Booking body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function patchHandler(req: NextApiRequest) { + const { prisma, query, body } = req; + const { id } = schemaQueryIdParseInt.parse(query); + const data = schemaBookingEditBodyParams.parse(body); + const booking = await prisma.booking.update({ where: { id }, data }); + return { booking: schemaBookingReadPublic.parse(booking) }; +} + +export default defaultResponder(patchHandler); diff --git a/pages/api/bookings/[id]/index.ts b/pages/api/bookings/[id]/index.ts new file mode 100644 index 0000000000..4b740bcbb5 --- /dev/null +++ b/pages/api/bookings/[id]/index.ts @@ -0,0 +1,16 @@ +import { NextApiRequest, NextApiResponse } from "next"; + +import { defaultHandler } from "@calcom/lib/server"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; + +import authMiddleware from "./_auth-middleware"; + +export default withMiddleware("HTTP_GET_DELETE_PATCH")(async (req: NextApiRequest, res: NextApiResponse) => { + await authMiddleware(req, res); + return defaultHandler({ + GET: import("./_get"), + PATCH: import("./_patch"), + DELETE: import("./_delete"), + })(req, res); +}); From bd485b7b77898d28d840d0d07deb360c88f1b83a Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo <6601142+agustif@users.noreply.github.com> Date: Fri, 8 Jul 2022 19:33:00 +0200 Subject: [PATCH 442/658] Update pages/api/teams/_get.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix prisma import Co-authored-by: Omar López --- pages/api/teams/_get.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/teams/_get.ts b/pages/api/teams/_get.ts index 4a175c899b..e961e59bb3 100644 --- a/pages/api/teams/_get.ts +++ b/pages/api/teams/_get.ts @@ -4,7 +4,7 @@ import { defaultResponder } from "@calcom/lib/server"; import { schemaTeamReadPublic } from "@lib/validations/team"; -import { Prisma } from ".prisma/client"; +import { Prisma } from "@prisma/client"; /** * @swagger From f6faa8bc4670f7c604f7c78de6f798e1e35e22bd Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo <6601142+agustif@users.noreply.github.com> Date: Fri, 8 Jul 2022 19:33:17 +0200 Subject: [PATCH 443/658] Update pages/api/users/_get.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit remove console log Co-authored-by: Omar López --- pages/api/users/_get.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/pages/api/users/_get.ts b/pages/api/users/_get.ts index 90a03e11d0..26a6c1925b 100644 --- a/pages/api/users/_get.ts +++ b/pages/api/users/_get.ts @@ -34,7 +34,6 @@ async function getHandler(req: NextApiRequest) { // If user is not ADMIN, return only his data. if (!isAdmin) where.id = userId; const data = await prisma.user.findMany({ where, take, skip }); - console.log(data); const users = schemaUsersReadPublic.parse(data); console.log(users); return { users }; From a72fbfa0933d9f90951a66aa8d75dc636c880007 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo <6601142+agustif@users.noreply.github.com> Date: Fri, 8 Jul 2022 19:33:37 +0200 Subject: [PATCH 444/658] Update pages/api/availability/_get.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit improve error message team no members Co-authored-by: Omar López --- pages/api/availability/_get.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/availability/_get.ts b/pages/api/availability/_get.ts index 0d9afa6100..894df6b8cb 100644 --- a/pages/api/availability/_get.ts +++ b/pages/api/availability/_get.ts @@ -37,7 +37,7 @@ async function handler(req: NextApiRequest) { select: { members: true }, }); if (!team) throw new HttpError({ statusCode: 404, message: "teamId not found" }); - if (!team.members) throw new HttpError({ statusCode: 404, message: "teamId not found" }); + if (!team.members) throw new HttpError({ statusCode: 404, message: "team has no members" }); const allMemberIds = team.members.map((membership) => membership.userId); const members = await prisma.user.findMany({ where: { id: { in: allMemberIds } }, From 80e414d4f55d20c2135b4c3b8e5b7eacebd3eb79 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo <6601142+agustif@users.noreply.github.com> Date: Fri, 8 Jul 2022 19:33:50 +0200 Subject: [PATCH 445/658] Update pages/api/availability/_get.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit no if just return Co-authored-by: Omar López --- pages/api/availability/_get.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/availability/_get.ts b/pages/api/availability/_get.ts index 894df6b8cb..6b6eecfe0b 100644 --- a/pages/api/availability/_get.ts +++ b/pages/api/availability/_get.ts @@ -64,7 +64,7 @@ async function handler(req: NextApiRequest) { statusCode: 401, message: "We had an issue retrieving all your members availabilities", }); - if (settled) return settled; +return settled; } export default defaultResponder(handler); From 76d0b0c1ee5281439f828f57aace8b332e9803df Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo <6601142+agustif@users.noreply.github.com> Date: Fri, 8 Jul 2022 19:34:26 +0200 Subject: [PATCH 446/658] Update pages/api/users/_get.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit remove console log statement Co-authored-by: Omar López --- pages/api/users/_get.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/pages/api/users/_get.ts b/pages/api/users/_get.ts index 26a6c1925b..853eef938b 100644 --- a/pages/api/users/_get.ts +++ b/pages/api/users/_get.ts @@ -35,7 +35,6 @@ async function getHandler(req: NextApiRequest) { if (!isAdmin) where.id = userId; const data = await prisma.user.findMany({ where, take, skip }); const users = schemaUsersReadPublic.parse(data); - console.log(users); return { users }; } From 530752147e560bc6ca87d3dfa94b41cd546c843c Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 8 Jul 2022 20:15:25 +0200 Subject: [PATCH 447/658] fix: use zod schema for parsing page query param --- lib/helpers/withPagination.ts | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/lib/helpers/withPagination.ts b/lib/helpers/withPagination.ts index 6d76c680f1..2bcd219b33 100644 --- a/lib/helpers/withPagination.ts +++ b/lib/helpers/withPagination.ts @@ -1,11 +1,25 @@ import { NextMiddleware } from "next-api-middleware"; +import z from "zod"; -export const withPagination: NextMiddleware = async (req, res, next) => { - const { page } = req.query; - const pageNumber = parseInt(page as string); - const skip = pageNumber * 10; +const withPage = z.object({ + pageNumber: z + .string() + .min(1) + .default("1") + .transform((n) => parseInt(n)), + take: z + .string() + .min(10) + .max(100) + .default("10") + .transform((n) => parseInt(n)), +}); + +export const withPagination: NextMiddleware = async (req, _, next) => { + const { pageNumber, take } = withPage.parse(req.query); + const skip = pageNumber * take; req.pagination = { - take: 10, + take: take || 10, skip: skip || 0, }; await next(); From c8829fc08bf4da949ccf2a91ae8525bb20ca7b44 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 8 Jul 2022 20:19:51 +0200 Subject: [PATCH 448/658] fix: rename pageNumber to page --- lib/helpers/withPagination.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/helpers/withPagination.ts b/lib/helpers/withPagination.ts index 2bcd219b33..d8c68fdd3b 100644 --- a/lib/helpers/withPagination.ts +++ b/lib/helpers/withPagination.ts @@ -2,7 +2,7 @@ import { NextMiddleware } from "next-api-middleware"; import z from "zod"; const withPage = z.object({ - pageNumber: z + page: z .string() .min(1) .default("1") @@ -16,8 +16,8 @@ const withPage = z.object({ }); export const withPagination: NextMiddleware = async (req, _, next) => { - const { pageNumber, take } = withPage.parse(req.query); - const skip = pageNumber * take; + const { page, take } = withPage.parse(req.query); + const skip = page * take; req.pagination = { take: take || 10, skip: skip || 0, From 6971ba249f0b3ca3289035a5c3fe519261e2f05b Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 8 Jul 2022 21:47:31 +0200 Subject: [PATCH 449/658] fix: add optional to pagination query's --- lib/helpers/withPagination.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/helpers/withPagination.ts b/lib/helpers/withPagination.ts index d8c68fdd3b..8e2da388f5 100644 --- a/lib/helpers/withPagination.ts +++ b/lib/helpers/withPagination.ts @@ -5,22 +5,24 @@ const withPage = z.object({ page: z .string() .min(1) + .optional() .default("1") .transform((n) => parseInt(n)), take: z .string() .min(10) .max(100) + .optional() .default("10") .transform((n) => parseInt(n)), }); export const withPagination: NextMiddleware = async (req, _, next) => { const { page, take } = withPage.parse(req.query); - const skip = page * take; + const skip = page * take || 0; req.pagination = { - take: take || 10, - skip: skip || 0, + take, + skip, }; await next(); }; From 3f6e7904cbbee8182fcda06240ca52e441c02ecd Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Fri, 8 Jul 2022 21:49:14 +0200 Subject: [PATCH 450/658] fix: no http_method middleware needed as already handled by defaultHandler --- pages/api/teams/[teamId]/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/teams/[teamId]/index.ts b/pages/api/teams/[teamId]/index.ts index ed397498d4..3644bbfd61 100644 --- a/pages/api/teams/[teamId]/index.ts +++ b/pages/api/teams/[teamId]/index.ts @@ -3,7 +3,7 @@ import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { withValidQueryTeamId } from "@lib/validations/shared/queryTeamId"; -export default withMiddleware("HTTP_GET_DELETE_PATCH")( +export default withMiddleware()( withValidQueryTeamId( defaultHandler({ GET: import("./_get"), From f985bbd1ff4100e15a11a1197621f86f93c85fb7 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 12 Jul 2022 20:01:25 +0200 Subject: [PATCH 451/658] fix: move patch to no then/catch --- pages/api/teams/[teamId]/_patch.ts | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/pages/api/teams/[teamId]/_patch.ts b/pages/api/teams/[teamId]/_patch.ts index 7550cd49b5..f395ca7414 100644 --- a/pages/api/teams/[teamId]/_patch.ts +++ b/pages/api/teams/[teamId]/_patch.ts @@ -39,7 +39,7 @@ export async function patchHandler(req: NextApiRequest, res: NextApiResponse) { }); const userTeamIds = userWithMemberships.map((membership) => membership.teamId); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user - if (!isAdmin && !userTeamIds.includes(query.teamId)) + if (!isAdmin || !userTeamIds.includes(query.teamId)) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); if (!safeBody.success) { { @@ -47,16 +47,11 @@ export async function patchHandler(req: NextApiRequest, res: NextApiResponse) { return; } } - await prisma.team - .update({ where: { id: query.teamId }, data: safeBody.data }) - .then((team) => schemaTeamReadPublic.parse(team)) - .then((team) => res.status(200).json({ team })) - .catch((error: Error) => - res.status(404).json({ - message: `Team with id: ${query.teamId} not found`, - error, - }) - ); + const data = await prisma.team.update({ where: { id: query.teamId }, data: safeBody.data }); + if (!data) throw new HttpError({ statusCode: 404, message: `Team with id: ${query.teamId} not found` }); + const team = schemaTeamReadPublic.parse(data); + if (!team) throw new HttpError({ statusCode: 401, message: `Your request body wasn't valid` }); + return { team }; } export default defaultResponder(patchHandler); From f87eb7d18e19be8fe24e0e1e1e2014707c947572 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 12 Jul 2022 20:01:51 +0200 Subject: [PATCH 452/658] fix: lint add spaces --- pages/api/availability/_get.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/availability/_get.ts b/pages/api/availability/_get.ts index 6b6eecfe0b..590970fb70 100644 --- a/pages/api/availability/_get.ts +++ b/pages/api/availability/_get.ts @@ -64,7 +64,7 @@ async function handler(req: NextApiRequest) { statusCode: 401, message: "We had an issue retrieving all your members availabilities", }); -return settled; + return settled; } export default defaultResponder(handler); From 67fe26ec699dda3524b4b50cb3e6f21b24117a6f Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 12 Jul 2022 20:09:54 +0200 Subject: [PATCH 453/658] fix: lint issue import order --- pages/api/teams/_get.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pages/api/teams/_get.ts b/pages/api/teams/_get.ts index e961e59bb3..a716c2ec67 100644 --- a/pages/api/teams/_get.ts +++ b/pages/api/teams/_get.ts @@ -1,11 +1,10 @@ +import { Prisma } from "@prisma/client"; import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; import { schemaTeamReadPublic } from "@lib/validations/team"; -import { Prisma } from "@prisma/client"; - /** * @swagger * /teams: From 7a53c5bb85f17ecb0a7a53d811758a2fe409ee06 Mon Sep 17 00:00:00 2001 From: zomars Date: Tue, 12 Jul 2022 15:24:19 -0600 Subject: [PATCH 454/658] Adds missing lint scripts --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 7ab3bb2db3..1ff0ad35b9 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,9 @@ "build": "next build", "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next", "dev": "PORT=3002 next dev", - "lint-fix": "next lint --fix && prettier --write .", "lint": "next lint", + "lint:report": "eslint . --format json --output-file ../../lint-results/api.json", + "lint:fix": "next lint . --ext .ts,.js,.tsx,.jsx --fix", "start": "PORT=3002 next start", "test": "jest --detectOpenHandles --passWithNoTests", "type-check": "tsc --pretty --noEmit" From 80500ebaf09194941711b2a032db82d21015e5eb Mon Sep 17 00:00:00 2001 From: zomars Date: Wed, 13 Jul 2022 15:13:24 -0600 Subject: [PATCH 455/658] Fixes lint:fix script --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 1ff0ad35b9..0b4f085b37 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "dev": "PORT=3002 next dev", "lint": "next lint", "lint:report": "eslint . --format json --output-file ../../lint-results/api.json", - "lint:fix": "next lint . --ext .ts,.js,.tsx,.jsx --fix", + "lint:fix": "eslint . --ext .ts,.js,.tsx,.jsx --fix", "start": "PORT=3002 next start", "test": "jest --detectOpenHandles --passWithNoTests", "type-check": "tsc --pretty --noEmit" From aa12f893e813ffede140d5a719583c9cb3d5007b Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 14 Jul 2022 19:44:24 +0200 Subject: [PATCH 456/658] fix: users pagination remove min/max as its a string not a number, also add new env var to example --- .env.example | 1 + lib/helpers/withPagination.ts | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.env.example b/.env.example index 1c0f6152c1..eec3f283f7 100644 --- a/.env.example +++ b/.env.example @@ -1,2 +1,3 @@ API_KEY_PREFIX=cal_ DATABASE_URL="postgresql://postgres:@localhost:5450/calendso" +NEXT_PUBLIC_WEBAPP_URL=http://localhost:3000 \ No newline at end of file diff --git a/lib/helpers/withPagination.ts b/lib/helpers/withPagination.ts index 8e2da388f5..32ff4a7289 100644 --- a/lib/helpers/withPagination.ts +++ b/lib/helpers/withPagination.ts @@ -4,14 +4,11 @@ import z from "zod"; const withPage = z.object({ page: z .string() - .min(1) .optional() .default("1") .transform((n) => parseInt(n)), take: z .string() - .min(10) - .max(100) .optional() .default("10") .transform((n) => parseInt(n)), From aba7b1ec1c9b5122609dea916c7b114e9a3ba66f Mon Sep 17 00:00:00 2001 From: zomars Date: Thu, 21 Jul 2022 22:21:24 -0600 Subject: [PATCH 457/658] Linting --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c806ecc3e4..63abc73795 100644 --- a/README.md +++ b/README.md @@ -186,18 +186,21 @@ Add a deployment or go to an existing one. Activate API or Admin addon Provide your `DATABASE_URL` Now you can call api.cal.com?key=CALCOM_LICENSE_KEY, which will connect to your own databaseUrl. + ## How to deploy We recommend deploying API in vercel. There's some settings that you'll need to setup. -Under Vercel > Your API Deployment > Settings +Under Vercel > Your API Deployment > Settings In General > Build & Development Settings BUILD COMMAND: `yarn turbo run build --scope=@calcom/api --include-dependencies --no-deps` OUTPUT DIRECTORY: `apps/api/.next` See `scripts/vercel-deploy.sh` for more info on how the deployment is done. + ## Environment variables + Lastly API requires an env var for `DATABASE_URL` From 159792831a56fd30b1120b031a7403317c617618 Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 22 Jul 2022 20:32:10 -0600 Subject: [PATCH 458/658] New import --- lib/helpers/verifyApiKey.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index e5cf0332a3..94945c497c 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -1,6 +1,6 @@ import { NextMiddleware } from "next-api-middleware"; -import { hashAPIKey } from "@calcom/ee/lib/api/apiKeys"; +import { hashAPIKey } from "@calcom/ee/api-keys/lib/apiKeys"; import { isAdminGuard } from "@lib/utils/isAdmin"; From 60c2f736075122ec3b91a24ef612ad004d257cdb Mon Sep 17 00:00:00 2001 From: zomars Date: Thu, 28 Jul 2022 13:51:20 -0600 Subject: [PATCH 459/658] Migrates EE code --- README.md | 2 +- lib/helpers/verifyApiKey.ts | 2 +- next.config.js | 11 ++++------- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 63abc73795..7c2ce6e9ad 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ We're calling several packages from monorepo, this need to be transpiled before "@calcom/app-store", "@calcom/prisma", "@calcom/lib", - "@calcom/ee", + "@calcom/features", ``` ## API Endpoint Validation diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 94945c497c..b915df6626 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -1,6 +1,6 @@ import { NextMiddleware } from "next-api-middleware"; -import { hashAPIKey } from "@calcom/ee/api-keys/lib/apiKeys"; +import { hashAPIKey } from "@calcom/features/ee/api-keys/lib/apiKeys"; import { isAdminGuard } from "@lib/utils/isAdmin"; diff --git a/next.config.js b/next.config.js index 683d8c516b..817b179043 100644 --- a/next.config.js +++ b/next.config.js @@ -3,17 +3,14 @@ const withTM = require("next-transpile-modules")([ "@calcom/app-store", "@calcom/core", - "@calcom/ee", - "@calcom/lib", - "@calcom/prisma", - "@calcom/stripe", - "@calcom/ui", "@calcom/dayjs", "@calcom/emails", - "@calcom/dayjs", "@calcom/embed-core", - "@calcom/dayjs", "@calcom/embed-snippet", + "@calcom/features", + "@calcom/lib", + "@calcom/prisma", + "@calcom/ui", ]); const { withAxiom } = require("next-axiom"); From 915610763e87e310893f75c70729ec655a3df5e1 Mon Sep 17 00:00:00 2001 From: zomars Date: Wed, 3 Aug 2022 11:49:45 -0600 Subject: [PATCH 460/658] Build fixes --- next.config.js | 1 + package.json | 1 + tsconfig.json | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/next.config.js b/next.config.js index 817b179043..1031c0a949 100644 --- a/next.config.js +++ b/next.config.js @@ -10,6 +10,7 @@ const withTM = require("next-transpile-modules")([ "@calcom/features", "@calcom/lib", "@calcom/prisma", + "@calcom/trpc", "@calcom/ui", ]); const { withAxiom } = require("next-axiom"); diff --git a/package.json b/package.json index 0b4f085b37..3e7c495143 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "dependencies": { "@calcom/app-store-cli": "*", "@calcom/prisma": "*", + "@calcom/trpc": "*", "@sentry/nextjs": "^6.19.7", "bcryptjs": "^2.4.3", "memory-cache": "^0.2.0", diff --git a/tsconfig.json b/tsconfig.json index 2714b86c1c..c230406ae4 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,6 +9,6 @@ "@/*": ["*"] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "../../packages/types/next-auth.d.ts"], "exclude": ["node_modules", "templates", "auth"] } From 12fe6af995a6dfdf3d550a495560a6965c9e4b41 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 4 Aug 2022 19:54:25 +0200 Subject: [PATCH 461/658] feat: adds license check --- .env.example | 5 ++++- lib/helpers/verifyApiKey.ts | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/.env.example b/.env.example index eec3f283f7..c5354bfd7d 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,6 @@ API_KEY_PREFIX=cal_ DATABASE_URL="postgresql://postgres:@localhost:5450/calendso" -NEXT_PUBLIC_WEBAPP_URL=http://localhost:3000 \ No newline at end of file +NEXT_PUBLIC_WEBAPP_URL=http://localhost:3000 + +# Get it in console.cal.com +CALCOM_LICENSE_KEY="" diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index b915df6626..408cc55356 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -1,6 +1,7 @@ import { NextMiddleware } from "next-api-middleware"; import { hashAPIKey } from "@calcom/features/ee/api-keys/lib/apiKeys"; +import checkLicense from "@calcom/features/ee/common/server/checkLicense"; import { isAdminGuard } from "@lib/utils/isAdmin"; @@ -14,6 +15,9 @@ export const dateNotInPast = function (date: Date) { // This verifies the apiKey and sets the user if it is valid. export const verifyApiKey: NextMiddleware = async (req, res, next) => { + const hasValidLicense = await checkLicense(process.env.CALCOM_LICENSE_KEY || ""); + if (!hasValidLicense) + return res.status(401).json({ error: "Invalid or missing CALCOM_LICENSE_KEY environment variable" }); const { prisma, userId, isAdmin } = req; // If the user is an admin and using a license key (from customPrisma), skip the apiKey check. if (userId === 0 && isAdmin) { From 244f64d8e7db026f613e7fd84fd2b90c258efb6d Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Thu, 4 Aug 2022 19:57:20 +0200 Subject: [PATCH 462/658] fix: remove unneeded dep from api package.json app-store-cli --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 3e7c495143..17f1cc6fba 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,6 @@ "node-mocks-http": "^1.11.0" }, "dependencies": { - "@calcom/app-store-cli": "*", "@calcom/prisma": "*", "@calcom/trpc": "*", "@sentry/nextjs": "^6.19.7", From fc87557902a85bb7b0ec6f15efa19af12685ff0c Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 5 Aug 2022 15:08:36 -0600 Subject: [PATCH 463/658] Fixes callbackUrl --- auth/signup.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/auth/signup.tsx b/auth/signup.tsx index 8dc735ddab..6a04c71ecc 100644 --- a/auth/signup.tsx +++ b/auth/signup.tsx @@ -9,7 +9,7 @@ import Button from "@calcom/ui/Button"; import { EmailField, PasswordField, TextField } from "@calcom/ui/form/fields"; import { HeadSeo } from "@calcom/web/components/seo/head-seo"; import { asStringOrNull } from "@calcom/web/lib/asStringOrNull"; -import { WEBSITE_URL, WEBAPP_URL } from "@calcom/web/lib/config/constants"; +import { WEBAPP_URL } from "@calcom/web/lib/config/constants"; import prisma from "@calcom/web/lib/prisma"; import { isSAMLLoginEnabled } from "@calcom/web/lib/saml"; import { IS_GOOGLE_LOGIN_ENABLED } from "@calcom/web/server/lib/constants"; @@ -53,7 +53,7 @@ export default function Signup() { .then( async () => await signIn("Cal.com", { - callbackUrl: (`${WEBSITE_URL}/${router.query.callbackUrl}` || "") as string, + callbackUrl: (`${WEBAPP_URL}/${router.query.callbackUrl}` || "") as string, }) ) .catch((err) => { From 87d8417dd9d84d98e4d8bbf72657a2c70073d84e Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 9 Aug 2022 19:17:42 +0200 Subject: [PATCH 464/658] feat: add license and readme about copyright --- LICENSE | 42 ++++++++++++++++++++++++++++++++++++++++++ README.md | 17 ++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..fa89efec90 --- /dev/null +++ b/LICENSE @@ -0,0 +1,42 @@ +The Cal.com Enterprise Edition (EE) license (the “EE License”) +Copyright (c) 2020-present Cal.com, Inc + +With regard to the Cal.com Software: + +This software and associated documentation files (the "Software") may only be +used in production, if you (and any entity that you represent) have agreed to, +and are in compliance with, the Cal.com Subscription Terms available +at https://cal.com/terms (the “EE Terms”), or other agreements governing +the use of the Software, as mutually agreed by you and Cal.com, Inc ("Cal.com"), +and otherwise have a valid Cal.com Enterprise Edition subscription ("EE Subscription") +for the correct number of hosts as defined in the EE Terms ("Hosts"). Subject to the foregoing sentence, +you are free to modify this Software and publish patches to the Software. You agree +that Cal.com and/or its licensors (as applicable) retain all right, title and interest in +and to all such modifications and/or patches, and all such modifications and/or +patches may only be used, copied, modified, displayed, distributed, or otherwise +exploited with a valid EE Subscription for the correct number of hosts. +Notwithstanding the foregoing, you may copy and modify the Software for development +and testing purposes, without requiring a subscription. You agree that Cal.com and/or +its licensors (as applicable) retain all right, title and interest in and to all such +modifications. You are not granted any other rights beyond what is expressly stated herein. +Subject to the foregoing, it is forbidden to copy, merge, publish, distribute, sublicense, +and/or sell the Software. + +This EE License applies only to the part of this Software that is not distributed under +the AGPLv3 license. Any part of this Software distributed under the MIT license or which +is served client-side as an image, font, cascading stylesheet (CSS), file which produces +or is compiled, arranged, augmented, or combined into client-side JavaScript, in whole or +in part, is copyrighted under the AGPLv3 license. The full text of this EE License shall +be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +For all third party components incorporated into the Cal.com Software, those +components are licensed under the original license provided by the owner of the +applicable component. \ No newline at end of file diff --git a/README.md b/README.md index 7c2ce6e9ad..2e9d04291c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,19 @@ -# Cal.com Public API (Enterprise Only) + + + +# Cal.com Public API - Enterprise Edition + +Welcome to the Public API Enterprise Edition ("/apps/api") of the Cal.com Public API. + +The [/apps/api](https://github.com/calcom/cal.com/tree/main/apps/api) subfolder is the place for our Public API, which we serve at api.cal.com, and enterprise customers can also run [enterprise-grade](https://cal.com/enterprise) + +> _❗ WARNING: This repository is copyrighted (unlike our [main repo](https://github.com/calcom/cal.com)). You are not allowed to use this code to host your own version of app.cal.com without obtaining a proper [license](https://cal.com/pricing?infra) first❗_ This is the public REST api for cal.com. It exposes CRUD Endpoints of all our most important resources. From 8dfc62386dd65c6d0592f99dbb06aeb4591a0bd1 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 9 Aug 2022 19:39:43 +0200 Subject: [PATCH 465/658] fix: add CALCOM_LICENSE_KEY in env vars section in readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2e9d04291c..262feb851d 100644 --- a/README.md +++ b/README.md @@ -218,4 +218,4 @@ See `scripts/vercel-deploy.sh` for more info on how the deployment is done. ## Environment variables -Lastly API requires an env var for `DATABASE_URL` +Lastly API requires an env var for `DATABASE_URL` and `CALCOM_LICENSE_KEY` From 7560fdbfc576f7a72ac840f9bef2b9fb92cbe3a3 Mon Sep 17 00:00:00 2001 From: zomars Date: Tue, 9 Aug 2022 17:36:18 -0600 Subject: [PATCH 466/658] Squashed commit of the following: commit fc87557902a85bb7b0ec6f15efa19af12685ff0c Author: zomars Date: Fri Aug 5 15:08:36 2022 -0600 Fixes callbackUrl --- auth/signup.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/auth/signup.tsx b/auth/signup.tsx index 8dc735ddab..6a04c71ecc 100644 --- a/auth/signup.tsx +++ b/auth/signup.tsx @@ -9,7 +9,7 @@ import Button from "@calcom/ui/Button"; import { EmailField, PasswordField, TextField } from "@calcom/ui/form/fields"; import { HeadSeo } from "@calcom/web/components/seo/head-seo"; import { asStringOrNull } from "@calcom/web/lib/asStringOrNull"; -import { WEBSITE_URL, WEBAPP_URL } from "@calcom/web/lib/config/constants"; +import { WEBAPP_URL } from "@calcom/web/lib/config/constants"; import prisma from "@calcom/web/lib/prisma"; import { isSAMLLoginEnabled } from "@calcom/web/lib/saml"; import { IS_GOOGLE_LOGIN_ENABLED } from "@calcom/web/server/lib/constants"; @@ -53,7 +53,7 @@ export default function Signup() { .then( async () => await signIn("Cal.com", { - callbackUrl: (`${WEBSITE_URL}/${router.query.callbackUrl}` || "") as string, + callbackUrl: (`${WEBAPP_URL}/${router.query.callbackUrl}` || "") as string, }) ) .catch((err) => { From db937ce00a621e92b066a111ef9f672d638cacb4 Mon Sep 17 00:00:00 2001 From: zomars Date: Thu, 11 Aug 2022 12:47:36 -0600 Subject: [PATCH 467/658] Matches local lint with CI lint --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3e7c495143..e3a07595bb 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "build": "next build", "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf .next", "dev": "PORT=3002 next dev", - "lint": "next lint", + "lint": "eslint . --ignore-path .gitignore", "lint:report": "eslint . --format json --output-file ../../lint-results/api.json", "lint:fix": "eslint . --ext .ts,.js,.tsx,.jsx --fix", "start": "PORT=3002 next start", From 188ad55686014c13e7b2780b0f3131918369f15c Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 12 Aug 2022 12:58:32 -0600 Subject: [PATCH 468/658] Update README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 262feb851d..dd278617f0 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ And it makes it easy for anyone to integrate with Cal.com at the application pro ```sh cp apps/api/.env.example apps/api/.env - cp packages/prisma/.env.example packages/prisma/.env + cp .env.example .env ``` 1. Install packages with yarn From 1de91a5124012d62d23eaf30d95c801ee6d7117d Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 12 Aug 2022 16:37:47 -0600 Subject: [PATCH 469/658] Fixes mismatches --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index ac5d07df25..0d6430d98c 100644 --- a/package.json +++ b/package.json @@ -31,15 +31,15 @@ "bcryptjs": "^2.4.3", "memory-cache": "^0.2.0", "modify-response-middleware": "^1.1.0", - "next": "^12.2.0", + "next": "^12.2.5", "next-api-middleware": "^1.0.1", "next-axiom": "^0.10.0", "next-swagger-doc": "^0.3.4", "next-transpile-modules": "^9.0.0", "next-validations": "^0.2.0", - "typescript": "^4.6.4", + "typescript": "^4.7.4", "tzdata": "^1.0.30", "uuid": "^8.3.2", - "zod": "^3.16.0" + "zod": "^3.18.0" } } From 181921f9c73c60de20c4a3f1cde9466e075e1201 Mon Sep 17 00:00:00 2001 From: zomars Date: Wed, 17 Aug 2022 11:40:12 -0600 Subject: [PATCH 470/658] Fixes mismatches From bc8623edb8e5633e13cdb457b04f794947afac80 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 5 Sep 2022 21:01:55 +0200 Subject: [PATCH 471/658] feat: adds me endpoint that returns session info --- pages/api/me.ts | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 pages/api/me.ts diff --git a/pages/api/me.ts b/pages/api/me.ts new file mode 100644 index 0000000000..c66f6919ec --- /dev/null +++ b/pages/api/me.ts @@ -0,0 +1,21 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import { ensureSession } from "@calcom/lib/auth"; +import { defaultHandler, defaultResponder } from "@calcom/lib/server"; + +import { User } from ".prisma/client"; + +async function handler( + req: NextApiRequest, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _res: NextApiResponse +): Promise<{ error?: string; user?: Partial }> { + const session = await ensureSession({ req }); + /* Only admins can opt-in to V2 for now */ + if (!session) return { error: "You need to be logged in" }; + return { user: { ...session.user, email: session.user.email || "" } }; +} + +export default defaultHandler({ + GET: Promise.resolve({ default: defaultResponder(handler) }), +}); From 4d74a6c896bde9ba226b4be6849c8902c230c148 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 5 Sep 2022 21:16:45 +0200 Subject: [PATCH 472/658] feat: dont use ensureSession, but userId from req --- pages/api/me.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pages/api/me.ts b/pages/api/me.ts index c66f6919ec..e6b1130b63 100644 --- a/pages/api/me.ts +++ b/pages/api/me.ts @@ -1,6 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import { ensureSession } from "@calcom/lib/auth"; import { defaultHandler, defaultResponder } from "@calcom/lib/server"; import { User } from ".prisma/client"; @@ -10,10 +9,10 @@ async function handler( // eslint-disable-next-line @typescript-eslint/no-unused-vars _res: NextApiResponse ): Promise<{ error?: string; user?: Partial }> { - const session = await ensureSession({ req }); - /* Only admins can opt-in to V2 for now */ - if (!session) return { error: "You need to be logged in" }; - return { user: { ...session.user, email: session.user.email || "" } }; + if (!prisma) return { error: "Cant connect to database" }; + const user = await prisma.user.findUniqueOrThrow({ where: { id: req.userId } }); + if (!user) return { error: "You need to pass apiKey" }; + return { user }; } export default defaultHandler({ From 731288bcb6d298f7638be46b1a8be967206e55ba Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Mon, 5 Sep 2022 21:31:12 +0200 Subject: [PATCH 473/658] fix: use middleware, refactor into _get --- pages/api/me.ts | 20 -------------------- pages/api/me/_get.ts | 21 +++++++++++++++++++++ pages/api/me/index.ts | 9 +++++++++ 3 files changed, 30 insertions(+), 20 deletions(-) delete mode 100644 pages/api/me.ts create mode 100644 pages/api/me/_get.ts create mode 100644 pages/api/me/index.ts diff --git a/pages/api/me.ts b/pages/api/me.ts deleted file mode 100644 index e6b1130b63..0000000000 --- a/pages/api/me.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import { defaultHandler, defaultResponder } from "@calcom/lib/server"; - -import { User } from ".prisma/client"; - -async function handler( - req: NextApiRequest, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - _res: NextApiResponse -): Promise<{ error?: string; user?: Partial }> { - if (!prisma) return { error: "Cant connect to database" }; - const user = await prisma.user.findUniqueOrThrow({ where: { id: req.userId } }); - if (!user) return { error: "You need to pass apiKey" }; - return { user }; -} - -export default defaultHandler({ - GET: Promise.resolve({ default: defaultResponder(handler) }), -}); diff --git a/pages/api/me/_get.ts b/pages/api/me/_get.ts new file mode 100644 index 0000000000..7fe25139a8 --- /dev/null +++ b/pages/api/me/_get.ts @@ -0,0 +1,21 @@ +import type { NextApiRequest } from "next"; + +import { defaultHandler, defaultResponder } from "@calcom/lib/server"; + +import { schemaUserReadPublic } from "@lib/validations/user"; + +import { User } from ".prisma/client"; + +async function handler(req: NextApiRequest): Promise<{ error?: string; user?: Partial }> { + if (!prisma) return { error: "Cant connect to database" }; + console.log(req); + if (!req.userId) return { error: "No user id found" }; + const data = await prisma.user.findUniqueOrThrow({ where: { id: req.userId } }); + if (!data) return { error: "You need to pass apiKey" }; + const user = schemaUserReadPublic.parse(data); + return { user }; +} + +export default defaultHandler({ + GET: Promise.resolve({ default: defaultResponder(handler) }), +}); diff --git a/pages/api/me/index.ts b/pages/api/me/index.ts new file mode 100644 index 0000000000..fe6357f6bc --- /dev/null +++ b/pages/api/me/index.ts @@ -0,0 +1,9 @@ +import { defaultHandler } from "@calcom/lib/server"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; + +export default withMiddleware("HTTP_GET")( + defaultHandler({ + GET: import("./_get"), + }) +); From 3caee6c697b1a49a46abf6ecc302c1452bd70ff4 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 6 Sep 2022 19:04:16 +0200 Subject: [PATCH 474/658] fix: removes daily-event-reference endpoints and types --- lib/types.ts | 17 +-- lib/utils/sendPayload.ts | 1 + lib/validations/event-reference.ts | 38 ------- lib/validations/event-type.ts | 3 +- lib/validations/user.ts | 2 - pages/api/event-references/[id].ts | 164 ---------------------------- pages/api/event-references/index.ts | 84 -------------- 7 files changed, 7 insertions(+), 302 deletions(-) delete mode 100644 lib/validations/event-reference.ts delete mode 100644 pages/api/event-references/[id].ts delete mode 100644 pages/api/event-references/index.ts diff --git a/lib/types.ts b/lib/types.ts index b5d9ac4663..db806fa3aa 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -1,4 +1,4 @@ -import { AppStoreLocationType, DefaultLocationType } from "@calcom/app-store/locations"; +import { AppStoreLocationType, DefaultEventLocationType } from "@calcom/app-store/locations"; import { User, Team, @@ -9,7 +9,6 @@ import { Availability, BookingReference, Booking, - DailyEventReference, Webhook, DestinationCalendar, Membership, @@ -93,14 +92,6 @@ export type CredentialsResponse = BaseResponse & { credentials?: Partial[]; }; -// DailyEventReference -export type DailyEventReferenceResponse = BaseResponse & { - daily_event_reference?: Partial; -}; -export type DailyEventReferencesResponse = BaseResponse & { - daily_event_references?: Partial[]; -}; - // DestinationCalendar export type DestinationCalendarResponse = BaseResponse & { destination_calendar?: Partial; @@ -148,9 +139,11 @@ interface EventTypeExtended extends Omit -) { - const safeQuery = schemaQueryIdParseInt.safeParse(query); - const safeBody = schemaDailyEventReferenceEditBodyParams.safeParse(body); - if (!safeQuery.success) { - res.status(400).json({ message: "Your query was invalid" }); - return; - } - const userBookings = await prisma.booking.findMany({ where: { userId } }); - const userBookingIds: number[] = userBookings.map((booking) => booking.id); - const userBookingDailyEventReferences = await prisma.dailyEventReference.findMany({ - where: { bookingId: { in: userBookingIds } }, - }); - const userBookingDailyEventReferenceIds = userBookingDailyEventReferences.map( - (dailyEventReference) => dailyEventReference.id - ); - if (!userBookingDailyEventReferenceIds.includes(safeQuery.data.id)) - res.status(401).json({ message: "Unauthorized" }); - else { - switch (method) { - /** - * @swagger - * /event-references/{id}: - * get: - * summary: Find a event reference - * operationId: getEventReferenceById - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the event reference to get - * tags: - * - event-references - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: EventReference was not found - */ - case "GET": - await prisma.dailyEventReference - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaDailyEventReferenceReadPublic.parse(data)) - .then((daily_event_reference) => res.status(200).json({ daily_event_reference })) - .catch((error: Error) => - res.status(404).json({ - message: `DailyEventReference with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - - /** - * @swagger - * /event-references/{id}: - * patch: - * summary: Edit an existing event reference - * operationId: editEventReferenceById - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the event reference to edit - * tags: - * - event-references - * responses: - * 201: - * description: OK, EventReference edited successfuly - * 400: - * description: Bad request. EventReference body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - case "PATCH": - if (!safeBody.success) { - { - res.status(400).json({ message: "Invalid request body" }); - return; - } - } - await prisma.dailyEventReference - .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) - .then((data) => schemaDailyEventReferenceReadPublic.parse(data)) - .then((daily_event_reference) => res.status(200).json({ daily_event_reference })) - .catch((error: Error) => - res.status(404).json({ - message: `DailyEventReference with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - - /** - * @swagger - * /event-references/{id}: - * delete: - * summary: Remove an existing event reference - * operationId: removeEventReferenceById - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the event reference to delete - * tags: - * - event-references - * responses: - * 201: - * description: OK, EventReference removed successfuly - * 400: - * description: Bad request. EventReference id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - case "DELETE": - await prisma.dailyEventReference - .delete({ - where: { id: safeQuery.data.id }, - }) - .then(() => - res.status(200).json({ - message: `DailyEventReference with id: ${safeQuery.data.id} deleted`, - }) - ) - .catch((error: Error) => - res.status(404).json({ - message: `DailyEventReference with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } - } -} - -export default withMiddleware("HTTP_GET_DELETE_PATCH")( - withValidQueryIdTransformParseInt(dailyEventReferenceById) -); diff --git a/pages/api/event-references/index.ts b/pages/api/event-references/index.ts deleted file mode 100644 index 449737cd06..0000000000 --- a/pages/api/event-references/index.ts +++ /dev/null @@ -1,84 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { DailyEventReferenceResponse, DailyEventReferencesResponse } from "@lib/types"; -import { - schemaDailyEventReferenceCreateBodyParams, - schemaDailyEventReferenceReadPublic, -} from "@lib/validations/event-reference"; - -async function createOrlistAllDailyEventReferences( - { method, body, userId, prisma }: NextApiRequest, - res: NextApiResponse -) { - const userBookings = await prisma.booking.findMany({ where: { userId } }); - const userBookingIds = userBookings.map((booking) => booking.id); - - if (method === "GET") { - /** - * @swagger - * /event-references: - * get: - * summary: Find all event reference - * operationId: listEventReferences - * tags: - * - event-references - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No event references were found - */ - const data = await prisma.dailyEventReference.findMany({ - where: { bookingId: { in: userBookingIds } }, - }); - const daily_event_references = data.map((dailyEventReference) => - schemaDailyEventReferenceReadPublic.parse(dailyEventReference) - ); - if (daily_event_references) res.status(200).json({ daily_event_references }); - else - (error: Error) => - res.status(404).json({ - message: "No DailyEventReferences were found", - error, - }); - } else if (method === "POST") { - /** - * @swagger - * /event-references: - * post: - * summary: Creates a new event reference - * operationId: addEventReference - * tags: - * - event-references - * responses: - * 201: - * description: OK, event reference created - * 400: - * description: Bad request. DailyEventReference body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - const safe = schemaDailyEventReferenceCreateBodyParams.safeParse(body); - if (!safe.success) { - res.status(400).json({ message: "Invalid request body" }); - return; - } - - const data = await prisma.dailyEventReference.create({ data: safe.data }); - const daily_event_reference = schemaDailyEventReferenceReadPublic.parse(data); - - if (daily_event_reference) - res.status(201).json({ daily_event_reference, message: "DailyEventReference created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new event reference", - error, - }); - } else res.status(405).json({ message: `Method ${method} not allowed` }); -} - -export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllDailyEventReferences); From 80bd5068d498880cfb90e2352b59857e4a2699e7 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 6 Sep 2022 19:20:04 +0200 Subject: [PATCH 475/658] fix: don't use defaultHandler w promise in api yet, was from console --- pages/api/me/_get.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/pages/api/me/_get.ts b/pages/api/me/_get.ts index 7fe25139a8..40a518f9ae 100644 --- a/pages/api/me/_get.ts +++ b/pages/api/me/_get.ts @@ -1,6 +1,6 @@ import type { NextApiRequest } from "next"; -import { defaultHandler, defaultResponder } from "@calcom/lib/server"; +import { defaultResponder } from "@calcom/lib/server"; import { schemaUserReadPublic } from "@lib/validations/user"; @@ -16,6 +16,4 @@ async function handler(req: NextApiRequest): Promise<{ error?: string; user?: Pa return { user }; } -export default defaultHandler({ - GET: Promise.resolve({ default: defaultResponder(handler) }), -}); +export default defaultResponder(handler); From fc4d0ab3ea825097bb44629fa859001fd28bf26a Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Tue, 6 Sep 2022 19:40:23 +0200 Subject: [PATCH 476/658] fix: prisma not defined --- pages/api/me/_get.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pages/api/me/_get.ts b/pages/api/me/_get.ts index 40a518f9ae..1ae8d47d82 100644 --- a/pages/api/me/_get.ts +++ b/pages/api/me/_get.ts @@ -6,11 +6,14 @@ import { schemaUserReadPublic } from "@lib/validations/user"; import { User } from ".prisma/client"; -async function handler(req: NextApiRequest): Promise<{ error?: string; user?: Partial }> { +async function handler({ + userId, + prisma, +}: NextApiRequest): Promise<{ error?: string; user?: Partial }> { + const data = await prisma.user.findUniqueOrThrow({ where: { id: userId } }); if (!prisma) return { error: "Cant connect to database" }; - console.log(req); - if (!req.userId) return { error: "No user id found" }; - const data = await prisma.user.findUniqueOrThrow({ where: { id: req.userId } }); + + if (!userId) return { error: "No user id found" }; if (!data) return { error: "You need to pass apiKey" }; const user = schemaUserReadPublic.parse(data); return { user }; From be200cd07676dfd5663b909abae4754995477562 Mon Sep 17 00:00:00 2001 From: Agusti Fernandez Pardo Date: Wed, 7 Sep 2022 18:18:43 +0200 Subject: [PATCH 477/658] fix: userId not 0 for fixing /me endpoint --- lib/helpers/customPrisma.ts | 2 +- lib/helpers/extendRequest.ts | 1 + lib/helpers/verifyApiKey.ts | 6 +++--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/helpers/customPrisma.ts b/lib/helpers/customPrisma.ts index f2d038c5e5..f374048499 100644 --- a/lib/helpers/customPrisma.ts +++ b/lib/helpers/customPrisma.ts @@ -47,7 +47,7 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { we skip verifyApiKey logic and pass onto next middleware instead. */ req.isAdmin = true; - req.userId = 0; + req.isCustomPrisma = true; await next(); }; diff --git a/lib/helpers/extendRequest.ts b/lib/helpers/extendRequest.ts index 2924782d3e..d01cce81e2 100644 --- a/lib/helpers/extendRequest.ts +++ b/lib/helpers/extendRequest.ts @@ -15,6 +15,7 @@ declare module "next" { session: { user: { id: number } }; query: Partial<{ [key: string]: string | string[] }>; isAdmin: boolean; + isCustomPrisma: boolean; pagination: { take: number; skip: number }; } } diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 408cc55356..ee252d91fd 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -18,9 +18,9 @@ export const verifyApiKey: NextMiddleware = async (req, res, next) => { const hasValidLicense = await checkLicense(process.env.CALCOM_LICENSE_KEY || ""); if (!hasValidLicense) return res.status(401).json({ error: "Invalid or missing CALCOM_LICENSE_KEY environment variable" }); - const { prisma, userId, isAdmin } = req; + const { prisma, isCustomPrisma, isAdmin } = req; // If the user is an admin and using a license key (from customPrisma), skip the apiKey check. - if (userId === 0 && isAdmin) { + if (isCustomPrisma && isAdmin) { await next(); return; } @@ -42,6 +42,6 @@ export const verifyApiKey: NextMiddleware = async (req, res, next) => { req.userId = apiKey.userId; // save the isAdmin boolean here for later use req.isAdmin = await isAdminGuard(req); - + req.isCustomPrisma = false; await next(); }; From d14c8404e708cc966d2049ffe6bddeabf2dd51a8 Mon Sep 17 00:00:00 2001 From: Peer Richelsen Date: Sat, 24 Sep 2022 13:23:10 +0000 Subject: [PATCH 478/658] Update index.ts --- pages/api/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/index.ts b/pages/api/index.ts index 94461cedce..85f1d6be3b 100644 --- a/pages/api/index.ts +++ b/pages/api/index.ts @@ -1,5 +1,5 @@ import type { NextApiRequest, NextApiResponse } from "next"; export default async function CalcomApi(_: NextApiRequest, res: NextApiResponse) { - res.status(201).json({ message: "Welcome to Cal.com API - docs are at https://docs.cal.com/api" }); + res.status(201).json({ message: "Welcome to Cal.com API - docs are at https://developer.cal.com/api" }); } From 362d8ca7697aeb69d1b553e1eb2a80e33870013c Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung Date: Mon, 3 Oct 2022 14:26:00 -0400 Subject: [PATCH 479/658] Connect user to new event type --- pages/api/event-types/index.ts | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index b3a9d74138..fc05909e2c 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -98,12 +98,32 @@ async function createOrlistAllEventTypes( return; } if (!isAdmin) { - const data = await prisma.eventType.create({ data: { ...safe.data, userId } }); + const data = await prisma.eventType.create({ + data: { + ...safe.data, + userId, + users: { + connect: { + id: userId, + }, + }, + }, + }); const event_type = schemaEventTypeReadPublic.parse(data); if (data) res.status(201).json({ event_type, message: "EventType created successfully" }); } else { // if admin don't re-set userId from input - const data = await prisma.eventType.create({ data: { ...safe.data } }); + const data = await prisma.eventType.create({ + data: { + ...safe.data, + ...(!safe.data.userId && { userId }), + users: { + connect: { + id: safe.data.userId || userId, + }, + }, + }, + }); const event_type = schemaEventTypeReadPublic.parse(data); if (data) res.status(201).json({ event_type, message: "EventType created successfully" }); } From 1adace1c0d98b3f3c1a9f6a3132c68285893bd91 Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung Date: Wed, 5 Oct 2022 09:56:27 -0400 Subject: [PATCH 480/658] Create new availability on new schedule --- lib/validations/schedule.ts | 2 +- pages/api/schedules/index.ts | 27 ++++++++++++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/lib/validations/schedule.ts b/lib/validations/schedule.ts index 176d972da1..e477087055 100644 --- a/lib/validations/schedule.ts +++ b/lib/validations/schedule.ts @@ -5,7 +5,7 @@ import { _ScheduleModel as Schedule } from "@calcom/prisma/zod"; const schemaScheduleBaseBodyParams = Schedule.omit({ id: true }).partial(); const schemaScheduleRequiredParams = z.object({ - userId: z.number(), + userId: z.number().optional(), name: z.string(), }); diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index 81964f4030..e4e2b69105 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -1,11 +1,13 @@ import type { NextApiRequest, NextApiResponse } from "next"; +import { getAvailabilityFromSchedule, DEFAULT_SCHEDULE } from "@calcom/lib/availability"; + import { withMiddleware } from "@lib/helpers/withMiddleware"; import { ScheduleResponse, SchedulesResponse } from "@lib/types"; import { schemaScheduleBodyParams, schemaSchedulePublic } from "@lib/validations/schedule"; async function createOrlistAllSchedules( - { method, body, userId, prisma }: NextApiRequest, + { method, body, userId, isAdmin, prisma }: NextApiRequest, res: NextApiResponse ) { if (method === "GET") { @@ -25,7 +27,10 @@ async function createOrlistAllSchedules( * 404: * description: No schedules were found */ - const data = await prisma.schedule.findMany({ where: { userId } }); + if (body.userId && !isAdmin) res.status(401).json({ message: "Unauthorized" }); + const data = await prisma.schedule.findMany({ + where: { userId: body.userId && isAdmin ? body.userId : userId }, + }); const schedules = data.map((schedule) => schemaSchedulePublic.parse(schedule)); if (schedules) res.status(200).json({ schedules }); else @@ -52,11 +57,27 @@ async function createOrlistAllSchedules( * description: Authorization information is missing or invalid. */ const safe = schemaScheduleBodyParams.safeParse(body); + if (body.userId && !isAdmin) res.status(401).json({ message: "Unauthorized" }); + if (!safe.success) { res.status(400).json({ message: "Invalid request body" }); return; } - const data = await prisma.schedule.create({ data: { ...safe.data, userId } }); + const data = await prisma.schedule.create({ + data: { + ...safe.data, + userId: body.userId && isAdmin ? body.userId : userId, + availability: { + createMany: { + data: getAvailabilityFromSchedule(DEFAULT_SCHEDULE).map((schedule) => ({ + days: schedule.days, + startTime: schedule.startTime, + endTime: schedule.endTime, + })), + }, + }, + }, + }); const schedule = schemaSchedulePublic.parse(data); if (schedule) res.status(201).json({ schedule, message: "Schedule created successfully" }); From 95fc04a45316ce09161d925cde0231e4867e5a12 Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung Date: Wed, 5 Oct 2022 10:05:04 -0400 Subject: [PATCH 481/658] Add check for userId and admin to top --- pages/api/schedules/index.ts | 151 ++++++++++++++++++----------------- 1 file changed, 77 insertions(+), 74 deletions(-) diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index e4e2b69105..8a23a6c121 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -10,84 +10,87 @@ async function createOrlistAllSchedules( { method, body, userId, isAdmin, prisma }: NextApiRequest, res: NextApiResponse ) { - if (method === "GET") { - /** - * @swagger - * /schedules: - * get: - * operationId: listSchedules - * summary: Find all schedules - * tags: - * - schedules - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No schedules were found - */ - if (body.userId && !isAdmin) res.status(401).json({ message: "Unauthorized" }); - const data = await prisma.schedule.findMany({ - where: { userId: body.userId && isAdmin ? body.userId : userId }, - }); - const schedules = data.map((schedule) => schemaSchedulePublic.parse(schedule)); - if (schedules) res.status(200).json({ schedules }); - else - (error: Error) => - res.status(404).json({ - message: "No Schedules were found", - error, - }); - } else if (method === "POST") { - /** - * @swagger - * /schedules: - * post: - * operationId: addSchedule - * summary: Creates a new schedule - * tags: - * - schedules - * responses: - * 201: - * description: OK, schedule created - * 400: - * description: Bad request. Schedule body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - const safe = schemaScheduleBodyParams.safeParse(body); - if (body.userId && !isAdmin) res.status(401).json({ message: "Unauthorized" }); + if (body.userId && !isAdmin) { + res.status(401).json({ message: "Unauthorized" }); + } else { + if (method === "GET") { + /** + * @swagger + * /schedules: + * get: + * operationId: listSchedules + * summary: Find all schedules + * tags: + * - schedules + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No schedules were found + */ + const data = await prisma.schedule.findMany({ + where: { userId: body.userId && isAdmin ? body.userId : userId }, + }); + const schedules = data.map((schedule) => schemaSchedulePublic.parse(schedule)); + if (schedules) res.status(200).json({ schedules }); + else + (error: Error) => + res.status(404).json({ + message: "No Schedules were found", + error, + }); + } else if (method === "POST") { + /** + * @swagger + * /schedules: + * post: + * operationId: addSchedule + * summary: Creates a new schedule + * tags: + * - schedules + * responses: + * 201: + * description: OK, schedule created + * 400: + * description: Bad request. Schedule body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safe = schemaScheduleBodyParams.safeParse(body); + if (body.userId && !isAdmin) res.status(401).json({ message: "Unauthorized" }); - if (!safe.success) { - res.status(400).json({ message: "Invalid request body" }); - return; - } - const data = await prisma.schedule.create({ - data: { - ...safe.data, - userId: body.userId && isAdmin ? body.userId : userId, - availability: { - createMany: { - data: getAvailabilityFromSchedule(DEFAULT_SCHEDULE).map((schedule) => ({ - days: schedule.days, - startTime: schedule.startTime, - endTime: schedule.endTime, - })), + if (!safe.success) { + res.status(400).json({ message: "Invalid request body" }); + return; + } + const data = await prisma.schedule.create({ + data: { + ...safe.data, + userId: body.userId && isAdmin ? body.userId : userId, + availability: { + createMany: { + data: getAvailabilityFromSchedule(DEFAULT_SCHEDULE).map((schedule) => ({ + days: schedule.days, + startTime: schedule.startTime, + endTime: schedule.endTime, + })), + }, }, }, - }, - }); - const schedule = schemaSchedulePublic.parse(data); + }); + const schedule = schemaSchedulePublic.parse(data); - if (schedule) res.status(201).json({ schedule, message: "Schedule created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new schedule", - error, - }); - } else res.status(405).json({ message: `Method ${method} not allowed` }); + if (schedule) res.status(201).json({ schedule, message: "Schedule created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new schedule", + error, + }); + } else res.status(405).json({ message: `Method ${method} not allowed` }); + } } export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllSchedules); From a5413b40abac79885f8e1ade219a29312e2df099 Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung Date: Wed, 5 Oct 2022 11:04:58 -0400 Subject: [PATCH 482/658] Add ability to get, post, and delete for other users if admin --- lib/validations/schedule.ts | 10 ++++++++-- pages/api/schedules/[id].ts | 10 +++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/lib/validations/schedule.ts b/lib/validations/schedule.ts index e477087055..4e8e983094 100644 --- a/lib/validations/schedule.ts +++ b/lib/validations/schedule.ts @@ -5,10 +5,16 @@ import { _ScheduleModel as Schedule } from "@calcom/prisma/zod"; const schemaScheduleBaseBodyParams = Schedule.omit({ id: true }).partial(); const schemaScheduleRequiredParams = z.object({ - userId: z.number().optional(), name: z.string(), }); export const schemaScheduleBodyParams = schemaScheduleBaseBodyParams.merge(schemaScheduleRequiredParams); -export const schemaSchedulePublic = Schedule.omit({}); +export const schemaSchedulePublic = z + .object({ id: z.number() }) + .merge(Schedule) + .merge( + z.object({ + availability: z.array(z.object({ id: z.number() })).optional(), + }) + ); diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index 593f9d7846..834a7138e2 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -9,16 +9,17 @@ import { } from "@lib/validations/shared/queryIdTransformParseInt"; export async function scheduleById( - { method, query, body, userId, prisma }: NextApiRequest, + { method, query, body, userId, isAdmin, prisma }: NextApiRequest, res: NextApiResponse ) { + if (body.userId && !isAdmin) res.status(401).json({ message: "Unauthorized" }); const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaScheduleBodyParams.safeParse(body); if (!safeQuery.success) { res.status(400).json({ message: "Your query was invalid" }); return; } - const userSchedules = await prisma.schedule.findMany({ where: { userId } }); + const userSchedules = await prisma.schedule.findMany({ where: { userId: body.userId || userId } }); const userScheduleIds = userSchedules.map((schedule) => schedule.id); if (!userScheduleIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); else { @@ -48,7 +49,10 @@ export async function scheduleById( */ case "GET": await prisma.schedule - .findUnique({ where: { id: safeQuery.data.id } }) + .findUnique({ + where: { id: safeQuery.data.id }, + include: { availability: { select: { id: true } } }, + }) .then((data) => schemaSchedulePublic.parse(data)) .then((schedule) => res.status(200).json({ schedule })) .catch((error: Error) => From ce8af8b6a5c0261d430d3a1d413df519248ffa54 Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung Date: Wed, 5 Oct 2022 15:59:34 -0400 Subject: [PATCH 483/658] Allow for admin to edit other user's event types --- pages/api/event-types/[id].ts | 12 +++++++++--- pages/api/event-types/index.ts | 4 +++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts index dd9ac1a4d9..bd8c823489 100644 --- a/pages/api/event-types/[id].ts +++ b/pages/api/event-types/[id].ts @@ -12,19 +12,24 @@ export async function eventTypeById( { method, query, body, userId, isAdmin, prisma }: NextApiRequest, res: NextApiResponse ) { + if (body.userId && !isAdmin) { + res.status(401).json({ message: "Unauthorized" }); + return; + } const safeQuery = schemaQueryIdParseInt.safeParse(query); if (!safeQuery.success) { res.status(400).json({ message: "Your query was invalid" }); return; } const data = await prisma.user.findUnique({ - where: { id: userId }, + where: { id: body.userId || userId }, rejectOnNotFound: true, select: { eventTypes: true }, }); const userEventTypes = data.eventTypes.map((eventType) => eventType.id); - if (!isAdmin) { - if (!userEventTypes.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); + if (!userEventTypes.includes(safeQuery.data.id)) { + res.status(401).json({ message: "Unauthorized" }); + return; } else { switch (method) { /** @@ -96,6 +101,7 @@ export async function eventTypeById( */ case "PATCH": const safeBody = schemaEventTypeEditBodyParams.safeParse(body); + if (!safeBody.success) { { res.status(400).json({ message: "Invalid request body" }); diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index fc05909e2c..c46979385d 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -44,7 +44,9 @@ async function createOrlistAllEventTypes( error, }); } else { - const data = await prisma.eventType.findMany({}); + const data = await prisma.eventType.findMany({ + where: { userId: isAdmin && body.userId ? body.userId : userId }, + }); const event_types = data.map((eventType) => schemaEventTypeReadPublic.parse(eventType)); if (event_types) res.status(200).json({ event_types }); } From 77b89fda05628bec3eaed2d0b2abc20261c0046b Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung Date: Wed, 5 Oct 2022 16:02:34 -0400 Subject: [PATCH 484/658] Add return statements --- pages/api/schedules/[id].ts | 11 ++++++++--- pages/api/schedules/index.ts | 6 +++++- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index 834a7138e2..5fab15f833 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -12,7 +12,10 @@ export async function scheduleById( { method, query, body, userId, isAdmin, prisma }: NextApiRequest, res: NextApiResponse ) { - if (body.userId && !isAdmin) res.status(401).json({ message: "Unauthorized" }); + if (body.userId && !isAdmin) { + res.status(401).json({ message: "Unauthorized" }); + return; + } const safeQuery = schemaQueryIdParseInt.safeParse(query); const safeBody = schemaScheduleBodyParams.safeParse(body); if (!safeQuery.success) { @@ -21,8 +24,10 @@ export async function scheduleById( } const userSchedules = await prisma.schedule.findMany({ where: { userId: body.userId || userId } }); const userScheduleIds = userSchedules.map((schedule) => schedule.id); - if (!userScheduleIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); - else { + if (!userScheduleIds.includes(safeQuery.data.id)) { + res.status(401).json({ message: "Unauthorized" }); + return; + } else { switch (method) { /** * @swagger diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index 8a23a6c121..0a35657d09 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -12,6 +12,7 @@ async function createOrlistAllSchedules( ) { if (body.userId && !isAdmin) { res.status(401).json({ message: "Unauthorized" }); + return; } else { if (method === "GET") { /** @@ -59,7 +60,10 @@ async function createOrlistAllSchedules( * description: Authorization information is missing or invalid. */ const safe = schemaScheduleBodyParams.safeParse(body); - if (body.userId && !isAdmin) res.status(401).json({ message: "Unauthorized" }); + if (body.userId && !isAdmin) { + res.status(401).json({ message: "Unauthorized" }); + return; + } if (!safe.success) { res.status(400).json({ message: "Invalid request body" }); From 372e1882287202156eb78287ba0fb6ea1d8dd020 Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung Date: Thu, 6 Oct 2022 09:55:34 -0400 Subject: [PATCH 485/658] Pass userId as a single value or an array --- pages/api/schedules/index.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index 0a35657d09..29b5577c51 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -32,7 +32,13 @@ async function createOrlistAllSchedules( * description: No schedules were found */ const data = await prisma.schedule.findMany({ - where: { userId: body.userId && isAdmin ? body.userId : userId }, + // where: { userId: body.userId && isAdmin ? body.userId : userId }, + where: { + ...(Array.isArray(body.userId) + ? { userId: { in: body.userId } } + : { userId: body.userId || userId }), + }, + ...(Array.isArray(body.userId) && { orderBy: { userId: "asc" } }), }); const schedules = data.map((schedule) => schemaSchedulePublic.parse(schedule)); if (schedules) res.status(200).json({ schedules }); From 4ac9c1e6dd4be13f6f35fb79e9f2d26cd29a742b Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung Date: Thu, 6 Oct 2022 10:02:35 -0400 Subject: [PATCH 486/658] Remove old comment --- pages/api/schedules/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index 29b5577c51..d6156c9c8b 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -32,7 +32,6 @@ async function createOrlistAllSchedules( * description: No schedules were found */ const data = await prisma.schedule.findMany({ - // where: { userId: body.userId && isAdmin ? body.userId : userId }, where: { ...(Array.isArray(body.userId) ? { userId: { in: body.userId } } From 34f5f5f83f0f4a66392ff17757159b4834689eb8 Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung Date: Thu, 6 Oct 2022 10:55:14 -0400 Subject: [PATCH 487/658] Pass userId as single value or array --- pages/api/event-types/index.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index c46979385d..04445a709c 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -45,8 +45,14 @@ async function createOrlistAllEventTypes( }); } else { const data = await prisma.eventType.findMany({ - where: { userId: isAdmin && body.userId ? body.userId : userId }, + where: { + ...(Array.isArray(body.userId) + ? { userId: { in: body.userId } } + : { userId: body.userId || userId }), + }, + ...(Array.isArray(body.userId) && { orderBy: { userId: "asc" } }), }); + console.log("🚀 ~ file: index.ts ~ line 50 ~ data", data); const event_types = data.map((eventType) => schemaEventTypeReadPublic.parse(eventType)); if (event_types) res.status(200).json({ event_types }); } From 48f270d032da49e39009f110fb14b5a2701607d1 Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung Date: Thu, 6 Oct 2022 10:59:46 -0400 Subject: [PATCH 488/658] Remove console log --- pages/api/event-types/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index 04445a709c..d5a203e67d 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -52,7 +52,6 @@ async function createOrlistAllEventTypes( }, ...(Array.isArray(body.userId) && { orderBy: { userId: "asc" } }), }); - console.log("🚀 ~ file: index.ts ~ line 50 ~ data", data); const event_types = data.map((eventType) => schemaEventTypeReadPublic.parse(eventType)); if (event_types) res.status(200).json({ event_types }); } From 2a7a111855411ae156a3d69b231066cc9464cfd7 Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung Date: Thu, 6 Oct 2022 14:38:17 -0400 Subject: [PATCH 489/658] Safe parse for userId --- lib/validations/schedule.ts | 9 ++++++--- pages/api/schedules/[id].ts | 14 +++++++++----- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/lib/validations/schedule.ts b/lib/validations/schedule.ts index 4e8e983094..32edcdae63 100644 --- a/lib/validations/schedule.ts +++ b/lib/validations/schedule.ts @@ -1,11 +1,12 @@ import { z } from "zod"; -import { _ScheduleModel as Schedule } from "@calcom/prisma/zod"; +import { _ScheduleModel as Schedule, _AvailabilityModel as Availability } from "@calcom/prisma/zod"; const schemaScheduleBaseBodyParams = Schedule.omit({ id: true }).partial(); const schemaScheduleRequiredParams = z.object({ - name: z.string(), + name: z.string().optional(), + userId: z.union([z.number(), z.array(z.number())]).optional(), }); export const schemaScheduleBodyParams = schemaScheduleBaseBodyParams.merge(schemaScheduleRequiredParams); @@ -15,6 +16,8 @@ export const schemaSchedulePublic = z .merge(Schedule) .merge( z.object({ - availability: z.array(z.object({ id: z.number() })).optional(), + availability: z + .array(Availability.pick({ id: true, eventTypeId: true, days: true, startTime: true, endTime: true })) + .optional(), }) ); diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index 5fab15f833..f92392fa3f 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -12,17 +12,18 @@ export async function scheduleById( { method, query, body, userId, isAdmin, prisma }: NextApiRequest, res: NextApiResponse ) { - if (body.userId && !isAdmin) { + const safeQuery = schemaQueryIdParseInt.safeParse(query); + const safeBody = schemaScheduleBodyParams.safeParse(body); + + if (safeBody.data.userId && !isAdmin) { res.status(401).json({ message: "Unauthorized" }); return; } - const safeQuery = schemaQueryIdParseInt.safeParse(query); - const safeBody = schemaScheduleBodyParams.safeParse(body); if (!safeQuery.success) { res.status(400).json({ message: "Your query was invalid" }); return; } - const userSchedules = await prisma.schedule.findMany({ where: { userId: body.userId || userId } }); + const userSchedules = await prisma.schedule.findMany({ where: { userId: safeBody.data.userId || userId } }); const userScheduleIds = userSchedules.map((schedule) => schedule.id); if (!userScheduleIds.includes(safeQuery.data.id)) { res.status(401).json({ message: "Unauthorized" }); @@ -56,7 +57,7 @@ export async function scheduleById( await prisma.schedule .findUnique({ where: { id: safeQuery.data.id }, - include: { availability: { select: { id: true } } }, + include: { availability: true }, }) .then((data) => schemaSchedulePublic.parse(data)) .then((schedule) => res.status(200).json({ schedule })) @@ -98,6 +99,9 @@ export async function scheduleById( return; } } + + delete safeBody.data.userId; + await prisma.schedule .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) .then((data) => schemaSchedulePublic.parse(data)) From 00ccb4ffd102d1e22b75ec20016ae10ef0fb148b Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung Date: Thu, 6 Oct 2022 14:41:50 -0400 Subject: [PATCH 490/658] Simplify get /schedules --- pages/api/schedules/index.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index d6156c9c8b..b486431440 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -10,7 +10,9 @@ async function createOrlistAllSchedules( { method, body, userId, isAdmin, prisma }: NextApiRequest, res: NextApiResponse ) { - if (body.userId && !isAdmin) { + const safeBody = schemaScheduleBodyParams.safeParse(body); + + if (safeBody.data.userId && !isAdmin) { res.status(401).json({ message: "Unauthorized" }); return; } else { @@ -31,11 +33,14 @@ async function createOrlistAllSchedules( * 404: * description: No schedules were found */ + + const userIds = Array.isArray(safeBody.data.userId) + ? safeBody.data.userId + : [safeBody.data.userId || userId]; + const data = await prisma.schedule.findMany({ where: { - ...(Array.isArray(body.userId) - ? { userId: { in: body.userId } } - : { userId: body.userId || userId }), + userId: { in: userIds }, }, ...(Array.isArray(body.userId) && { orderBy: { userId: "asc" } }), }); From da88beb1f5b31755bacd32a2f3cb2dbf4f443f97 Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung Date: Thu, 6 Oct 2022 15:06:07 -0400 Subject: [PATCH 491/658] Fix type errors --- lib/validations/schedule.ts | 8 ++++++++ pages/api/schedules/[id].ts | 8 ++++++-- pages/api/schedules/index.ts | 27 +++++++++++++++++++-------- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/lib/validations/schedule.ts b/lib/validations/schedule.ts index 32edcdae63..229ab5a14b 100644 --- a/lib/validations/schedule.ts +++ b/lib/validations/schedule.ts @@ -11,6 +11,14 @@ const schemaScheduleRequiredParams = z.object({ export const schemaScheduleBodyParams = schemaScheduleBaseBodyParams.merge(schemaScheduleRequiredParams); +export const schemaSingleScheduleBodyParams = schemaScheduleBaseBodyParams.merge( + z.object({ userId: z.number().optional() }) +); + +export const schemaCreateScheduleBodyParams = schemaScheduleBaseBodyParams.merge( + z.object({ userId: z.number().optional(), name: z.string() }) +); + export const schemaSchedulePublic = z .object({ id: z.number() }) .merge(Schedule) diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index f92392fa3f..adc26e7b6d 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from "next"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { ScheduleResponse } from "@lib/types"; -import { schemaScheduleBodyParams, schemaSchedulePublic } from "@lib/validations/schedule"; +import { schemaSingleScheduleBodyParams, schemaSchedulePublic } from "@lib/validations/schedule"; import { schemaQueryIdParseInt, withValidQueryIdTransformParseInt, @@ -13,7 +13,11 @@ export async function scheduleById( res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); - const safeBody = schemaScheduleBodyParams.safeParse(body); + const safeBody = schemaSingleScheduleBodyParams.safeParse(body); + if (!safeBody.success) { + res.status(400).json({ message: "Bad request" }); + return; + } if (safeBody.data.userId && !isAdmin) { res.status(401).json({ message: "Unauthorized" }); diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index b486431440..7380a4faa2 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -4,15 +4,26 @@ import { getAvailabilityFromSchedule, DEFAULT_SCHEDULE } from "@calcom/lib/avail import { withMiddleware } from "@lib/helpers/withMiddleware"; import { ScheduleResponse, SchedulesResponse } from "@lib/types"; -import { schemaScheduleBodyParams, schemaSchedulePublic } from "@lib/validations/schedule"; +import { + schemaScheduleBodyParams, + schemaSchedulePublic, + schemaCreateScheduleBodyParams, +} from "@lib/validations/schedule"; async function createOrlistAllSchedules( { method, body, userId, isAdmin, prisma }: NextApiRequest, res: NextApiResponse ) { - const safeBody = schemaScheduleBodyParams.safeParse(body); + const safe = schemaScheduleBodyParams.safeParse(body); - if (safeBody.data.userId && !isAdmin) { + if (!safe.success) { + res.status(400).json({ message: "Bad request" }); + return; + } + + const safeBody = safe.data; + + if (safeBody.userId && !isAdmin) { res.status(401).json({ message: "Unauthorized" }); return; } else { @@ -34,14 +45,13 @@ async function createOrlistAllSchedules( * description: No schedules were found */ - const userIds = Array.isArray(safeBody.data.userId) - ? safeBody.data.userId - : [safeBody.data.userId || userId]; + const userIds = Array.isArray(safeBody.userId) ? safeBody.userId : [safeBody.userId || userId]; const data = await prisma.schedule.findMany({ where: { userId: { in: userIds }, }, + include: { availability: true }, ...(Array.isArray(body.userId) && { orderBy: { userId: "asc" } }), }); const schedules = data.map((schedule) => schemaSchedulePublic.parse(schedule)); @@ -69,7 +79,7 @@ async function createOrlistAllSchedules( * 401: * description: Authorization information is missing or invalid. */ - const safe = schemaScheduleBodyParams.safeParse(body); + const safe = schemaCreateScheduleBodyParams.safeParse(body); if (body.userId && !isAdmin) { res.status(401).json({ message: "Unauthorized" }); return; @@ -79,10 +89,11 @@ async function createOrlistAllSchedules( res.status(400).json({ message: "Invalid request body" }); return; } + const data = await prisma.schedule.create({ data: { ...safe.data, - userId: body.userId && isAdmin ? body.userId : userId, + userId: safe.data.userId || userId, availability: { createMany: { data: getAvailabilityFromSchedule(DEFAULT_SCHEDULE).map((schedule) => ({ From 2a05f15156b66b6d7ebb86fa4ab2d6c6a18b2abf Mon Sep 17 00:00:00 2001 From: Leo Giovanetti Date: Thu, 6 Oct 2022 17:40:41 -0300 Subject: [PATCH 492/658] Recurring booking implementation (#167) * Recurring booking implementation * Tweaks to expected texts in tests * Applied feedback Co-authored-by: zomars --- jest.config.ts | 61 --------- lib/validations/booking.ts | 1 + pages/api/bookings/_get.ts | 37 ++++++ pages/api/bookings/_post.ts | 168 +++++++++++++++++++++++++ pages/api/bookings/index.ts | 174 ++------------------------ test/README.md | 12 ++ test/docker-compose.yml | 15 +++ test/jest-resolver.js | 15 +++ test/jest-setup.js | 6 + test/lib/bookings/_post.test.ts | 215 ++++++++++++++++++++++++++++++++ 10 files changed, 476 insertions(+), 228 deletions(-) delete mode 100644 jest.config.ts create mode 100644 pages/api/bookings/_get.ts create mode 100644 pages/api/bookings/_post.ts create mode 100644 test/README.md create mode 100644 test/docker-compose.yml create mode 100644 test/jest-resolver.js create mode 100644 test/jest-setup.js create mode 100644 test/lib/bookings/_post.test.ts diff --git a/jest.config.ts b/jest.config.ts deleted file mode 100644 index 7923b4cacc..0000000000 --- a/jest.config.ts +++ /dev/null @@ -1,61 +0,0 @@ -/* - * For a detailed explanation regarding each configuration property and type check, visit: - * https://jestjs.io/docs/en/configuration.html - */ - -const config = { - clearMocks: true, - coverageDirectory: "./coverage", - collectCoverage: true, - collectCoverageFrom: ["pages/api/**/*.ts"], - - // An array of regexp pattern strings used to skip coverage collection - // coveragePathIgnorePatterns: [ - // "/node_modules/" - // ], - - // Indicates which provider should be used to instrument code for coverage - // coverageProvider: "babel", - - // A list of reporter names that Jest uses when writing coverage reports - coverageReporters: ["json", "text", "lcov", "clover"], - - // An object that configures minimum threshold enforcement for coverage results - coverageThreshold: { - global: { - lines: 50, - functions: 40, - branches: 50, - statements: 50, - }, - }, - // A path to a custom dependency extractor - // dependencyExtractor: undefined, - - // Make calling deprecated APIs throw helpful error messages - errorOnDeprecated: true, - - // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. - maxWorkers: "50%", - - moduleNameMapper: { - "^@lib/(.*)$": "/lib/$1", - "^@api/(.*)$": "/pages/api/$1", - }, - - // The paths to modules that run some code to configure or set up the testing environment before each test - // setupFiles: [], - - // A list of paths to modules that run some code to configure or set up the testing framework before each test - setupFilesAfterEnv: ["/jest.setup.ts"], - - // The number of seconds after which a test is considered as slow and reported as such in the results. - slowTestThreshold: 0.1, - - // A list of paths to snapshot serializer modules Jest should use for snapshot testing - // snapshotSerializers: [], - - // The test environment that will be used for testing - testEnvironment: "node", -}; -export default config; diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index a7a8eab730..25e580059d 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -16,6 +16,7 @@ const schemaBookingCreateParams = z title: z.string(), startTime: z.date().or(z.string()), endTime: z.date().or(z.string()), + recurringCount: z.number().optional(), }) .strict(); diff --git a/pages/api/bookings/_get.ts b/pages/api/bookings/_get.ts new file mode 100644 index 0000000000..527af2718f --- /dev/null +++ b/pages/api/bookings/_get.ts @@ -0,0 +1,37 @@ +import { Prisma } from "@prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { BookingResponse, BookingsResponse } from "@lib/types"; +import { schemaBookingReadPublic } from "@lib/validations/booking"; + +/** + * @swagger + * /bookings: + * get: + * summary: Find all bookings + * operationId: listBookings + * tags: + * - bookings + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No bookings were found + */ +async function handler( + { userId, isAdmin, prisma }: NextApiRequest, + res: NextApiResponse +) { + const args: Prisma.BookingFindManyArgs = isAdmin ? {} : { where: { userId } }; + const data = await prisma.booking.findMany(args); + const bookings = data.map((booking) => schemaBookingReadPublic.parse(booking)); + if (!bookings) throw new HttpError({ statusCode: 401, message: "No Bookings were found" }); + res.status(200).json({ bookings }); +} + +export default defaultResponder(handler); diff --git a/pages/api/bookings/_post.ts b/pages/api/bookings/_post.ts new file mode 100644 index 0000000000..2509c24540 --- /dev/null +++ b/pages/api/bookings/_post.ts @@ -0,0 +1,168 @@ +import { HttpError } from "@/../../packages/lib/http-error"; +import { WebhookTriggerEvents } from "@prisma/client"; +import type { NextApiRequest, NextApiResponse } from "next"; +import { v4 as uuidv4 } from "uuid"; +import z from "zod"; + +import { BookingResponse, BookingsResponse } from "@calcom/api/lib/types"; +import sendPayload from "@calcom/api/lib/utils/sendPayload"; +import getWebhooks from "@calcom/api/lib/utils/webhookSubscriptions"; +import { schemaBookingCreateBodyParams, schemaBookingReadPublic } from "@calcom/api/lib/validations/booking"; +import { schemaEventTypeReadPublic } from "@calcom/api/lib/validations/event-type"; +import { defaultResponder } from "@calcom/lib/server"; + +/** + * @swagger + * /bookings: + * post: + * summary: Creates a new booking + * operationId: addBooking + * requestBody: + * description: Edit an existing booking related to one of your event-types + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * title: + * type: string + * example: 15min + * startTime: + * type: string + * example: 1970-01-01T17:00:00.000Z + * endTime: + * type: string + * example: 1970-01-01T17:00:00.000Z + * recurringCount: + * type: number + * example: 8 + * tags: + * - bookings + * responses: + * 201: + * description: Booking(s) created successfully. + * 400: + * description: | + * Message | Cause + * :--|:-- + * Booking body is invalid| Missing property on booking entity. + * Invalid eventTypeId| The provided eventTypeId does not exist. + * Missing recurringCount| The eventType is recurring, and no recurringCount was passed. + * Invalid recurringCount| The provided recurringCount is greater than the eventType recurring config + * 401: + * description: Authorization information is missing or invalid. + */ +async function handler( + { body, userId, isAdmin, prisma }: NextApiRequest, + res: NextApiResponse +) { + const booking = schemaBookingCreateBodyParams.parse(body); + if (!isAdmin) { + booking.userId = userId; + } + const eventTypeDb = await prisma.eventType.findUnique({ + where: { id: booking.eventTypeId }, + }); + const eventType = schemaEventTypeReadPublic.parse(eventTypeDb); + let bookings: z.infer[]; + if (!eventType) throw new HttpError({ statusCode: 400, message: "Could not create new booking" }); + if (eventType.recurringEvent) { + console.log("Event type has recurring configuration"); + if (!booking.recurringCount) throw new HttpError({ statusCode: 400, message: "Missing recurringCount" }); + if (eventType.recurringEvent.count && booking.recurringCount > eventType?.recurringEvent.count) { + throw new HttpError({ statusCode: 400, message: "Invalid recurringCount" }); + } + // Event type is recurring, ceating each booking + const recurringEventId = uuidv4(); + const allBookings = await Promise.all( + Array.from(Array(booking.recurringCount).keys()).map(async () => { + return await prisma.booking.create({ + data: { + uid: uuidv4(), + recurringEventId, + eventTypeId: booking.eventTypeId, + title: booking.title, + startTime: booking.startTime, + endTime: booking.endTime, + userId: booking.userId, + }, + }); + }) + ); + bookings = allBookings.map((book) => schemaBookingReadPublic.parse(book)); + } else { + // Event type not recurring, ceating as single one + const data = await prisma.booking.create({ + data: { + uid: uuidv4(), + eventTypeId: booking.eventTypeId, + title: booking.title, + startTime: booking.startTime, + endTime: booking.endTime, + userId: booking.userId, + }, + }); + bookings = [schemaBookingReadPublic.parse(data)]; + } + + await Promise.all( + bookings.map(async (booking) => { + const evt = { + type: eventType?.title || booking.title, + title: booking.title, + description: "", + additionalNotes: "", + customInputs: {}, + startTime: booking.startTime.toISOString(), + endTime: booking.endTime.toISOString(), + organizer: { + name: "", + email: "", + timeZone: "", + language: { + locale: "en", + }, + }, + attendees: [], + location: "", + destinationCalendar: null, + hideCalendar: false, + uid: booking.uid, + metadata: {}, + }; + console.log(`evt: ${evt}`); + + // Send Webhook call if hooked to BOOKING_CREATED + const triggerEvent = WebhookTriggerEvents.BOOKING_CREATED; + console.log(`Trigger Event: ${triggerEvent}`); + const subscriberOptions = { + userId, + eventTypeId: booking.eventTypeId as number, + triggerEvent, + }; + console.log(`subscriberOptions: ${subscriberOptions}`); + + const subscribers = await getWebhooks(subscriberOptions, prisma); + console.log(`subscribers: ${subscribers}`); + const bookingId = booking?.id; + await Promise.all( + subscribers.map((sub) => + sendPayload(triggerEvent, new Date().toISOString(), sub, { + ...evt, + bookingId, + }) + ) + ); + console.log("All promises resolved! About to send the response"); + }) + ); + + if (bookings.length > 1) { + res.status(201).json({ bookings, message: "Bookings created successfully." }); + } else { + res.status(201).json({ booking: bookings[0], message: "Booking created successfully." }); + } +} + +export default defaultResponder(handler); diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index b70e059d8b..c07846423f 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -1,170 +1,10 @@ -import { WebhookTriggerEvents } from "@prisma/client"; -import type { NextApiRequest, NextApiResponse } from "next"; -import { v4 as uuidv4 } from "uuid"; +import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { BookingResponse, BookingsResponse } from "@lib/types"; -import sendPayload from "@lib/utils/sendPayload"; -import getWebhooks from "@lib/utils/webhookSubscriptions"; -import { schemaBookingCreateBodyParams, schemaBookingReadPublic } from "@lib/validations/booking"; -import { schemaEventTypeReadPublic } from "@lib/validations/event-type"; -async function createOrlistAllBookings( - { method, body, userId, isAdmin, prisma }: NextApiRequest, - res: NextApiResponse -) { - if (method === "GET") { - /** - * @swagger - * /bookings: - * get: - * summary: Find all bookings - * operationId: listBookings - * tags: - * - bookings - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No bookings were found - */ - if (!isAdmin) { - const data = await prisma.booking.findMany({ where: { userId } }); - const bookings = data.map((booking) => schemaBookingReadPublic.parse(booking)); - if (bookings) res.status(200).json({ bookings }); - else { - (error: Error) => - res.status(404).json({ - message: "No Bookings were found", - error, - }); - } - } else { - const data = await prisma.booking.findMany(); - const bookings = data.map((booking) => schemaBookingReadPublic.parse(booking)); - if (bookings) res.status(200).json({ bookings }); - else { - (error: Error) => - res.status(404).json({ - message: "No Bookings were found", - error, - }); - } - } - } else if (method === "POST") { - /** - * @swagger - * /bookings: - * post: - * summary: Creates a new booking - * operationId: addBooking - * requestBody: - * description: Edit an existing booking related to one of your event-types - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * title: - * type: string - * example: 15min - * startTime: - * type: string - * example: 1970-01-01T17:00:00.000Z - * endTime: - * type: string - * example: 1970-01-01T17:00:00.000Z - * tags: - * - bookings - * responses: - * 201: - * description: OK, booking created - * 400: - * description: Bad request. Booking body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - const safe = schemaBookingCreateBodyParams.safeParse(body); - if (!safe.success) { - console.log(safe.error); - res.status(400).json({ message: "Bad request. Booking body is invalid." }); - return; - } - if (!isAdmin) { - safe.data.userId = userId; - } - const data = await prisma.booking.create({ data: { uid: uuidv4(), ...safe.data } }); - const booking = schemaBookingReadPublic.parse(data); - - if (booking) { - const eventType = await prisma.eventType - .findUnique({ where: { id: booking.eventTypeId as number } }) - .then((data) => schemaEventTypeReadPublic.parse(data)) - .catch((e: Error) => { - console.error(`Event type with ID: ${booking.eventTypeId} not found`, e); - }); - console.log(`eventType: ${eventType}`); - const evt = { - type: eventType?.title || booking.title, - title: booking.title, - description: "", - additionalNotes: "", - customInputs: {}, - startTime: booking.startTime.toISOString(), - endTime: booking.endTime.toISOString(), - organizer: { - name: "", - email: "", - timeZone: "", - language: { - locale: "en", - }, - }, - attendees: [], - location: "", - destinationCalendar: null, - hideCalendar: false, - uid: booking.uid, - metadata: {}, - }; - console.log(`evt: ${evt}`); - - // Send Webhook call if hooked to BOOKING_CREATED - const triggerEvent = WebhookTriggerEvents.BOOKING_CREATED; - console.log(`Trigger Event: ${triggerEvent}`); - const subscriberOptions = { - userId, - eventTypeId: booking.eventTypeId as number, - triggerEvent, - }; - console.log(`subscriberOptions: ${subscriberOptions}`); - - const subscribers = await getWebhooks(subscriberOptions, prisma); - console.log(`subscribers: ${subscribers}`); - const bookingId = booking?.id; - const promises = subscribers.map((sub) => - sendPayload(triggerEvent, new Date().toISOString(), sub, { - ...evt, - bookingId, - }).catch((e) => { - console.error(`Error executing webhook for event: ${triggerEvent}, URL: ${sub.subscriberUrl}`, e); - }) - ); - await Promise.all(promises); - console.log("All promises resolved! About to send the response"); - res.status(201).json({ booking, message: "Booking created successfully" }); - } else - (error: Error) => { - console.log(error); - res.status(400).json({ - message: "Could not create new booking", - error, - }); - }; - } else res.status(405).json({ message: `Method ${method} not allowed` }); -} - -export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllBookings); +export default withMiddleware("HTTP_GET_OR_POST")( + defaultHandler({ + GET: import("./_get"), + POST: import("./_post"), + }) +); diff --git a/test/README.md b/test/README.md new file mode 100644 index 0000000000..938d54f0be --- /dev/null +++ b/test/README.md @@ -0,0 +1,12 @@ +# Unit and Integration Tests + +Make sure you have copied .env.test.example to .env.test + +You can run all jest tests as + +`yarn test` + +You can run tests matching specific description by following command +`yarn test -t _post` + +Tip: Use `--watchAll` flag to run tests on every change diff --git a/test/docker-compose.yml b/test/docker-compose.yml new file mode 100644 index 0000000000..769adab097 --- /dev/null +++ b/test/docker-compose.yml @@ -0,0 +1,15 @@ +# Set the version of docker compose to use +version: '3.9' + +# The containers that compose the project +services: + db: + image: postgres:13 + restart: always + container_name: integration-tests-prisma + ports: + - '5433:5432' + environment: + POSTGRES_USER: prisma + POSTGRES_PASSWORD: prisma + POSTGRES_DB: tests \ No newline at end of file diff --git a/test/jest-resolver.js b/test/jest-resolver.js new file mode 100644 index 0000000000..d5fb532a29 --- /dev/null +++ b/test/jest-resolver.js @@ -0,0 +1,15 @@ +module.exports = (path, options) => { + // Call the defaultResolver, so we leverage its cache, error handling, etc. + return options.defaultResolver(path, { + ...options, + // Use packageFilter to process parsed `package.json` before the resolution (see https://www.npmjs.com/package/resolve#resolveid-opts-cb) + packageFilter: (pkg) => { + // See https://github.com/microsoft/accessibility-insights-web/blob/40416a4ae6b91baf43102f58e069eff787de4de2/src/tests/common/resolver.js + if (pkg.name === "uuid" || pkg.name === "nanoid") { + delete pkg["exports"]; + delete pkg["module"]; + } + return pkg; + }, + }); +}; diff --git a/test/jest-setup.js b/test/jest-setup.js new file mode 100644 index 0000000000..fa5c44868d --- /dev/null +++ b/test/jest-setup.js @@ -0,0 +1,6 @@ +// This is a workaround for https://github.com/jsdom/jsdom/issues/2524#issuecomment-902027138 + +// See https://github.com/microsoft/accessibility-insights-web/blob/40416a4ae6b91baf43102f58e069eff787de4de2/src/tests/unit/jest-setup.ts +const { TextEncoder, TextDecoder } = require("util"); +global.TextEncoder = TextEncoder; +global.TextDecoder = TextDecoder; diff --git a/test/lib/bookings/_post.test.ts b/test/lib/bookings/_post.test.ts new file mode 100644 index 0000000000..5fc57e5c9d --- /dev/null +++ b/test/lib/bookings/_post.test.ts @@ -0,0 +1,215 @@ +import { Booking, WebhookTriggerEvents } from "@prisma/client"; +import { Request, Response } from "express"; +import { NextApiRequest, NextApiResponse } from "next"; +import { createMocks } from "node-mocks-http"; + +import sendPayload from "@calcom/api/lib/utils/sendPayload"; +import handler from "@calcom/api/pages/api/bookings/_post"; +import dayjs from "@calcom/dayjs"; +import { buildEventType, buildWebhook, buildBooking } from "@calcom/lib/test/builder"; +import prisma from "@calcom/prisma"; + +import { prismaMock } from "../../../../../tests/config/singleton"; + +type CustomNextApiRequest = NextApiRequest & Request; +type CustomNextApiResponse = NextApiResponse & Response; +jest.mock("@calcom/api/lib/utils/sendPayload"); + +describe("POST /api/bookings", () => { + describe("Errors", () => { + test("Missing required data", async () => { + const { req, res } = createMocks({ + method: "POST", + body: {}, + }); + + await handler(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(JSON.parse(res._getData())).toEqual( + expect.objectContaining({ + message: "Booking body is invalid.", + }) + ); + }); + + test("Invalid eventTypeId", async () => { + const { req, res } = createMocks({ + method: "POST", + body: { + title: "test", + eventTypeId: 2, + startTime: dayjs().toDate(), + endTime: dayjs().add(1, "day").toDate(), + }, + prisma, + }); + + //prismaMock.eventType.findUnique.mockResolvedValue(null); + + await handler(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(JSON.parse(res._getData())).toEqual( + expect.objectContaining({ + message: "Invalid eventTypeId.", + }) + ); + }); + + test("Missing recurringCount", async () => { + const { req, res } = createMocks({ + method: "POST", + body: { + title: "test", + eventTypeId: 2, + startTime: dayjs().toDate(), + endTime: dayjs().add(1, "day").toDate(), + }, + prisma, + }); + + prismaMock.eventType.findUnique.mockResolvedValue( + buildEventType({ recurringEvent: { freq: 2, count: 12, interval: 1 } }) + ); + + await handler(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(JSON.parse(res._getData())).toEqual( + expect.objectContaining({ + message: "Missing recurringCount.", + }) + ); + }); + + test("Invalid recurringCount", async () => { + const { req, res } = createMocks({ + method: "POST", + body: { + title: "test", + eventTypeId: 2, + startTime: dayjs().toDate(), + endTime: dayjs().add(1, "day").toDate(), + recurringCount: 15, + }, + prisma, + }); + + prismaMock.eventType.findUnique.mockResolvedValue( + buildEventType({ recurringEvent: { freq: 2, count: 12, interval: 1 } }) + ); + + await handler(req, res); + + expect(res._getStatusCode()).toBe(400); + expect(JSON.parse(res._getData())).toEqual( + expect.objectContaining({ + message: "Invalid recurringCount.", + }) + ); + }); + }); + + describe("Success", () => { + describe("Regular event-type", () => { + test("Creates one single booking", async () => { + const { req, res } = createMocks({ + method: "POST", + body: { + title: "test", + eventTypeId: 2, + startTime: dayjs().toDate(), + endTime: dayjs().add(1, "day").toDate(), + }, + prisma, + }); + + prismaMock.eventType.findUnique.mockResolvedValue(buildEventType()); + + await handler(req, res); + + expect(prismaMock.booking.create).toHaveBeenCalledTimes(1); + }); + }); + + describe("Recurring event-type", () => { + test("Creates multiple bookings", async () => { + const { req, res } = createMocks({ + method: "POST", + body: { + title: "test", + eventTypeId: 2, + startTime: dayjs().toDate(), + endTime: dayjs().add(1, "day").toDate(), + recurringCount: 12, + }, + prisma, + }); + + prismaMock.eventType.findUnique.mockResolvedValue( + buildEventType({ recurringEvent: { freq: 2, count: 12, interval: 1 } }) + ); + + Array.from(Array(12).keys()).map(async () => { + prismaMock.booking.create.mockResolvedValue(buildBooking()); + }); + + prismaMock.webhook.findMany.mockResolvedValue([]); + + await handler(req, res); + const data = JSON.parse(res._getData()); + + expect(prismaMock.booking.create).toHaveBeenCalledTimes(12); + expect(res._getStatusCode()).toBe(201); + expect(data.message).toEqual("Bookings created successfully."); + expect(data.bookings.length).toEqual(12); + }); + }); + test("Notifies multiple bookings", async () => { + const { req, res } = createMocks({ + method: "POST", + body: { + title: "test", + eventTypeId: 2, + startTime: dayjs().toDate(), + endTime: dayjs().add(1, "day").toDate(), + recurringCount: 12, + }, + prisma, + }); + + prismaMock.eventType.findUnique.mockResolvedValue( + buildEventType({ recurringEvent: { freq: 2, count: 12, interval: 1 } }) + ); + + const createdAt = new Date(); + Array.from(Array(12).keys()).map(async () => { + prismaMock.booking.create.mockResolvedValue(buildBooking({ createdAt })); + }); + + const mockedWebhooks = [ + buildWebhook({ + subscriberUrl: "http://mockedURL1.com", + createdAt, + eventTypeId: 1, + secret: "secret1", + }), + buildWebhook({ + subscriberUrl: "http://mockedURL2.com", + createdAt, + eventTypeId: 2, + secret: "secret2", + }), + ]; + prismaMock.webhook.findMany.mockResolvedValue(mockedWebhooks); + + await handler(req, res); + const data = JSON.parse(res._getData()); + + expect(sendPayload).toHaveBeenCalledTimes(24); + expect(data.message).toEqual("Bookings created successfully."); + expect(data.bookings.length).toEqual(12); + }); + }); +}); From 70b9969fe3907352554a4b06e51ddf4fe7257b5a Mon Sep 17 00:00:00 2001 From: Leo Giovanetti Date: Thu, 6 Oct 2022 18:27:49 -0300 Subject: [PATCH 493/658] Fixing en error case for invalid eventTypeId --- pages/api/bookings/_post.ts | 5 +++-- test/lib/bookings/_post.test.ts | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pages/api/bookings/_post.ts b/pages/api/bookings/_post.ts index 2509c24540..da7d473d39 100644 --- a/pages/api/bookings/_post.ts +++ b/pages/api/bookings/_post.ts @@ -64,14 +64,15 @@ async function handler( const eventTypeDb = await prisma.eventType.findUnique({ where: { id: booking.eventTypeId }, }); + if (!eventTypeDb) throw new HttpError({ statusCode: 400, message: "Invalid eventTypeId." }); const eventType = schemaEventTypeReadPublic.parse(eventTypeDb); let bookings: z.infer[]; if (!eventType) throw new HttpError({ statusCode: 400, message: "Could not create new booking" }); if (eventType.recurringEvent) { console.log("Event type has recurring configuration"); - if (!booking.recurringCount) throw new HttpError({ statusCode: 400, message: "Missing recurringCount" }); + if (!booking.recurringCount) throw new HttpError({ statusCode: 400, message: "Missing recurringCount." }); if (eventType.recurringEvent.count && booking.recurringCount > eventType?.recurringEvent.count) { - throw new HttpError({ statusCode: 400, message: "Invalid recurringCount" }); + throw new HttpError({ statusCode: 400, message: "Invalid recurringCount." }); } // Event type is recurring, ceating each booking const recurringEventId = uuidv4(); diff --git a/test/lib/bookings/_post.test.ts b/test/lib/bookings/_post.test.ts index 5fc57e5c9d..1fc3d0d108 100644 --- a/test/lib/bookings/_post.test.ts +++ b/test/lib/bookings/_post.test.ts @@ -28,7 +28,8 @@ describe("POST /api/bookings", () => { expect(res._getStatusCode()).toBe(400); expect(JSON.parse(res._getData())).toEqual( expect.objectContaining({ - message: "Booking body is invalid.", + message: + "'invalid_type' in 'eventTypeId': Required; 'invalid_type' in 'title': Required; 'invalid_type' in 'startTime': Required; 'invalid_type' in 'startTime': Required; 'invalid_type' in 'endTime': Required; 'invalid_type' in 'endTime': Required", }) ); }); @@ -45,7 +46,7 @@ describe("POST /api/bookings", () => { prisma, }); - //prismaMock.eventType.findUnique.mockResolvedValue(null); + prismaMock.eventType.findUnique.mockResolvedValue(null); await handler(req, res); From 12f54773f9243a9c45a75f14571d1657bb21c2d3 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 7 Oct 2022 12:43:47 +0530 Subject: [PATCH 494/658] Adds safeParseJSON.ts file --- lib/helpers/safeParseJSON.ts | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 lib/helpers/safeParseJSON.ts diff --git a/lib/helpers/safeParseJSON.ts b/lib/helpers/safeParseJSON.ts new file mode 100644 index 0000000000..f86e8539e0 --- /dev/null +++ b/lib/helpers/safeParseJSON.ts @@ -0,0 +1,8 @@ +export default function parseJSONSafely(str: string) { + try { + return JSON.parse(str); + } catch (e) { + console.error((e as Error).message); + return {}; + } +} From 36a0ebfbadf7db444f2540f60729d9534dce2e45 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 7 Oct 2022 12:46:35 +0530 Subject: [PATCH 495/658] Adds safe json parse of the body It ensures that the body complies with the safe parsing of the JSON so that if the body sent is not a valid JSON, we convert it into an empty JSON. Would improve in handling the response of such cases as a follow up for improved UX --- pages/api/schedules/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index 7380a4faa2..e1b8d79350 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -2,6 +2,7 @@ import type { NextApiRequest, NextApiResponse } from "next"; import { getAvailabilityFromSchedule, DEFAULT_SCHEDULE } from "@calcom/lib/availability"; +import safeParseJSON from "@lib/helpers/safeParseJSON"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { ScheduleResponse, SchedulesResponse } from "@lib/types"; import { @@ -14,7 +15,7 @@ async function createOrlistAllSchedules( { method, body, userId, isAdmin, prisma }: NextApiRequest, res: NextApiResponse ) { - const safe = schemaScheduleBodyParams.safeParse(body); + const safe = schemaScheduleBodyParams.safeParse(safeParseJSON(body)); if (!safe.success) { res.status(400).json({ message: "Bad request" }); From 79fabe0333e567e36ac42edcfc04ba2131d93026 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 7 Oct 2022 13:03:09 +0530 Subject: [PATCH 496/658] Adds safeParseJSON to the body --- pages/api/schedules/[id].ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index adc26e7b6d..677c8d8975 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -1,5 +1,6 @@ import type { NextApiRequest, NextApiResponse } from "next"; +import safeParseJSON from "@lib/helpers/safeParseJSON"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { ScheduleResponse } from "@lib/types"; import { schemaSingleScheduleBodyParams, schemaSchedulePublic } from "@lib/validations/schedule"; @@ -13,7 +14,7 @@ export async function scheduleById( res: NextApiResponse ) { const safeQuery = schemaQueryIdParseInt.safeParse(query); - const safeBody = schemaSingleScheduleBodyParams.safeParse(body); + const safeBody = schemaSingleScheduleBodyParams.safeParse(safeParseJSON(body)); if (!safeBody.success) { res.status(400).json({ message: "Bad request" }); return; From 3bdebba21ecb90901839d7acceaa6f854a97670c Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 7 Oct 2022 13:12:57 +0530 Subject: [PATCH 497/658] Adds meaningful response for the API caller --- lib/helpers/safeParseJSON.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/helpers/safeParseJSON.ts b/lib/helpers/safeParseJSON.ts index f86e8539e0..3681e42273 100644 --- a/lib/helpers/safeParseJSON.ts +++ b/lib/helpers/safeParseJSON.ts @@ -3,6 +3,12 @@ export default function parseJSONSafely(str: string) { return JSON.parse(str); } catch (e) { console.error((e as Error).message); + if ((e as Error).message.includes("Unexpected token")) { + return { + success: false, + message: `Invalid JSON in the body: ${(e as Error).message}`, + }; + } return {}; } } From affba8bf66013bf2e9250f6332b9992dbdc7a873 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 7 Oct 2022 13:13:56 +0530 Subject: [PATCH 498/658] Adds meaningful response for API caller --- pages/api/schedules/index.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index e1b8d79350..3b8abc776f 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -15,7 +15,12 @@ async function createOrlistAllSchedules( { method, body, userId, isAdmin, prisma }: NextApiRequest, res: NextApiResponse ) { - const safe = schemaScheduleBodyParams.safeParse(safeParseJSON(body)); + body = safeParseJSON(body); + if (!body.success) { + res.status(400).json({ message: body.message }); + } + + const safe = schemaScheduleBodyParams.safeParse(body); if (!safe.success) { res.status(400).json({ message: "Bad request" }); From 21e081c64c1525395752d4f5d98aa47612f459e9 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 7 Oct 2022 13:15:35 +0530 Subject: [PATCH 499/658] Adds meaningful response for API caller --- pages/api/schedules/[id].ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index 677c8d8975..4ef7a85b6d 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -13,13 +13,18 @@ export async function scheduleById( { method, query, body, userId, isAdmin, prisma }: NextApiRequest, res: NextApiResponse ) { - const safeQuery = schemaQueryIdParseInt.safeParse(query); - const safeBody = schemaSingleScheduleBodyParams.safeParse(safeParseJSON(body)); + body = safeParseJSON(body); + if (!body.success) { + res.status(400).json({ message: body.message }); + } + + const safe = schemaScheduleBodyParams.safeParse(body); if (!safeBody.success) { res.status(400).json({ message: "Bad request" }); return; } - + + const safeQuery = schemaQueryIdParseInt.safeParse(query); if (safeBody.data.userId && !isAdmin) { res.status(401).json({ message: "Unauthorized" }); return; From 9a65c547dcab2dde15668a65420f658c1fb8d069 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 7 Oct 2022 13:24:55 +0530 Subject: [PATCH 500/658] Adds missing return after res --- pages/api/schedules/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index 3b8abc776f..86faad4181 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -18,6 +18,7 @@ async function createOrlistAllSchedules( body = safeParseJSON(body); if (!body.success) { res.status(400).json({ message: body.message }); + return; } const safe = schemaScheduleBodyParams.safeParse(body); From 8eaad0c1c6976f0954f0a7953799d65890e5f3f9 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 7 Oct 2022 13:34:02 +0530 Subject: [PATCH 501/658] fixed typo --- pages/api/schedules/[id].ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index 4ef7a85b6d..384e1f37c3 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -18,7 +18,7 @@ export async function scheduleById( res.status(400).json({ message: body.message }); } - const safe = schemaScheduleBodyParams.safeParse(body); + const safe = schemaSingleScheduleBodyParams.safeParse(body); if (!safeBody.success) { res.status(400).json({ message: "Bad request" }); return; From b05b6e48e785176b5da470e75b34b1be9ffffdec Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 7 Oct 2022 13:41:17 +0530 Subject: [PATCH 502/658] Fixes another typo --- pages/api/schedules/[id].ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index 384e1f37c3..31182fabda 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -18,7 +18,7 @@ export async function scheduleById( res.status(400).json({ message: body.message }); } - const safe = schemaSingleScheduleBodyParams.safeParse(body); + const safeBody = schemaSingleScheduleBodyParams.safeParse(body); if (!safeBody.success) { res.status(400).json({ message: "Bad request" }); return; From 628306793d42d885ba7a37347d6cad6a40a2633f Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 7 Oct 2022 13:47:46 +0530 Subject: [PATCH 503/658] Prettier fix :/ --- pages/api/schedules/[id].ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index 31182fabda..59c78ea12b 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -23,7 +23,7 @@ export async function scheduleById( res.status(400).json({ message: "Bad request" }); return; } - + const safeQuery = schemaQueryIdParseInt.safeParse(query); if (safeBody.data.userId && !isAdmin) { res.status(401).json({ message: "Unauthorized" }); From d68ce5e72f92daa022770d5000c22560bd88b0d3 Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com> Date: Fri, 7 Oct 2022 05:56:02 -0400 Subject: [PATCH 504/658] Admin privileges for /availabilities endpoint (#169) * List other user's availabilities * /availabilityId methods for other users * Add return statements * Accept userId single value or array * Add zod schema checks * Filter for schedules only with an availability * Adds safeParsing of JSON before safeParsing of zod * Removed console log * Adds safe JSON parsing before .safeParse * Allow API call without necessarily passing userId Allow `/availabilities` call by a regular user without having to pass their userId to make it work Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> --- lib/validations/availability.ts | 15 ++- pages/api/availabilities/[id].ts | 42 +++++- pages/api/availabilities/index.ts | 207 ++++++++++++++++++------------ 3 files changed, 172 insertions(+), 92 deletions(-) diff --git a/lib/validations/availability.ts b/lib/validations/availability.ts index a6ddf4b5c6..f55d481b2f 100644 --- a/lib/validations/availability.ts +++ b/lib/validations/availability.ts @@ -8,6 +8,7 @@ export const schemaAvailabilityBaseBodyParams = Availability.pick({ date: true, scheduleId: true, days: true, + userId: true, }).partial(); export const schemaAvailabilityReadPublic = Availability.pick({ @@ -17,9 +18,9 @@ export const schemaAvailabilityReadPublic = Availability.pick({ date: true, scheduleId: true, days: true, - userId: true, eventTypeId: true, -}); + userId: true, +}).merge(z.object({ success: z.boolean().optional() })); const schemaAvailabilityCreateParams = z .object({ @@ -45,3 +46,13 @@ export const schemaAvailabilityEditBodyParams = schemaAvailabilityBaseBodyParams export const schemaAvailabilityCreateBodyParams = schemaAvailabilityBaseBodyParams.merge( schemaAvailabilityCreateParams ); + +export const schemaAvailabilityReadBodyParams = z + .object({ + userId: z.union([z.number(), z.array(z.number())]), + }) + .partial(); + +export const schemaSingleAvailabilityReadBodyParams = z.object({ + userId: z.number(), +}); diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts index 1d4b6ed4a1..d95c10cc18 100644 --- a/pages/api/availabilities/[id].ts +++ b/pages/api/availabilities/[id].ts @@ -1,10 +1,12 @@ import type { NextApiRequest, NextApiResponse } from "next"; +import safeParseJSON from "@lib/helpers/safeParseJSON"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import type { AvailabilityResponse } from "@lib/types"; import { schemaAvailabilityEditBodyParams, schemaAvailabilityReadPublic, + schemaSingleAvailabilityReadBodyParams, } from "@lib/validations/availability"; import { schemaQueryIdParseInt, @@ -12,18 +14,47 @@ import { } from "@lib/validations/shared/queryIdTransformParseInt"; export async function availabilityById( - { method, query, body, userId, prisma }: NextApiRequest, + { method, query, body, userId, isAdmin, prisma }: NextApiRequest, res: NextApiResponse ) { + body = safeParseJSON(body); + if (body.success !== undefined && !body.success) { + res.status(400).json({ message: body.message }); + return; + } + const safeQuery = schemaQueryIdParseInt.safeParse(query); if (!safeQuery.success) { res.status(400).json({ message: "Your query is invalid", error: safeQuery.error }); return; } - const data = await prisma.availability.findMany({ where: { userId } }); - const availabiltiesIds = data.map((availability) => availability.id); - if (!availabiltiesIds.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); - else { + + const safe = schemaSingleAvailabilityReadBodyParams.safeParse(body); + if (!safe.success) { + res.status(400).json({ message: "Bad request" }); + return; + } + + const safeBody = safe.data; + + if (safeBody.userId && !isAdmin) { + res.status(401).json({ message: "Unauthorized" }); + return; + } + + const data = await prisma.schedule.findMany({ + where: { userId: safeBody.userId || userId }, + select: { + availability: true, + }, + }); + + const availabilitiesArray = data.flatMap((schedule) => schedule.availability); + + if (!availabilitiesArray.some((availability) => availability.id === safeQuery.data.id)) { + res.status(401).json({ message: "Unauthorized" }); + return; + } else { switch (method) { /** * @swagger @@ -100,7 +131,6 @@ export async function availabilityById( * description: Authorization information is missing or invalid. */ case "PATCH": - console.log(body); const safeBody = schemaAvailabilityEditBodyParams.safeParse(body); if (!safeBody.success) { console.log(safeBody.error); diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index ab4ae8f73b..e3bc338f9f 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -1,101 +1,140 @@ import type { NextApiRequest, NextApiResponse } from "next"; +import safeParseJSON from "@lib/helpers/safeParseJSON"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { AvailabilityResponse, AvailabilitiesResponse } from "@lib/types"; import { schemaAvailabilityCreateBodyParams, schemaAvailabilityReadPublic, + schemaAvailabilityReadBodyParams, } from "@lib/validations/availability"; async function createOrlistAllAvailabilities( - { method, body, userId, prisma }: NextApiRequest, + { method, body, userId, isAdmin, prisma }: NextApiRequest, res: NextApiResponse ) { - if (method === "GET") { - /** - * @swagger - * /availabilities: - * get: - * operationId: listAvailabilities - * summary: Find all availabilities - * tags: - * - availabilities - * externalDocs: - * url: https://docs.cal.com/availability - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No availabilities were found - */ - const data = await prisma.availability.findMany({ where: { userId } }); - const availabilities = data.map((availability) => schemaAvailabilityReadPublic.parse(availability)); - if (availabilities) res.status(200).json({ availabilities }); - else - (error: Error) => - res.status(404).json({ - message: "No Availabilities were found", - error, - }); - } else if (method === "POST") { - /** - * @swagger - * /availabilities: - * post: - * operationId: addAvailability - * summary: Creates a new availability - * requestBody: - * description: Edit an existing availability related to one of your bookings - * required: true - * content: - * application/json: - * schema: - * type: object - * required: - * - startTime - * - endTime - * properties: - * days: - * type: array - * example: email@example.com - * startTime: - * type: string - * example: 1970-01-01T17:00:00.000Z - * endTime: - * type: string - * example: 1970-01-01T17:00:00.000Z - * tags: - * - availabilities - * externalDocs: - * url: https://docs.cal.com/availability - * responses: - * 201: - * description: OK, availability created - * 400: - * description: Bad request. Availability body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - const safe = schemaAvailabilityCreateBodyParams.safeParse(body); - if (!safe.success) { - res.status(400).json({ message: "Your request is invalid", error: safe.error }); - return; - } - // FIXME: check for eventTypeId ad scheduleId ownership if passed + body = safeParseJSON(body); + if (body.success !== undefined && !body.success) { + res.status(400).json({ message: body.message }); + return; + } - const data = await prisma.availability.create({ data: { ...safe.data, userId } }); - const availability = schemaAvailabilityReadPublic.parse(data); + const safe = schemaAvailabilityReadBodyParams.safeParse(body); - if (availability) res.status(201).json({ availability, message: "Availability created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new availability", - error, - }); - } else res.status(405).json({ message: `Method ${method} not allowed` }); + if (!safe.success) { + return res.status(400).json({ message: "Bad request" }); + } + + const safeBody = safe.data; + + if (safeBody.userId && !isAdmin) { + res.status(401).json({ message: "Unauthorized" }); + return; + } else { + if (method === "GET") { + /** + * @swagger + * /availabilities: + * get: + * operationId: listAvailabilities + * summary: Find all availabilities + * tags: + * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No availabilities were found + */ + // const data = await prisma.availability.findMany({ where: { userId } }); + + const userIds = Array.isArray(safeBody.userId) ? safeBody.userId : [safeBody.userId || userId]; + + const schedules = await prisma.schedule.findMany({ + where: { + userId: { in: userIds }, + availability: { some: {} }, + }, + select: { + availability: true, + userId: true, + }, + ...(Array.isArray(body.userId) && { orderBy: { userId: "asc" } }), + }); + + const availabilities = schedules.flatMap((schedule) => { + return { ...schedule.availability[0], userId: schedule.userId }; + }); + + if (availabilities) res.status(200).json({ availabilities }); + else + (error: Error) => + res.status(404).json({ + message: "No Availabilities were found", + error, + }); + } else if (method === "POST") { + /** + * @swagger + * /availabilities: + * post: + * operationId: addAvailability + * summary: Creates a new availability + * requestBody: + * description: Edit an existing availability related to one of your bookings + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - startTime + * - endTime + * properties: + * days: + * type: array + * example: email@example.com + * startTime: + * type: string + * example: 1970-01-01T17:00:00.000Z + * endTime: + * type: string + * example: 1970-01-01T17:00:00.000Z + * tags: + * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability + * responses: + * 201: + * description: OK, availability created + * 400: + * description: Bad request. Availability body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ + const safe = schemaAvailabilityCreateBodyParams.safeParse(body); + if (!safe.success) { + res.status(400).json({ message: "Your request is invalid", error: safe.error }); + return; + } + // FIXME: check for eventTypeId ad scheduleId ownership if passed + + const data = await prisma.availability.create({ data: { ...safe.data, userId } }); + const availability = schemaAvailabilityReadPublic.parse(data); + + if (availability) res.status(201).json({ availability, message: "Availability created successfully" }); + else + (error: Error) => + res.status(400).json({ + message: "Could not create new availability", + error, + }); + } else res.status(405).json({ message: `Method ${method} not allowed` }); + } } export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllAvailabilities); From f5d953ef1cf8bf89471c1b6544029f7ea00f4267 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 7 Oct 2022 12:03:04 +0200 Subject: [PATCH 505/658] Hotfix/schedule (#174) * Allows empty call An authorized API call by a non-admin user with empty body will still fetch his data now * Adds missing return --- pages/api/schedules/[id].ts | 1 + pages/api/schedules/index.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id].ts index 59c78ea12b..9dbb75470a 100644 --- a/pages/api/schedules/[id].ts +++ b/pages/api/schedules/[id].ts @@ -16,6 +16,7 @@ export async function scheduleById( body = safeParseJSON(body); if (!body.success) { res.status(400).json({ message: body.message }); + return; } const safeBody = schemaSingleScheduleBodyParams.safeParse(body); diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index 86faad4181..10536f5cea 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -16,7 +16,7 @@ async function createOrlistAllSchedules( res: NextApiResponse ) { body = safeParseJSON(body); - if (!body.success) { + if (body.success !== undefined && !body.success) { res.status(400).json({ message: body.message }); return; } From d4a2b8e791978ae7e1f6a7af28e374eae7eaa8c8 Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 7 Oct 2022 13:08:25 -0600 Subject: [PATCH 506/658] Refactors attendees' endpoints --- pages/api/attendees/[id].ts | 180 ------------------- pages/api/attendees/[id]/_auth-middleware.ts | 21 +++ pages/api/attendees/[id]/_delete.ts | 37 ++++ pages/api/attendees/[id]/_get.ts | 39 ++++ pages/api/attendees/[id]/_patch.ts | 57 ++++++ pages/api/attendees/[id]/index.ts | 16 ++ pages/api/attendees/_get.ts | 34 ++++ pages/api/attendees/_post.ts | 77 ++++++++ pages/api/attendees/index.ts | 148 +-------------- 9 files changed, 288 insertions(+), 321 deletions(-) delete mode 100644 pages/api/attendees/[id].ts create mode 100644 pages/api/attendees/[id]/_auth-middleware.ts create mode 100644 pages/api/attendees/[id]/_delete.ts create mode 100644 pages/api/attendees/[id]/_get.ts create mode 100644 pages/api/attendees/[id]/_patch.ts create mode 100644 pages/api/attendees/[id]/index.ts create mode 100644 pages/api/attendees/_get.ts create mode 100644 pages/api/attendees/_post.ts diff --git a/pages/api/attendees/[id].ts b/pages/api/attendees/[id].ts deleted file mode 100644 index d7e927e36e..0000000000 --- a/pages/api/attendees/[id].ts +++ /dev/null @@ -1,180 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { AttendeeResponse } from "@lib/types"; -import { schemaAttendeeEditBodyParams, schemaAttendeeReadPublic } from "@lib/validations/attendee"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -export async function attendeeById( - { method, query, body, userId, isAdmin, prisma }: NextApiRequest, - res: NextApiResponse -) { - const safeQuery = schemaQueryIdParseInt.safeParse(query); - if (!safeQuery.success) { - res.status(400).json({ error: safeQuery.error }); - return; - } - const userBookingsAttendeeIds = await prisma.booking - // Find all user bookings, including attendees - .findMany({ - where: { userId }, - include: { attendees: true }, - }) - .then( - // Flatten and merge all the attendees in one array - (bookings) => - bookings - .map((bookings) => bookings.attendees) - .flat() - .map((attendee) => attendee.id) - ); - // @note: Here we make sure to only return attendee's of the user's own bookings if the user is not an admin. - if (!isAdmin) { - if (!userBookingsAttendeeIds.includes(safeQuery.data.id)) - res.status(401).json({ message: "Unauthorized" }); - } else { - switch (method) { - /** - * @swagger - * /attendees/{id}: - * get: - * operationId: getAttendeeById - * summary: Find an attendee - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the attendee to get - * example: 3 - * tags: - * - attendees - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Attendee was not found - */ - case "GET": - await prisma.attendee - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaAttendeeReadPublic.parse(data)) - .then((attendee) => res.status(200).json({ attendee })) - .catch((error: Error) => - res.status(404).json({ - message: `Attendee with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - /** - * @swagger - * /attendees/{id}: - * patch: - * summary: Edit an existing attendee - * operationId: editAttendeeById - * requestBody: - * description: Edit an existing attendee related to one of your bookings - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * email: - * type: string - * example: email@example.com - * name: - * type: string - * example: John Doe - * timeZone: - * type: string - * example: Europe/London - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * example: 3 - * required: true - * description: ID of the attendee to edit - * tags: - * - attendees - * responses: - * 201: - * description: OK, attendee edited successfuly - * 400: - * description: Bad request. Attendee body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - case "PATCH": - const safeBody = schemaAttendeeEditBodyParams.safeParse(body); - if (!safeBody.success) { - res.status(400).json({ message: "Bad request", error: safeBody.error }); - return; - } - await prisma.attendee - .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) - .then((data) => schemaAttendeeReadPublic.parse(data)) - .then((attendee) => res.status(200).json({ attendee })) - .catch((error: Error) => - res.status(404).json({ - message: `Attendee with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - /** - * @swagger - * /attendees/{id}: - * delete: - * operationId: removeAttendeeById - * summary: Remove an existing attendee - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the attendee to delete - * tags: - * - attendees - * responses: - * 201: - * description: OK, attendee removed successfuly - * 400: - * description: Bad request. Attendee id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - case "DELETE": - await prisma.attendee - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ - message: `Attendee with id: ${safeQuery.data.id} deleted successfully`, - }) - ) - .catch((error: Error) => - res.status(404).json({ - message: `Attendee with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } - } -} - -export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(attendeeById)); diff --git a/pages/api/attendees/[id]/_auth-middleware.ts b/pages/api/attendees/[id]/_auth-middleware.ts new file mode 100644 index 0000000000..b1b474b506 --- /dev/null +++ b/pages/api/attendees/[id]/_auth-middleware.ts @@ -0,0 +1,21 @@ +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +async function authMiddleware(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const query = schemaQueryIdParseInt.parse(req.query); + // @note: Here we make sure to only return attendee's of the user's own bookings if the user is not an admin. + if (isAdmin) return; + // Find all user bookings, including attendees + const attendee = await prisma.attendee.findFirst({ + where: { id: query.id, booking: { userId } }, + }); + // Flatten and merge all the attendees in one array + if (!attendee) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); +} + +export default defaultResponder(authMiddleware); diff --git a/pages/api/attendees/[id]/_delete.ts b/pages/api/attendees/[id]/_delete.ts new file mode 100644 index 0000000000..a51b6457b6 --- /dev/null +++ b/pages/api/attendees/[id]/_delete.ts @@ -0,0 +1,37 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /attendees/{id}: + * delete: + * operationId: removeAttendeeById + * summary: Remove an existing attendee + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the attendee to delete + * tags: + * - attendees + * responses: + * 201: + * description: OK, attendee removed successfuly + * 400: + * description: Bad request. Attendee id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdParseInt.parse(query); + await prisma.attendee.delete({ where: { id } }); + return { message: `Attendee with id: ${id} deleted successfully` }; +} + +export default defaultResponder(deleteHandler); diff --git a/pages/api/attendees/[id]/_get.ts b/pages/api/attendees/[id]/_get.ts new file mode 100644 index 0000000000..aa10526544 --- /dev/null +++ b/pages/api/attendees/[id]/_get.ts @@ -0,0 +1,39 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaAttendeeReadPublic } from "@lib/validations/attendee"; +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /attendees/{id}: + * get: + * operationId: getAttendeeById + * summary: Find an attendee + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the attendee to get + * example: 3 + * tags: + * - attendees + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Attendee was not found + */ +export async function getHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdParseInt.parse(query); + const attendee = await prisma.attendee.findUnique({ where: { id } }); + return { attendee: schemaAttendeeReadPublic.parse(attendee) }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/attendees/[id]/_patch.ts b/pages/api/attendees/[id]/_patch.ts new file mode 100644 index 0000000000..77d3dc28d0 --- /dev/null +++ b/pages/api/attendees/[id]/_patch.ts @@ -0,0 +1,57 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaAttendeeEditBodyParams, schemaAttendeeReadPublic } from "@lib/validations/attendee"; +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /attendees/{id}: + * patch: + * summary: Edit an existing attendee + * operationId: editAttendeeById + * requestBody: + * description: Edit an existing attendee related to one of your bookings + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * email: + * type: string + * example: email@example.com + * name: + * type: string + * example: John Doe + * timeZone: + * type: string + * example: Europe/London + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * example: 3 + * required: true + * description: ID of the attendee to edit + * tags: + * - attendees + * responses: + * 201: + * description: OK, attendee edited successfuly + * 400: + * description: Bad request. Attendee body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function patchHandler(req: NextApiRequest) { + const { prisma, query, body } = req; + const { id } = schemaQueryIdParseInt.parse(query); + const data = schemaAttendeeEditBodyParams.parse(body); + const attendee = await prisma.attendee.update({ where: { id }, data }); + return { attendee: schemaAttendeeReadPublic.parse(attendee) }; +} + +export default defaultResponder(patchHandler); diff --git a/pages/api/attendees/[id]/index.ts b/pages/api/attendees/[id]/index.ts new file mode 100644 index 0000000000..4b740bcbb5 --- /dev/null +++ b/pages/api/attendees/[id]/index.ts @@ -0,0 +1,16 @@ +import { NextApiRequest, NextApiResponse } from "next"; + +import { defaultHandler } from "@calcom/lib/server"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; + +import authMiddleware from "./_auth-middleware"; + +export default withMiddleware("HTTP_GET_DELETE_PATCH")(async (req: NextApiRequest, res: NextApiResponse) => { + await authMiddleware(req, res); + return defaultHandler({ + GET: import("./_get"), + PATCH: import("./_patch"), + DELETE: import("./_delete"), + })(req, res); +}); diff --git a/pages/api/attendees/_get.ts b/pages/api/attendees/_get.ts new file mode 100644 index 0000000000..078e8174a8 --- /dev/null +++ b/pages/api/attendees/_get.ts @@ -0,0 +1,34 @@ +import type { Prisma } from "@prisma/client"; +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaAttendeeReadPublic } from "@lib/validations/attendee"; + +/** + * @swagger + * /attendees: + * get: + * operationId: listAttendees + * summary: Find all attendees + * tags: + * - attendees + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No attendees were found + */ +async function handler(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const args: Prisma.AttendeeFindManyArgs = isAdmin ? {} : { where: { booking: { userId } } }; + const data = await prisma.attendee.findMany(args); + const attendees = data.map((attendee) => schemaAttendeeReadPublic.parse(attendee)); + if (!attendees) throw new HttpError({ statusCode: 404, message: "No attendees were found" }); + return { attendees }; +} + +export default defaultResponder(handler); diff --git a/pages/api/attendees/_post.ts b/pages/api/attendees/_post.ts new file mode 100644 index 0000000000..1e5ff8199f --- /dev/null +++ b/pages/api/attendees/_post.ts @@ -0,0 +1,77 @@ +import { HttpError } from "@/../../packages/lib/http-error"; +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaAttendeeCreateBodyParams, schemaAttendeeReadPublic } from "@lib/validations/attendee"; + +/** + * @swagger + * /attendees: + * post: + * operationId: addAttendee + * summary: Creates a new attendee + * requestBody: + * description: Create a new attendee related to one of your bookings + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - bookingId + * - name + * - email + * - timeZone + * properties: + * bookingId: + * type: number + * example: 1 + * email: + * type: string + * example: email@example.com + * name: + * type: string + * example: John Doe + * timeZone: + * type: string + * example: Europe/London + * tags: + * - attendees + * responses: + * 201: + * description: OK, attendee created + * 400: + * description: Bad request. Attendee body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function postHandler(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const body = schemaAttendeeCreateBodyParams.parse(req.body); + + if (!isAdmin) { + const userBooking = await prisma.booking.findFirst({ + where: { userId, id: body.bookingId }, + select: { id: true }, + }); + // Here we make sure to only return attendee's of the user's own bookings. + if (!userBooking) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + } + + const data = await prisma.attendee.create({ + data: { + email: body.email, + name: body.name, + timeZone: body.timeZone, + booking: { connect: { id: body.bookingId } }, + }, + }); + + return { + attendee: schemaAttendeeReadPublic.parse(data), + message: "Attendee created successfully", + }; +} + +export default defaultResponder(postHandler); diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index 880c8d4d4b..c07846423f 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -1,144 +1,10 @@ -import type { NextApiRequest, NextApiResponse } from "next"; +import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { AttendeeResponse, AttendeesResponse } from "@lib/types"; -import { schemaAttendeeCreateBodyParams, schemaAttendeeReadPublic } from "@lib/validations/attendee"; -async function createOrlistAllAttendees( - { method, userId, body, prisma, isAdmin }: NextApiRequest, - res: NextApiResponse -) { - let attendees; - if (!isAdmin) { - const userBookings = await prisma.booking.findMany({ - where: { - userId, - }, - include: { - attendees: true, - }, - }); - attendees = userBookings.map((booking) => booking.attendees).flat(); - } else { - const data = await prisma.attendee.findMany(); - attendees = data.map((attendee) => schemaAttendeeReadPublic.parse(attendee)); - } - if (method === "GET") { - /** - * @swagger - * /attendees: - * get: - * operationId: listAttendees - * summary: Find all attendees - * tags: - * - attendees - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No attendees were found - */ - if (attendees) res.status(200).json({ attendees }); - else (error: Error) => res.status(400).json({ error }); - } else if (method === "POST") { - /** - * @swagger - * /attendees: - * post: - * operationId: addAttendee - * summary: Creates a new attendee - * requestBody: - * description: Create a new attendee related to one of your bookings - * required: true - * content: - * application/json: - * schema: - * type: object - * required: - * - bookingId - * - name - * - email - * - timeZone - * properties: - * bookingId: - * type: number - * example: 1 - * email: - * type: string - * example: email@example.com - * name: - * type: string - * example: John Doe - * timeZone: - * type: string - * example: Europe/London - * tags: - * - attendees - * responses: - * 201: - * description: OK, attendee created - * 400: - * description: Bad request. Attendee body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - const safePost = schemaAttendeeCreateBodyParams.safeParse(body); - if (!safePost.success) { - res.status(400).json({ message: "Invalid request body", error: safePost.error }); - return; - } - if (!isAdmin) { - const userWithBookings = await prisma.user.findUnique({ - where: { id: userId }, - include: { bookings: true }, - }); - if (!userWithBookings) { - res.status(404).json({ message: "User not found" }); - return; - } - const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); - // Here we make sure to only return attendee's of the user's own bookings. - if (!userBookingIds.includes(safePost.data.bookingId)) - res.status(401).json({ message: "Unauthorized" }); - else { - const data = await prisma.attendee.create({ - data: { - email: safePost.data.email, - name: safePost.data.name, - timeZone: safePost.data.timeZone, - booking: { connect: { id: safePost.data.bookingId } }, - }, - }); - const attendee = schemaAttendeeReadPublic.parse(data); - - if (attendee) { - res.status(201).json({ - attendee, - message: "Attendee created successfully", - }); - } else (error: Error) => res.status(400).json({ error }); - } - } else { - const data = await prisma.attendee.create({ - data: { - email: safePost.data.email, - name: safePost.data.name, - timeZone: safePost.data.timeZone, - booking: { connect: { id: safePost.data.bookingId } }, - }, - }); - const attendee = schemaAttendeeReadPublic.parse(data); - - if (attendee) { - res.status(201).json({ - attendee, - message: "Attendee created successfully", - }); - } else (error: Error) => res.status(400).json({ error }); - } - } else res.status(405).json({ message: `Method ${method} not allowed` }); -} - -export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllAttendees); +export default withMiddleware("HTTP_GET_OR_POST")( + defaultHandler({ + GET: import("./_get"), + POST: import("./_post"), + }) +); From 18e96e2a47a48c5d79f98925f91f45a7cb7e2e11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Mon, 10 Oct 2022 09:42:15 -0600 Subject: [PATCH 507/658] Refactors availabilities endpoints (#177) refs #175 --- lib/validations/availability.ts | 30 ++- pages/api/availabilities/[id].ts | 206 ------------------ .../availabilities/[id]/_auth-middleware.ts | 21 ++ pages/api/availabilities/[id]/_delete.ts | 39 ++++ pages/api/availabilities/[id]/_get.ts | 41 ++++ pages/api/availabilities/[id]/_patch.ts | 65 ++++++ pages/api/availabilities/[id]/index.ts | 16 ++ pages/api/availabilities/_get.ts | 58 +++++ pages/api/availabilities/_post.ts | 76 +++++++ pages/api/availabilities/index.ts | 144 +----------- 10 files changed, 336 insertions(+), 360 deletions(-) delete mode 100644 pages/api/availabilities/[id].ts create mode 100644 pages/api/availabilities/[id]/_auth-middleware.ts create mode 100644 pages/api/availabilities/[id]/_delete.ts create mode 100644 pages/api/availabilities/[id]/_get.ts create mode 100644 pages/api/availabilities/[id]/_patch.ts create mode 100644 pages/api/availabilities/[id]/index.ts create mode 100644 pages/api/availabilities/_get.ts create mode 100644 pages/api/availabilities/_post.ts diff --git a/lib/validations/availability.ts b/lib/validations/availability.ts index f55d481b2f..9d6fd20d1f 100644 --- a/lib/validations/availability.ts +++ b/lib/validations/availability.ts @@ -1,15 +1,14 @@ import { z } from "zod"; -import { _AvailabilityModel as Availability } from "@calcom/prisma/zod"; +import { _AvailabilityModel as Availability, _ScheduleModel as Schedule } from "@calcom/prisma/zod"; +import { denullishShape } from "@calcom/prisma/zod-utils"; -export const schemaAvailabilityBaseBodyParams = Availability.pick({ - startTime: true, - endTime: true, - date: true, - scheduleId: true, - days: true, - userId: true, -}).partial(); +export const schemaAvailabilityBaseBodyParams = /** We make all these properties required */ denullishShape( + Availability.pick({ + /** We need to pass the schedule where this availability belongs to */ + scheduleId: true, + }) +); export const schemaAvailabilityReadPublic = Availability.pick({ id: true, @@ -18,16 +17,15 @@ export const schemaAvailabilityReadPublic = Availability.pick({ date: true, scheduleId: true, days: true, - eventTypeId: true, - userId: true, -}).merge(z.object({ success: z.boolean().optional() })); + // eventTypeId: true /** @deprecated */, + // userId: true /** @deprecated */, +}).merge(z.object({ success: z.boolean().optional(), Schedule: Schedule.partial() }).partial()); const schemaAvailabilityCreateParams = z .object({ startTime: z.date().or(z.string()), endTime: z.date().or(z.string()), days: z.array(z.number()).optional(), - eventTypeId: z.number().optional(), }) .strict(); @@ -36,13 +34,11 @@ const schemaAvailabilityEditParams = z startTime: z.date().or(z.string()).optional(), endTime: z.date().or(z.string()).optional(), days: z.array(z.number()).optional(), - eventTypeId: z.number().optional(), }) .strict(); -export const schemaAvailabilityEditBodyParams = schemaAvailabilityBaseBodyParams.merge( - schemaAvailabilityEditParams -); +export const schemaAvailabilityEditBodyParams = schemaAvailabilityEditParams; + export const schemaAvailabilityCreateBodyParams = schemaAvailabilityBaseBodyParams.merge( schemaAvailabilityCreateParams ); diff --git a/pages/api/availabilities/[id].ts b/pages/api/availabilities/[id].ts deleted file mode 100644 index d95c10cc18..0000000000 --- a/pages/api/availabilities/[id].ts +++ /dev/null @@ -1,206 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import safeParseJSON from "@lib/helpers/safeParseJSON"; -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { AvailabilityResponse } from "@lib/types"; -import { - schemaAvailabilityEditBodyParams, - schemaAvailabilityReadPublic, - schemaSingleAvailabilityReadBodyParams, -} from "@lib/validations/availability"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -export async function availabilityById( - { method, query, body, userId, isAdmin, prisma }: NextApiRequest, - res: NextApiResponse -) { - body = safeParseJSON(body); - if (body.success !== undefined && !body.success) { - res.status(400).json({ message: body.message }); - return; - } - - const safeQuery = schemaQueryIdParseInt.safeParse(query); - if (!safeQuery.success) { - res.status(400).json({ message: "Your query is invalid", error: safeQuery.error }); - return; - } - - const safe = schemaSingleAvailabilityReadBodyParams.safeParse(body); - if (!safe.success) { - res.status(400).json({ message: "Bad request" }); - return; - } - - const safeBody = safe.data; - - if (safeBody.userId && !isAdmin) { - res.status(401).json({ message: "Unauthorized" }); - return; - } - - const data = await prisma.schedule.findMany({ - where: { userId: safeBody.userId || userId }, - select: { - availability: true, - }, - }); - - const availabilitiesArray = data.flatMap((schedule) => schedule.availability); - - if (!availabilitiesArray.some((availability) => availability.id === safeQuery.data.id)) { - res.status(401).json({ message: "Unauthorized" }); - return; - } else { - switch (method) { - /** - * @swagger - * /availabilities/{id}: - * get: - * operationId: getAvailabilityById - * summary: Find an availability - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the availability to get - * tags: - * - availabilities - * externalDocs: - * url: https://docs.cal.com/availability - * responses: - * 200: - * description: OK - * 401: - * description: Unathorized - */ - case "GET": - await prisma.availability - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaAvailabilityReadPublic.parse(data)) - .then((availability) => res.status(200).json({ availability })) - .catch((error: Error) => - res.status(404).json({ message: `Availability with id: ${safeQuery.data.id} not found`, error }) - ); - break; - /** - * @swagger - * /availabilities/{id}: - * patch: - * operationId: editAvailabilityById - * summary: Edit an existing availability - * requestBody: - * description: Edit an existing availability related to one of your bookings - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * days: - * type: array - * example: email@example.com - * startTime: - * type: string - * example: 1970-01-01T17:00:00.000Z - * endTime: - * type: string - * example: 1970-01-01T17:00:00.000Z - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the availability to edit - * tags: - * - availabilities - * externalDocs: - * url: https://docs.cal.com/availability - * responses: - * 201: - * description: OK, availability edited successfuly - * 400: - * description: Bad request. Availability body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - case "PATCH": - const safeBody = schemaAvailabilityEditBodyParams.safeParse(body); - if (!safeBody.success) { - console.log(safeBody.error); - res.status(400).json({ message: "Bad request" + safeBody.error, error: safeBody.error }); - return; - } - const userEventTypes = await prisma.eventType.findMany({ where: { userId } }); - const userEventTypesIds = userEventTypes.map((event) => event.id); - if (safeBody.data.eventTypeId && !userEventTypesIds.includes(safeBody.data.eventTypeId)) { - res.status(401).json({ - message: `Bad request. You're not the owner of eventTypeId: ${safeBody.data.eventTypeId}`, - }); - } - await prisma.availability - .update({ - where: { id: safeQuery.data.id }, - data: safeBody.data, - }) - .then((data) => schemaAvailabilityReadPublic.parse(data)) - .then((availability) => res.status(200).json({ availability })) - .catch((error: Error) => { - res.status(404).json({ - message: `Availability with id: ${safeQuery.data.id} not found`, - error, - }); - }); - break; - /** - * @swagger - * /availabilities/{id}: - * delete: - * operationId: removeAvailabilityById - * summary: Remove an existing availability - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the availability to delete - * tags: - * - availabilities - * externalDocs: - * url: https://docs.cal.com/availability - * responses: - * 201: - * description: OK, availability removed successfuly - * 400: - * description: Bad request. Availability id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - case "DELETE": - await prisma.availability - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res - .status(200) - .json({ message: `Availability with id: ${safeQuery.data.id} deleted successfully` }) - ) - .catch((error: Error) => - res.status(404).json({ message: `Availability with id: ${safeQuery.data.id} not found`, error }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } - } -} - -export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(availabilityById)); diff --git a/pages/api/availabilities/[id]/_auth-middleware.ts b/pages/api/availabilities/[id]/_auth-middleware.ts new file mode 100644 index 0000000000..44378f90a3 --- /dev/null +++ b/pages/api/availabilities/[id]/_auth-middleware.ts @@ -0,0 +1,21 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +export async function authMiddleware(req: NextApiRequest) { + const { userId, prisma, isAdmin, query } = req; + const { id } = schemaQueryIdParseInt.parse(query); + /** Admins can skip the ownership verification */ + if (isAdmin) return; + /** + * There's a caveat here. If the availability exists but the user doesn't own it, + * the user will see a 404 error which may or not be the desired behavior. + */ + await prisma.availability.findFirstOrThrow({ + where: { id, Schedule: { userId } }, + }); +} + +export default defaultResponder(authMiddleware); diff --git a/pages/api/availabilities/[id]/_delete.ts b/pages/api/availabilities/[id]/_delete.ts new file mode 100644 index 0000000000..a298642d6f --- /dev/null +++ b/pages/api/availabilities/[id]/_delete.ts @@ -0,0 +1,39 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /availabilities/{id}: + * delete: + * operationId: removeAvailabilityById + * summary: Remove an existing availability + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the availability to delete + * tags: + * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability + * responses: + * 201: + * description: OK, availability removed successfully + * 400: + * description: Bad request. Availability id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdParseInt.parse(query); + await prisma.availability.delete({ where: { id } }); + return { message: `Availability with id: ${id} deleted successfully` }; +} + +export default defaultResponder(deleteHandler); diff --git a/pages/api/availabilities/[id]/_get.ts b/pages/api/availabilities/[id]/_get.ts new file mode 100644 index 0000000000..3ea8064e05 --- /dev/null +++ b/pages/api/availabilities/[id]/_get.ts @@ -0,0 +1,41 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaAvailabilityReadPublic } from "@lib/validations/availability"; +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /availabilities/{id}: + * get: + * operationId: getAvailabilityById + * summary: Find an availability + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the availability to get + * tags: + * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability + * responses: + * 200: + * description: OK + * 401: + * description: Unauthorized + */ +export async function getHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdParseInt.parse(query); + const availability = await prisma.availability.findUnique({ + where: { id }, + include: { Schedule: { select: { userId: true } } }, + }); + return { availability: schemaAvailabilityReadPublic.parse(availability) }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/availabilities/[id]/_patch.ts b/pages/api/availabilities/[id]/_patch.ts new file mode 100644 index 0000000000..9e7b0b5ebb --- /dev/null +++ b/pages/api/availabilities/[id]/_patch.ts @@ -0,0 +1,65 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { + schemaAvailabilityEditBodyParams, + schemaAvailabilityReadPublic, +} from "@lib/validations/availability"; +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /availabilities/{id}: + * patch: + * operationId: editAvailabilityById + * summary: Edit an existing availability + * requestBody: + * description: Edit an existing availability related to one of your bookings + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * days: + * type: array + * example: email@example.com + * startTime: + * type: string + * example: 1970-01-01T17:00:00.000Z + * endTime: + * type: string + * example: 1970-01-01T17:00:00.000Z + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the availability to edit + * tags: + * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability + * responses: + * 201: + * description: OK, availability edited successfully + * 400: + * description: Bad request. Availability body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function patchHandler(req: NextApiRequest) { + const { prisma, query, body } = req; + const { id } = schemaQueryIdParseInt.parse(query); + const data = schemaAvailabilityEditBodyParams.parse(body); + const availability = await prisma.availability.update({ + where: { id }, + data, + include: { Schedule: { select: { userId: true } } }, + }); + return { availability: schemaAvailabilityReadPublic.parse(availability) }; +} + +export default defaultResponder(patchHandler); diff --git a/pages/api/availabilities/[id]/index.ts b/pages/api/availabilities/[id]/index.ts new file mode 100644 index 0000000000..4b740bcbb5 --- /dev/null +++ b/pages/api/availabilities/[id]/index.ts @@ -0,0 +1,16 @@ +import { NextApiRequest, NextApiResponse } from "next"; + +import { defaultHandler } from "@calcom/lib/server"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; + +import authMiddleware from "./_auth-middleware"; + +export default withMiddleware("HTTP_GET_DELETE_PATCH")(async (req: NextApiRequest, res: NextApiResponse) => { + await authMiddleware(req, res); + return defaultHandler({ + GET: import("./_get"), + PATCH: import("./_patch"), + DELETE: import("./_delete"), + })(req, res); +}); diff --git a/pages/api/availabilities/_get.ts b/pages/api/availabilities/_get.ts new file mode 100644 index 0000000000..b0649b5b16 --- /dev/null +++ b/pages/api/availabilities/_get.ts @@ -0,0 +1,58 @@ +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaAvailabilityReadBodyParams } from "@lib/validations/availability"; + +/** + * @swagger + * /availabilities: + * get: + * operationId: listAvailabilities + * summary: Find all availabilities + * tags: + * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No availabilities were found + */ +async function handler(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const body = schemaAvailabilityReadBodyParams.parse(req.body || {}); + + if (body.userId && !isAdmin) + throw new HttpError({ + statusCode: 401, + message: "Unauthorized: Only admins can request other users' availabilities", + }); + + const userIds = Array.isArray(body.userId) ? body.userId : [body.userId || userId]; + + let availabilities = await prisma.availability.findMany({ + where: { Schedule: { userId: { in: userIds } } }, + include: { Schedule: { select: { userId: true } } }, + ...(Array.isArray(body.userId) && { orderBy: { userId: "asc" } }), + }); + + /** + * IDK if this a special requirement but, since availabilities aren't directly related to a user. + * We manually override the `userId` field so the user doesn't need to query the scheduleId just + * to get the user that it belongs to... OR... we can just access `availability.Schedule.userId` instead + * but at this point I'm afraid to break something so we will have both for now... ¯\_(ツ)_/¯ + */ + availabilities = availabilities.map((a) => ({ ...a, userId: a.Schedule?.userId || null })); + + if (!availabilities.length) + throw new HttpError({ statusCode: 404, message: "No Availabilities were found" }); + + return { availabilities }; +} + +export default defaultResponder(handler); diff --git a/pages/api/availabilities/_post.ts b/pages/api/availabilities/_post.ts new file mode 100644 index 0000000000..aa4bac13fe --- /dev/null +++ b/pages/api/availabilities/_post.ts @@ -0,0 +1,76 @@ +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { + schemaAvailabilityCreateBodyParams, + schemaAvailabilityReadPublic, +} from "@lib/validations/availability"; + +/** + * @swagger + * /availabilities: + * post: + * operationId: addAvailability + * summary: Creates a new availability + * requestBody: + * description: Edit an existing availability related to one of your bookings + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - scheduleId + * - startTime + * - endTime + * properties: + * days: + * type: array + * example: email@example.com + * startTime: + * type: string + * example: 1970-01-01T17:00:00.000Z + * endTime: + * type: string + * example: 1970-01-01T17:00:00.000Z + * tags: + * - availabilities + * externalDocs: + * url: https://docs.cal.com/availability + * responses: + * 201: + * description: OK, availability created + * 400: + * description: Bad request. Availability body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function postHandler(req: NextApiRequest) { + const { prisma } = req; + const data = schemaAvailabilityCreateBodyParams.parse(req.body); + await checkPermissions(req); + const availability = await prisma.availability.create({ + data, + include: { Schedule: { select: { userId: true } } }, + }); + req.statusCode = 201; + return { + availability: schemaAvailabilityReadPublic.parse(availability), + message: "Availability created successfully", + }; +} + +async function checkPermissions(req: NextApiRequest) { + const { userId, prisma, isAdmin } = req; + if (isAdmin) return; + const data = schemaAvailabilityCreateBodyParams.parse(req.body); + const schedule = await prisma.schedule.findFirst({ + where: { userId, id: data.scheduleId }, + }); + if (!schedule) + throw new HttpError({ statusCode: 401, message: "You can't add availabilities to this schedule" }); +} + +export default defaultResponder(postHandler); diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index e3bc338f9f..c07846423f 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -1,140 +1,10 @@ -import type { NextApiRequest, NextApiResponse } from "next"; +import { defaultHandler } from "@calcom/lib/server"; -import safeParseJSON from "@lib/helpers/safeParseJSON"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { AvailabilityResponse, AvailabilitiesResponse } from "@lib/types"; -import { - schemaAvailabilityCreateBodyParams, - schemaAvailabilityReadPublic, - schemaAvailabilityReadBodyParams, -} from "@lib/validations/availability"; -async function createOrlistAllAvailabilities( - { method, body, userId, isAdmin, prisma }: NextApiRequest, - res: NextApiResponse -) { - body = safeParseJSON(body); - if (body.success !== undefined && !body.success) { - res.status(400).json({ message: body.message }); - return; - } - - const safe = schemaAvailabilityReadBodyParams.safeParse(body); - - if (!safe.success) { - return res.status(400).json({ message: "Bad request" }); - } - - const safeBody = safe.data; - - if (safeBody.userId && !isAdmin) { - res.status(401).json({ message: "Unauthorized" }); - return; - } else { - if (method === "GET") { - /** - * @swagger - * /availabilities: - * get: - * operationId: listAvailabilities - * summary: Find all availabilities - * tags: - * - availabilities - * externalDocs: - * url: https://docs.cal.com/availability - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No availabilities were found - */ - // const data = await prisma.availability.findMany({ where: { userId } }); - - const userIds = Array.isArray(safeBody.userId) ? safeBody.userId : [safeBody.userId || userId]; - - const schedules = await prisma.schedule.findMany({ - where: { - userId: { in: userIds }, - availability: { some: {} }, - }, - select: { - availability: true, - userId: true, - }, - ...(Array.isArray(body.userId) && { orderBy: { userId: "asc" } }), - }); - - const availabilities = schedules.flatMap((schedule) => { - return { ...schedule.availability[0], userId: schedule.userId }; - }); - - if (availabilities) res.status(200).json({ availabilities }); - else - (error: Error) => - res.status(404).json({ - message: "No Availabilities were found", - error, - }); - } else if (method === "POST") { - /** - * @swagger - * /availabilities: - * post: - * operationId: addAvailability - * summary: Creates a new availability - * requestBody: - * description: Edit an existing availability related to one of your bookings - * required: true - * content: - * application/json: - * schema: - * type: object - * required: - * - startTime - * - endTime - * properties: - * days: - * type: array - * example: email@example.com - * startTime: - * type: string - * example: 1970-01-01T17:00:00.000Z - * endTime: - * type: string - * example: 1970-01-01T17:00:00.000Z - * tags: - * - availabilities - * externalDocs: - * url: https://docs.cal.com/availability - * responses: - * 201: - * description: OK, availability created - * 400: - * description: Bad request. Availability body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - const safe = schemaAvailabilityCreateBodyParams.safeParse(body); - if (!safe.success) { - res.status(400).json({ message: "Your request is invalid", error: safe.error }); - return; - } - // FIXME: check for eventTypeId ad scheduleId ownership if passed - - const data = await prisma.availability.create({ data: { ...safe.data, userId } }); - const availability = schemaAvailabilityReadPublic.parse(data); - - if (availability) res.status(201).json({ availability, message: "Availability created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new availability", - error, - }); - } else res.status(405).json({ message: `Method ${method} not allowed` }); - } -} - -export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllAvailabilities); +export default withMiddleware("HTTP_GET_OR_POST")( + defaultHandler({ + GET: import("./_get"), + POST: import("./_post"), + }) +); From a35454bb68ba8dbcb2ac6335d785cf069a7949c5 Mon Sep 17 00:00:00 2001 From: zomars Date: Mon, 10 Oct 2022 18:02:36 -0600 Subject: [PATCH 508/658] Me cleanup --- pages/api/me/_get.ts | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/pages/api/me/_get.ts b/pages/api/me/_get.ts index 1ae8d47d82..bd27aad6ea 100644 --- a/pages/api/me/_get.ts +++ b/pages/api/me/_get.ts @@ -4,19 +4,9 @@ import { defaultResponder } from "@calcom/lib/server"; import { schemaUserReadPublic } from "@lib/validations/user"; -import { User } from ".prisma/client"; - -async function handler({ - userId, - prisma, -}: NextApiRequest): Promise<{ error?: string; user?: Partial }> { +async function handler({ userId, prisma }: NextApiRequest) { const data = await prisma.user.findUniqueOrThrow({ where: { id: userId } }); - if (!prisma) return { error: "Cant connect to database" }; - - if (!userId) return { error: "No user id found" }; - if (!data) return { error: "You need to pass apiKey" }; - const user = schemaUserReadPublic.parse(data); - return { user }; + return { user: schemaUserReadPublic.parse(data) }; } export default defaultResponder(handler); From c03144c34353eac456aeca9218d2f0bf89d621e7 Mon Sep 17 00:00:00 2001 From: zomars Date: Mon, 10 Oct 2022 19:46:45 -0600 Subject: [PATCH 509/658] Fixed major flaw with authMiddleware authMiddleware should not use defaultResponder directly as it will catch thrown error and we need those errors to prevent running the rest of the code. --- pages/api/attendees/[id]/_auth-middleware.ts | 3 +-- pages/api/attendees/[id]/index.ts | 20 ++++++++++--------- .../availabilities/[id]/_auth-middleware.ts | 6 ++---- pages/api/availabilities/[id]/index.ts | 20 ++++++++++--------- pages/api/bookings/[id]/_auth-middleware.ts | 5 ++--- pages/api/bookings/[id]/index.ts | 20 ++++++++++--------- 6 files changed, 38 insertions(+), 36 deletions(-) diff --git a/pages/api/attendees/[id]/_auth-middleware.ts b/pages/api/attendees/[id]/_auth-middleware.ts index b1b474b506..ab27cf266e 100644 --- a/pages/api/attendees/[id]/_auth-middleware.ts +++ b/pages/api/attendees/[id]/_auth-middleware.ts @@ -1,7 +1,6 @@ import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; -import { defaultResponder } from "@calcom/lib/server"; import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; @@ -18,4 +17,4 @@ async function authMiddleware(req: NextApiRequest) { if (!attendee) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); } -export default defaultResponder(authMiddleware); +export default authMiddleware; diff --git a/pages/api/attendees/[id]/index.ts b/pages/api/attendees/[id]/index.ts index 4b740bcbb5..7d92ee2906 100644 --- a/pages/api/attendees/[id]/index.ts +++ b/pages/api/attendees/[id]/index.ts @@ -1,16 +1,18 @@ import { NextApiRequest, NextApiResponse } from "next"; -import { defaultHandler } from "@calcom/lib/server"; +import { defaultHandler, defaultResponder } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import authMiddleware from "./_auth-middleware"; -export default withMiddleware("HTTP_GET_DELETE_PATCH")(async (req: NextApiRequest, res: NextApiResponse) => { - await authMiddleware(req, res); - return defaultHandler({ - GET: import("./_get"), - PATCH: import("./_patch"), - DELETE: import("./_delete"), - })(req, res); -}); +export default withMiddleware("HTTP_GET_DELETE_PATCH")( + defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { + await authMiddleware(req); + return defaultHandler({ + GET: import("./_get"), + PATCH: import("./_patch"), + DELETE: import("./_delete"), + })(req, res); + }) +); diff --git a/pages/api/availabilities/[id]/_auth-middleware.ts b/pages/api/availabilities/[id]/_auth-middleware.ts index 44378f90a3..4197944cf9 100644 --- a/pages/api/availabilities/[id]/_auth-middleware.ts +++ b/pages/api/availabilities/[id]/_auth-middleware.ts @@ -1,10 +1,8 @@ import type { NextApiRequest } from "next"; -import { defaultResponder } from "@calcom/lib/server"; - import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; -export async function authMiddleware(req: NextApiRequest) { +async function authMiddleware(req: NextApiRequest) { const { userId, prisma, isAdmin, query } = req; const { id } = schemaQueryIdParseInt.parse(query); /** Admins can skip the ownership verification */ @@ -18,4 +16,4 @@ export async function authMiddleware(req: NextApiRequest) { }); } -export default defaultResponder(authMiddleware); +export default authMiddleware; diff --git a/pages/api/availabilities/[id]/index.ts b/pages/api/availabilities/[id]/index.ts index 4b740bcbb5..7d92ee2906 100644 --- a/pages/api/availabilities/[id]/index.ts +++ b/pages/api/availabilities/[id]/index.ts @@ -1,16 +1,18 @@ import { NextApiRequest, NextApiResponse } from "next"; -import { defaultHandler } from "@calcom/lib/server"; +import { defaultHandler, defaultResponder } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import authMiddleware from "./_auth-middleware"; -export default withMiddleware("HTTP_GET_DELETE_PATCH")(async (req: NextApiRequest, res: NextApiResponse) => { - await authMiddleware(req, res); - return defaultHandler({ - GET: import("./_get"), - PATCH: import("./_patch"), - DELETE: import("./_delete"), - })(req, res); -}); +export default withMiddleware("HTTP_GET_DELETE_PATCH")( + defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { + await authMiddleware(req); + return defaultHandler({ + GET: import("./_get"), + PATCH: import("./_patch"), + DELETE: import("./_delete"), + })(req, res); + }) +); diff --git a/pages/api/bookings/[id]/_auth-middleware.ts b/pages/api/bookings/[id]/_auth-middleware.ts index ead390f413..c8ea34e335 100644 --- a/pages/api/bookings/[id]/_auth-middleware.ts +++ b/pages/api/bookings/[id]/_auth-middleware.ts @@ -1,11 +1,10 @@ import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; -import { defaultResponder } from "@calcom/lib/server"; import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; -export async function authMiddleware(req: NextApiRequest) { +async function authMiddleware(req: NextApiRequest) { const { userId, prisma, isAdmin, query } = req; const { id } = schemaQueryIdParseInt.parse(query); const userWithBookings = await prisma.user.findUnique({ @@ -22,4 +21,4 @@ export async function authMiddleware(req: NextApiRequest) { } } -export default defaultResponder(authMiddleware); +export default authMiddleware; diff --git a/pages/api/bookings/[id]/index.ts b/pages/api/bookings/[id]/index.ts index 4b740bcbb5..7d92ee2906 100644 --- a/pages/api/bookings/[id]/index.ts +++ b/pages/api/bookings/[id]/index.ts @@ -1,16 +1,18 @@ import { NextApiRequest, NextApiResponse } from "next"; -import { defaultHandler } from "@calcom/lib/server"; +import { defaultHandler, defaultResponder } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import authMiddleware from "./_auth-middleware"; -export default withMiddleware("HTTP_GET_DELETE_PATCH")(async (req: NextApiRequest, res: NextApiResponse) => { - await authMiddleware(req, res); - return defaultHandler({ - GET: import("./_get"), - PATCH: import("./_patch"), - DELETE: import("./_delete"), - })(req, res); -}); +export default withMiddleware("HTTP_GET_DELETE_PATCH")( + defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { + await authMiddleware(req); + return defaultHandler({ + GET: import("./_get"), + PATCH: import("./_patch"), + DELETE: import("./_delete"), + })(req, res); + }) +); From 88332fb2ab7d9e78b694431bb2c6a0b9bd0c5e3b Mon Sep 17 00:00:00 2001 From: zomars Date: Mon, 10 Oct 2022 20:25:47 -0600 Subject: [PATCH 510/658] Refactors teams --- lib/validations/team.ts | 8 +++-- pages/api/teams/[teamId]/_auth-middleware.ts | 16 +++++++++ pages/api/teams/[teamId]/_delete.ts | 36 ++++++------------- pages/api/teams/[teamId]/_get.ts | 20 ++++------- pages/api/teams/[teamId]/_patch.ts | 38 +++++++------------- pages/api/teams/[teamId]/index.ts | 18 ++++++---- pages/api/teams/_get.ts | 19 +++------- pages/api/teams/_post.ts | 27 +++++++------- 8 files changed, 82 insertions(+), 100 deletions(-) create mode 100644 pages/api/teams/[teamId]/_auth-middleware.ts diff --git a/lib/validations/team.ts b/lib/validations/team.ts index 1efa3e84df..352b2ff431 100644 --- a/lib/validations/team.ts +++ b/lib/validations/team.ts @@ -2,10 +2,14 @@ import { z } from "zod"; import { _TeamModel as Team } from "@calcom/prisma/zod"; -export const schemaTeamBaseBodyParams = Team.omit({ id: true }).partial(); +export const schemaTeamBaseBodyParams = Team.omit({ id: true }).partial({ hideBranding: true }); const schemaTeamRequiredParams = z.object({}); -export const schemaTeamBodyParams = schemaTeamBaseBodyParams.merge(schemaTeamRequiredParams); +export const schemaTeamBodyParams = schemaTeamBaseBodyParams.merge(schemaTeamRequiredParams).strict(); + +export const schemaTeamUpdateBodyParams = schemaTeamBodyParams.partial(); export const schemaTeamReadPublic = Team.omit({}); + +export const schemaTeamsReadPublic = z.array(schemaTeamReadPublic); diff --git a/pages/api/teams/[teamId]/_auth-middleware.ts b/pages/api/teams/[teamId]/_auth-middleware.ts new file mode 100644 index 0000000000..347c3e3075 --- /dev/null +++ b/pages/api/teams/[teamId]/_auth-middleware.ts @@ -0,0 +1,16 @@ +import type { NextApiRequest } from "next"; + +import { schemaQueryTeamId } from "@lib/validations/shared/queryTeamId"; + +async function authMiddleware(req: NextApiRequest) { + const { userId, prisma, isAdmin } = req; + const { teamId } = schemaQueryTeamId.parse(req.query); + /** Admins can skip the ownership verification */ + if (isAdmin) return; + /** Non-members will see a 404 error which may or not be the desired behavior. */ + await prisma.team.findFirstOrThrow({ + where: { id: teamId, members: { some: { userId } } }, + }); +} + +export default authMiddleware; diff --git a/pages/api/teams/[teamId]/_delete.ts b/pages/api/teams/[teamId]/_delete.ts index 39b982caff..c372e5dd79 100644 --- a/pages/api/teams/[teamId]/_delete.ts +++ b/pages/api/teams/[teamId]/_delete.ts @@ -1,4 +1,4 @@ -import type { NextApiRequest, NextApiResponse } from "next"; +import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; @@ -22,36 +22,22 @@ import { schemaQueryTeamId } from "@lib/validations/shared/queryTeamId"; * - teams * responses: * 201: - * description: OK, team removed successfuly + * description: OK, team removed successfully * 400: * description: Bad request. Team id is invalid. * 401: * description: Authorization information is missing or invalid. */ -export async function deleteHandler(req: NextApiRequest, res: NextApiResponse) { - const { prisma, isAdmin, userId } = req; - - const query = schemaQueryTeamId.parse(req.query); - const userWithMemberships = await prisma.membership.findMany({ - where: { userId: userId }, +export async function deleteHandler(req: NextApiRequest) { + const { prisma, query, userId } = req; + const { teamId } = schemaQueryTeamId.parse(query); + /** Only OWNERS can delete teams */ + const _team = await prisma.team.findFirst({ + where: { id: teamId, members: { some: { userId, role: "OWNER" } } }, }); - const userTeamIds = userWithMemberships.map((membership) => membership.teamId); - // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user - if (!isAdmin && !userTeamIds.includes(query.teamId)) - throw new HttpError({ statusCode: 401, message: "Unauthorized" }); - await prisma.team - .delete({ where: { id: query.teamId } }) - .then(() => - res.status(200).json({ - message: `Team with id: ${query.teamId} deleted successfully`, - }) - ) - .catch((error: Error) => - res.status(404).json({ - message: `Team with id: ${query.teamId} not found`, - error, - }) - ); + if (!_team) throw new HttpError({ statusCode: 401, message: "Unauthorized: OWNER required" }); + await prisma.team.delete({ where: { id: teamId } }); + return { message: `Team with id: ${teamId} deleted successfully` }; } export default defaultResponder(deleteHandler); diff --git a/pages/api/teams/[teamId]/_get.ts b/pages/api/teams/[teamId]/_get.ts index b2295d40fa..34b70e6e24 100644 --- a/pages/api/teams/[teamId]/_get.ts +++ b/pages/api/teams/[teamId]/_get.ts @@ -1,6 +1,6 @@ +import type { Prisma } from "@prisma/client"; import type { NextApiRequest } from "next"; -import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; import { schemaQueryTeamId } from "@lib/validations/shared/queryTeamId"; @@ -31,18 +31,12 @@ import { schemaTeamReadPublic } from "@lib/validations/team"; */ export async function getHandler(req: NextApiRequest) { const { prisma, isAdmin, userId } = req; - - const query = schemaQueryTeamId.parse(req.query); - const userWithMemberships = await prisma.membership.findMany({ - where: { userId: userId }, - }); - const userTeamIds = userWithMemberships.map((membership) => membership.teamId); - // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user - if (!isAdmin && !userTeamIds.includes(query.teamId)) - throw new HttpError({ statusCode: 401, message: "Unauthorized" }); - const data = await prisma.team.findUnique({ where: { id: query.teamId } }); - const team = schemaTeamReadPublic.parse(data); - return { team }; + const { teamId } = schemaQueryTeamId.parse(req.query); + const where: Prisma.TeamWhereInput = { id: teamId }; + // Non-admins can only query the teams they're part of + if (!isAdmin) where.members = { some: { userId } }; + const data = await prisma.team.findFirstOrThrow({ where }); + return { team: schemaTeamReadPublic.parse(data) }; } export default defaultResponder(getHandler); diff --git a/pages/api/teams/[teamId]/_patch.ts b/pages/api/teams/[teamId]/_patch.ts index f395ca7414..a8782d5a4c 100644 --- a/pages/api/teams/[teamId]/_patch.ts +++ b/pages/api/teams/[teamId]/_patch.ts @@ -1,10 +1,10 @@ -import type { NextApiRequest, NextApiResponse } from "next"; +import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; import { schemaQueryTeamId } from "@lib/validations/shared/queryTeamId"; -import { schemaTeamBodyParams, schemaTeamReadPublic } from "@lib/validations/team"; +import { schemaTeamReadPublic, schemaTeamUpdateBodyParams } from "@lib/validations/team"; /** * @swagger @@ -23,35 +23,23 @@ import { schemaTeamBodyParams, schemaTeamReadPublic } from "@lib/validations/tea * - teams * responses: * 201: - * description: OK, team edited successfuly + * description: OK, team edited successfully * 400: * description: Bad request. Team body is invalid. * 401: * description: Authorization information is missing or invalid. */ -export async function patchHandler(req: NextApiRequest, res: NextApiResponse) { - const { prisma, isAdmin, userId, body } = req; - const safeBody = schemaTeamBodyParams.safeParse(body); - - const query = schemaQueryTeamId.parse(req.query); - const userWithMemberships = await prisma.membership.findMany({ - where: { userId: userId }, +export async function patchHandler(req: NextApiRequest) { + const { prisma, body, userId } = req; + const data = schemaTeamUpdateBodyParams.parse(body); + const { teamId } = schemaQueryTeamId.parse(req.query); + /** Only OWNERS and ADMINS can edit teams */ + const _team = await prisma.team.findFirst({ + where: { id: teamId, members: { some: { userId, role: { in: ["OWNER", "ADMIN"] } } } }, }); - const userTeamIds = userWithMemberships.map((membership) => membership.teamId); - // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user - if (!isAdmin || !userTeamIds.includes(query.teamId)) - throw new HttpError({ statusCode: 401, message: "Unauthorized" }); - if (!safeBody.success) { - { - res.status(400).json({ message: "Invalid request body" }); - return; - } - } - const data = await prisma.team.update({ where: { id: query.teamId }, data: safeBody.data }); - if (!data) throw new HttpError({ statusCode: 404, message: `Team with id: ${query.teamId} not found` }); - const team = schemaTeamReadPublic.parse(data); - if (!team) throw new HttpError({ statusCode: 401, message: `Your request body wasn't valid` }); - return { team }; + if (!_team) throw new HttpError({ statusCode: 401, message: "Unauthorized: OWNER or ADMIN required" }); + const team = await prisma.team.update({ where: { id: teamId }, data }); + return { team: schemaTeamReadPublic.parse(team) }; } export default defaultResponder(patchHandler); diff --git a/pages/api/teams/[teamId]/index.ts b/pages/api/teams/[teamId]/index.ts index 3644bbfd61..7d92ee2906 100644 --- a/pages/api/teams/[teamId]/index.ts +++ b/pages/api/teams/[teamId]/index.ts @@ -1,14 +1,18 @@ -import { defaultHandler } from "@calcom/lib/server"; +import { NextApiRequest, NextApiResponse } from "next"; + +import { defaultHandler, defaultResponder } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { withValidQueryTeamId } from "@lib/validations/shared/queryTeamId"; -export default withMiddleware()( - withValidQueryTeamId( - defaultHandler({ +import authMiddleware from "./_auth-middleware"; + +export default withMiddleware("HTTP_GET_DELETE_PATCH")( + defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { + await authMiddleware(req); + return defaultHandler({ GET: import("./_get"), PATCH: import("./_patch"), DELETE: import("./_delete"), - }) - ) + })(req, res); + }) ); diff --git a/pages/api/teams/_get.ts b/pages/api/teams/_get.ts index a716c2ec67..9e9adebcdb 100644 --- a/pages/api/teams/_get.ts +++ b/pages/api/teams/_get.ts @@ -3,7 +3,7 @@ import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; -import { schemaTeamReadPublic } from "@lib/validations/team"; +import { schemaTeamsReadPublic } from "@lib/validations/team"; /** * @swagger @@ -23,20 +23,11 @@ import { schemaTeamReadPublic } from "@lib/validations/team"; */ async function getHandler(req: NextApiRequest) { const { userId, prisma, isAdmin } = req; - const membershipWhere: Prisma.MembershipWhereInput = {}; + const where: Prisma.TeamWhereInput = {}; // If user is not ADMIN, return only his data. - if (!isAdmin) membershipWhere.userId = userId; - const userWithMemberships = await prisma.membership.findMany({ - where: membershipWhere, - }); - const teamIds = userWithMemberships.map((membership) => membership.teamId); - const teamWhere: Prisma.TeamWhereInput = {}; - - if (!isAdmin) teamWhere.id = { in: teamIds }; - - const data = await prisma.team.findMany({ where: teamWhere }); - const teams = schemaTeamReadPublic.parse(data); - return { teams }; + if (!isAdmin) where.members = { some: { userId } }; + const data = await prisma.team.findMany({ where }); + return { teams: schemaTeamsReadPublic.parse(data) }; } export default defaultResponder(getHandler); diff --git a/pages/api/teams/_post.ts b/pages/api/teams/_post.ts index 53f66d7746..54b8706d55 100644 --- a/pages/api/teams/_post.ts +++ b/pages/api/teams/_post.ts @@ -1,6 +1,5 @@ import type { NextApiRequest } from "next"; -import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; import { schemaMembershipPublic } from "@lib/validations/membership"; @@ -24,22 +23,22 @@ import { schemaTeamBodyParams, schemaTeamReadPublic } from "@lib/validations/tea */ async function postHandler(req: NextApiRequest) { const { prisma, body, userId } = req; - const safe = schemaTeamBodyParams.safeParse(body); - if (!safe.success) throw new HttpError({ statusCode: 400, message: "Invalid request body" }); - const data = await prisma.team.create({ data: safe.data }); - // We're also creating the relation membership of team ownership in this call. - const owner = await prisma.membership - .create({ - data: { userId, teamId: data.id, role: "OWNER", accepted: true }, - }) - .then((owner) => schemaMembershipPublic.parse(owner)); - const team = schemaTeamReadPublic.parse(data); - if (!team) throw new HttpError({ statusCode: 400, message: "We were not able to create your team" }); + const data = schemaTeamBodyParams.parse(body); + const team = await prisma.team.create({ + data: { + ...data, + members: { + // We're also creating the relation membership of team ownership in this call. + create: { userId, role: "OWNER", accepted: true }, + }, + }, + include: { members: true }, + }); req.statusCode = 201; // We are also returning the new ownership relation as owner besides team. return { - team, - owner, + team: schemaTeamReadPublic.parse(team), + owner: schemaMembershipPublic.parse(team.members[0]), message: "Team created successfully, we also made you the owner of this team", }; } From da618415254dbe35165559a53a7684dc9f135306 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Tue, 11 Oct 2022 08:25:57 -0600 Subject: [PATCH 511/658] Refactors booking references endpoints (#180) refs #175 --- lib/validations/booking-reference.ts | 33 +--- pages/api/booking-references/[id].ts | 181 ------------------ .../[id]/_auth-middleware.ts | 19 ++ pages/api/booking-references/[id]/_delete.ts | 37 ++++ pages/api/booking-references/[id]/_get.ts | 38 ++++ pages/api/booking-references/[id]/_patch.ts | 69 +++++++ pages/api/booking-references/[id]/index.ts | 18 ++ pages/api/booking-references/_get.ts | 31 +++ pages/api/booking-references/_post.ts | 80 ++++++++ pages/api/booking-references/index.ts | 125 +----------- 10 files changed, 303 insertions(+), 328 deletions(-) delete mode 100644 pages/api/booking-references/[id].ts create mode 100644 pages/api/booking-references/[id]/_auth-middleware.ts create mode 100644 pages/api/booking-references/[id]/_delete.ts create mode 100644 pages/api/booking-references/[id]/_get.ts create mode 100644 pages/api/booking-references/[id]/_patch.ts create mode 100644 pages/api/booking-references/[id]/index.ts create mode 100644 pages/api/booking-references/_get.ts create mode 100644 pages/api/booking-references/_post.ts diff --git a/lib/validations/booking-reference.ts b/lib/validations/booking-reference.ts index e6f90a0450..662285b690 100644 --- a/lib/validations/booking-reference.ts +++ b/lib/validations/booking-reference.ts @@ -1,6 +1,5 @@ -import { z } from "zod"; - import { _BookingReferenceModel as BookingReference } from "@calcom/prisma/zod"; +import { denullishShape } from "@calcom/prisma/zod-utils"; export const schemaBookingReferenceBaseBodyParams = BookingReference.pick({ type: true, @@ -23,31 +22,7 @@ export const schemaBookingReferenceReadPublic = BookingReference.pick({ deleted: true, }); -const schemaBookingReferenceCreateParams = z - .object({ - type: z.string(), - uid: z.string(), - meetingId: z.string(), - meetingPassword: z.string().optional(), - meetingUrl: z.string().optional(), - deleted: z.boolean(), - }) +export const schemaBookingCreateBodyParams = BookingReference.omit({ id: true, bookingId: true }) + .merge(denullishShape(BookingReference.pick({ bookingId: true }))) .strict(); - -const schemaBookingReferenceEditParams = z - .object({ - type: z.string().optional(), - uid: z.string().optional(), - meetingId: z.string().optional(), - meetingPassword: z.string().optional(), - meetingUrl: z.string().optional(), - deleted: z.boolean().optional(), - }) - .strict(); - -export const schemaBookingCreateBodyParams = schemaBookingReferenceBaseBodyParams.merge( - schemaBookingReferenceCreateParams -); -export const schemaBookingEditBodyParams = schemaBookingReferenceBaseBodyParams.merge( - schemaBookingReferenceEditParams -); +export const schemaBookingEditBodyParams = schemaBookingCreateBodyParams.partial(); diff --git a/pages/api/booking-references/[id].ts b/pages/api/booking-references/[id].ts deleted file mode 100644 index 17e444d717..0000000000 --- a/pages/api/booking-references/[id].ts +++ /dev/null @@ -1,181 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { BookingReferenceResponse } from "@lib/types"; -import { - schemaBookingEditBodyParams, - schemaBookingReferenceReadPublic, -} from "@lib/validations/booking-reference"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -export async function bookingReferenceById( - { method, query, body, userId, prisma }: NextApiRequest, - res: NextApiResponse -) { - const safeQuery = schemaQueryIdParseInt.safeParse(query); - if (!safeQuery.success) { - res.status(400).json({ message: "Your query was invalid" }); - return; - } - const userWithBookings = await prisma.user.findUnique({ - where: { id: userId }, - include: { bookings: true }, - }); - if (!userWithBookings) throw new Error("User not found"); - const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); - const bookingReferences = await prisma.bookingReference - .findMany({ where: { id: { in: userBookingIds } } }) - .then((bookingReferences) => bookingReferences.map((bookingReference) => bookingReference.id)); - - if (!bookingReferences?.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); - else { - switch (method) { - case "GET": - /** - * @swagger - * /booking-references/{id}: - * get: - * operationId: getBookingReferenceById - * summary: Find a booking reference - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the booking reference to get - * tags: - * - booking-references - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: BookingReference was not found - */ - await prisma.bookingReference - .findFirst({ where: { id: safeQuery.data.id } }) - .then((data) => schemaBookingReferenceReadPublic.parse(data)) - .then((booking_reference) => res.status(200).json({ booking_reference })) - .catch((error: Error) => { - res.status(404).json({ - message: `BookingReference with id: ${safeQuery.data.id} not found`, - error, - }); - }); - - break; - case "PATCH": - /** - * @swagger - * /booking-references/{id}: - * patch: - * operationId: editBookingReferenceById - * summary: Edit an existing booking reference - * requestBody: - * description: Edit an existing booking reference related to one of your bookings - * required: true - * content: - * application/json: - * schema: - * type: object - * properties: - * days: - * type: array - * example: email@example.com - * startTime: - * type: string - * example: 1970-01-01T17:00:00.000Z - * endTime: - * type: string - * example: 1970-01-01T17:00:00.000Z - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the booking reference to edit - * tags: - * - booking-references - * responses: - * 201: - * description: OK, safeBody.data edited successfuly - * 400: - * description: Bad request. BookingReference body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - - const safeBody = schemaBookingEditBodyParams.safeParse(body); - if (!safeBody.success) { - console.log(safeBody.error); - res.status(400).json({ message: "Invalid request body", error: safeBody.error }); - return; - } - await prisma.bookingReference - .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) - .then((data) => schemaBookingReferenceReadPublic.parse(data)) - .then((booking_reference) => res.status(200).json({ booking_reference })) - .catch((error: Error) => - res.status(404).json({ - message: `BookingReference with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - case "DELETE": - /** - * @swagger - * /booking-references/{id}: - * delete: - * operationId: removeBookingReferenceById - * summary: Remove an existing booking reference - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the booking reference to delete - * tags: - * - booking-references - * responses: - * 201: - * description: OK, bookingReference removed successfuly - * 400: - * description: Bad request. BookingReference id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - await prisma.bookingReference - .delete({ - where: { id: safeQuery.data.id }, - }) - .then(() => - res.status(200).json({ - message: `BookingReference with id: ${safeQuery.data.id} deleted`, - }) - ) - .catch((error: Error) => - res.status(404).json({ - message: `BookingReference with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } - } -} - -export default withMiddleware("HTTP_GET_DELETE_PATCH")( - withValidQueryIdTransformParseInt(bookingReferenceById) -); diff --git a/pages/api/booking-references/[id]/_auth-middleware.ts b/pages/api/booking-references/[id]/_auth-middleware.ts new file mode 100644 index 0000000000..f8a83b3bd2 --- /dev/null +++ b/pages/api/booking-references/[id]/_auth-middleware.ts @@ -0,0 +1,19 @@ +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; + +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +async function authMiddleware(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const { id } = schemaQueryIdParseInt.parse(req.query); + // Here we make sure to only return references of the user's own bookings if the user is not an admin. + if (isAdmin) return; + // Find all references where the user has bookings + const bookingReference = await prisma.bookingReference.findFirst({ + where: { id, booking: { userId } }, + }); + if (!bookingReference) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); +} + +export default authMiddleware; diff --git a/pages/api/booking-references/[id]/_delete.ts b/pages/api/booking-references/[id]/_delete.ts new file mode 100644 index 0000000000..7bc90b18b3 --- /dev/null +++ b/pages/api/booking-references/[id]/_delete.ts @@ -0,0 +1,37 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /booking-references/{id}: + * delete: + * operationId: removeBookingReferenceById + * summary: Remove an existing booking reference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the booking reference to delete + * tags: + * - booking-references + * responses: + * 201: + * description: OK, bookingReference removed successfully + * 400: + * description: Bad request. BookingReference id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdParseInt.parse(query); + await prisma.bookingReference.delete({ where: { id } }); + return { message: `BookingReference with id: ${id} deleted` }; +} + +export default defaultResponder(deleteHandler); diff --git a/pages/api/booking-references/[id]/_get.ts b/pages/api/booking-references/[id]/_get.ts new file mode 100644 index 0000000000..c78b40222a --- /dev/null +++ b/pages/api/booking-references/[id]/_get.ts @@ -0,0 +1,38 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaBookingReferenceReadPublic } from "@lib/validations/booking-reference"; +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /booking-references/{id}: + * get: + * operationId: getBookingReferenceById + * summary: Find a booking reference + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the booking reference to get + * tags: + * - booking-references + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: BookingReference was not found + */ +export async function getHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdParseInt.parse(query); + const booking_reference = await prisma.bookingReference.findUniqueOrThrow({ where: { id } }); + return { booking_reference: schemaBookingReferenceReadPublic.parse(booking_reference) }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/booking-references/[id]/_patch.ts b/pages/api/booking-references/[id]/_patch.ts new file mode 100644 index 0000000000..ccaa22000d --- /dev/null +++ b/pages/api/booking-references/[id]/_patch.ts @@ -0,0 +1,69 @@ +import type { Prisma } from "@prisma/client"; +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { + schemaBookingEditBodyParams, + schemaBookingReferenceReadPublic, +} from "@lib/validations/booking-reference"; +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /booking-references/{id}: + * patch: + * operationId: editBookingReferenceById + * summary: Edit an existing booking reference + * requestBody: + * description: Edit an existing booking reference related to one of your bookings + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * days: + * type: array + * example: email@example.com + * startTime: + * type: string + * example: 1970-01-01T17:00:00.000Z + * endTime: + * type: string + * example: 1970-01-01T17:00:00.000Z + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the booking reference to edit + * tags: + * - booking-references + * responses: + * 201: + * description: OK, safeBody.data edited successfully + * 400: + * description: Bad request. BookingReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function patchHandler(req: NextApiRequest) { + const { prisma, query, body, isAdmin, userId } = req; + const { id } = schemaQueryIdParseInt.parse(query); + const data = schemaBookingEditBodyParams.parse(body); + /* If user tries to update bookingId, we run extra checks */ + if (data.bookingId) { + const args: Prisma.BookingFindFirstOrThrowArgs = isAdmin + ? /* If admin, we only check that the booking exists */ + { where: { id: data.bookingId } } + : /* For non-admins we make sure the booking belongs to the user */ + { where: { id: data.bookingId, userId } }; + await prisma.booking.findFirstOrThrow(args); + } + const booking_reference = await prisma.bookingReference.update({ where: { id }, data }); + return { booking_reference: schemaBookingReferenceReadPublic.parse(booking_reference) }; +} + +export default defaultResponder(patchHandler); diff --git a/pages/api/booking-references/[id]/index.ts b/pages/api/booking-references/[id]/index.ts new file mode 100644 index 0000000000..7d92ee2906 --- /dev/null +++ b/pages/api/booking-references/[id]/index.ts @@ -0,0 +1,18 @@ +import { NextApiRequest, NextApiResponse } from "next"; + +import { defaultHandler, defaultResponder } from "@calcom/lib/server"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; + +import authMiddleware from "./_auth-middleware"; + +export default withMiddleware("HTTP_GET_DELETE_PATCH")( + defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { + await authMiddleware(req); + return defaultHandler({ + GET: import("./_get"), + PATCH: import("./_patch"), + DELETE: import("./_delete"), + })(req, res); + }) +); diff --git a/pages/api/booking-references/_get.ts b/pages/api/booking-references/_get.ts new file mode 100644 index 0000000000..0bf3b93b4a --- /dev/null +++ b/pages/api/booking-references/_get.ts @@ -0,0 +1,31 @@ +import type { Prisma } from "@prisma/client"; +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaBookingReferenceReadPublic } from "@lib/validations/booking-reference"; + +/** + * @swagger + * /booking-references: + * get: + * operationId: listBookingReferences + * summary: Find all booking references + * tags: + * - booking-references + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No booking references were found + */ +async function getHandler(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const args: Prisma.BookingReferenceFindManyArgs = isAdmin ? {} : { where: { booking: { userId } } }; + const data = await prisma.bookingReference.findMany(args); + return { booking_references: data.map((br) => schemaBookingReferenceReadPublic.parse(br)) }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/booking-references/_post.ts b/pages/api/booking-references/_post.ts new file mode 100644 index 0000000000..b5ed53b79d --- /dev/null +++ b/pages/api/booking-references/_post.ts @@ -0,0 +1,80 @@ +import type { Prisma } from "@prisma/client"; +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { + schemaBookingCreateBodyParams, + schemaBookingReferenceReadPublic, +} from "@lib/validations/booking-reference"; + +/** + * @swagger + * /booking-references: + * post: + * operationId: addBookingReference + * summary: Creates a new booking reference + * requestBody: + * description: Create a new booking reference related to one of your bookings + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - type + * - uid + * - meetingId + * - bookingId + * - deleted + * properties: + * deleted: + * type: boolean + * example: false + * uid: + * type: string + * example: '123456789' + * type: + * type: string + * example: email@example.com + * bookingId: + * type: number + * example: 1 + * meetingId: + * type: string + * example: 'meeting-id' + * tags: + * - booking-references + * responses: + * 201: + * description: OK, booking reference created + * 400: + * description: Bad request. BookingReference body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function postHandler(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const body = schemaBookingCreateBodyParams.parse(req.body); + const args: Prisma.BookingFindFirstOrThrowArgs = isAdmin + ? /* If admin, we only check that the booking exists */ + { where: { id: body.bookingId } } + : /* For non-admins we make sure the booking belongs to the user */ + { where: { id: body.bookingId, userId } }; + await prisma.booking.findFirstOrThrow(args); + + const data = await prisma.bookingReference.create({ + data: { + ...body, + bookingId: body.bookingId, + }, + }); + + return { + booking_reference: schemaBookingReferenceReadPublic.parse(data), + message: "Booking reference created successfully", + }; +} + +export default defaultResponder(postHandler); diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index 5c63a605b7..c07846423f 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -1,121 +1,10 @@ -import type { NextApiRequest, NextApiResponse } from "next"; +import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { BookingReferenceResponse, BookingReferencesResponse } from "@lib/types"; -import { - schemaBookingCreateBodyParams, - schemaBookingReferenceReadPublic, -} from "@lib/validations/booking-reference"; -async function createOrlistAllBookingReferences( - { method, userId, body, prisma }: NextApiRequest, - res: NextApiResponse -) { - const userWithBookings = await prisma.user.findUnique({ - where: { id: userId }, - include: { bookings: true }, - }); - if (!userWithBookings) throw new Error("User not found"); - const userBookingIds = userWithBookings.bookings.map((booking: { id: number }) => booking.id).flat(); - if (method === "GET") { - /** - * @swagger - * /booking-references: - * get: - * operationId: listBookingReferences - * summary: Find all booking references - * tags: - * - booking-references - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No booking references were found - */ - const data = await prisma.bookingReference.findMany({ where: { id: { in: userBookingIds } } }); - const booking_references = data.map((bookingReference) => - schemaBookingReferenceReadPublic.parse(bookingReference) - ); - if (booking_references) res.status(200).json({ booking_references }); - else - (error: Error) => - res.status(404).json({ - message: "No BookingReferences were found", - error, - }); - } else if (method === "POST") { - /** - * @swagger - * /booking-references: - * post: - * operationId: addBookingReference - * summary: Creates a new booking reference - * requestBody: - * description: Create a new booking reference related to one of your bookings - * required: true - * content: - * application/json: - * schema: - * type: object - * required: - * - type - * - uid - * - meetindId - * - bookingId - * - deleted - * properties: - * deleted: - * type: boolean - * example: false - * uid: - * type: string - * example: '123456789' - * type: - * type: string - * example: email@example.com - * bookingId: - * type: number - * example: 1 - * meetingId: - * type: string - * example: 'meeting-id' - * tags: - * - booking-references - * responses: - * 201: - * description: OK, booking reference created - * 400: - * description: Bad request. BookingReference body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - const safe = schemaBookingCreateBodyParams.safeParse(body); - if (!safe.success) { - res.status(400).json({ message: "Bad request. BookingReference body is invalid", error: safe.error }); - return; - } - if (!safe.data.bookingId) throw new Error("BookingReference: bookingId not found"); - if (!userBookingIds.includes(safe.data.bookingId)) res.status(401).json({ message: "Unauthorized" }); - else { - const booking_reference = await prisma.bookingReference.create({ - data: { ...safe.data }, - }); - if (booking_reference) { - res.status(201).json({ - booking_reference, - message: "BookingReference created successfully", - }); - } else { - (error: Error) => - res.status(400).json({ - message: "Could not create new booking reference", - error, - }); - } - } - } else res.status(405).json({ message: `Method ${method} not allowed` }); -} - -export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllBookingReferences); +export default withMiddleware("HTTP_GET_OR_POST")( + defaultHandler({ + GET: import("./_get"), + POST: import("./_post"), + }) +); From a506c7da33b640dcc3ba494d0c51464bcf992c6e Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Tue, 11 Oct 2022 15:33:25 +0100 Subject: [PATCH 512/658] Refactor + fix userIds filter (#179) This fix means a behaviour change to GET calls. Instead of a JSON payload, instead a filter param has been added to the URL itself. GET payloads are very unexpected in API designs, even though supported. * Todo write tests (with postman?) * Turn isAdmin logic into common middleware ```bash curl "http://localhost:3002/v1/schedules?apiKey=...&userId=2" ``` ```bash curl "http://localhost:3002/v1/schedules?apiKey=..." \ -d '{"name":"Hello", "userId": 2}' \ -H 'Content-Type: application/json' ``` --- lib/validations/schedule.ts | 8 ++ .../api/schedules/{[id].ts => [id]/index.ts} | 0 pages/api/schedules/_get.ts | 59 ++++++++ pages/api/schedules/_post.ts | 58 ++++++++ pages/api/schedules/index.ts | 132 +----------------- 5 files changed, 132 insertions(+), 125 deletions(-) rename pages/api/schedules/{[id].ts => [id]/index.ts} (100%) create mode 100644 pages/api/schedules/_get.ts create mode 100644 pages/api/schedules/_post.ts diff --git a/lib/validations/schedule.ts b/lib/validations/schedule.ts index 229ab5a14b..f8571c06c1 100644 --- a/lib/validations/schedule.ts +++ b/lib/validations/schedule.ts @@ -1,5 +1,6 @@ import { z } from "zod"; +import dayjs from "@calcom/dayjs"; import { _ScheduleModel as Schedule, _AvailabilityModel as Availability } from "@calcom/prisma/zod"; const schemaScheduleBaseBodyParams = Schedule.omit({ id: true }).partial(); @@ -26,6 +27,13 @@ export const schemaSchedulePublic = z z.object({ availability: z .array(Availability.pick({ id: true, eventTypeId: true, days: true, startTime: true, endTime: true })) + .transform((v) => + v.map((item) => ({ + ...item, + startTime: dayjs.utc(item.startTime).format("HH:mm:ss"), + endTime: dayjs.utc(item.endTime).format("HH:mm:ss"), + })) + ) .optional(), }) ); diff --git a/pages/api/schedules/[id].ts b/pages/api/schedules/[id]/index.ts similarity index 100% rename from pages/api/schedules/[id].ts rename to pages/api/schedules/[id]/index.ts diff --git a/pages/api/schedules/_get.ts b/pages/api/schedules/_get.ts new file mode 100644 index 0000000000..40d3c9a1a6 --- /dev/null +++ b/pages/api/schedules/_get.ts @@ -0,0 +1,59 @@ +import type { NextApiRequest } from "next"; +import { z } from "zod"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaSchedulePublic } from "@lib/validations/schedule"; + +export const schemaUserIds = z + .union([z.string(), z.array(z.string())]) + .transform((val) => (Array.isArray(val) ? val.map((v) => parseInt(v, 10)) : [parseInt(val, 10)])); + +/** + * @swagger + * /schedules: + * get: + * operationId: listSchedules + * summary: Find all schedules + * tags: + * - schedules + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No schedules were found + */ +async function handler({ body, prisma, userId, isAdmin, query }: NextApiRequest) { + let userIds: number[] = [userId]; + + if (!isAdmin && query.userId) { + // throw 403 Forbidden when the userId is given but user is not an admin + throw new HttpError({ statusCode: 403 }); + } + // When isAdmin && userId is given parse it and use it instead of the current (admin) user. + else if (query.userId) { + const result = schemaUserIds.safeParse(query.userId); + if (result.success && result.data) { + userIds = result.data; + } + } + + const data = await prisma.schedule.findMany({ + where: { + userId: { in: userIds }, + }, + include: { availability: true }, + ...(Array.isArray(body.userId) && { orderBy: { userId: "asc" } }), + }); + const schedules = data.map((schedule) => schemaSchedulePublic.parse(schedule)); + if (schedules) { + return { schedules }; + } + + throw new HttpError({ statusCode: 404, message: "No schedules were found" }); +} + +export default defaultResponder(handler); diff --git a/pages/api/schedules/_post.ts b/pages/api/schedules/_post.ts new file mode 100644 index 0000000000..cb6399d247 --- /dev/null +++ b/pages/api/schedules/_post.ts @@ -0,0 +1,58 @@ +import { HttpError } from "@/../../packages/lib/http-error"; +import type { NextApiRequest } from "next"; + +import { DEFAULT_SCHEDULE, getAvailabilityFromSchedule } from "@calcom/lib/availability"; +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaCreateScheduleBodyParams, schemaSchedulePublic } from "@lib/validations/schedule"; + +/** + * @swagger + * /schedules: + * post: + * operationId: addSchedule + * summary: Creates a new schedule + * tags: + * - schedules + * responses: + * 201: + * description: OK, schedule created + * 400: + * description: Bad request. Schedule body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function postHandler({ body, userId, isAdmin, prisma }: NextApiRequest) { + const parsedBody = schemaCreateScheduleBodyParams.parse(body); + if (parsedBody.userId && !isAdmin) { + throw new HttpError({ statusCode: 403 }); + } + + const data = await prisma.schedule.create({ + data: { + ...parsedBody, + userId: parsedBody.userId || userId, + availability: { + createMany: { + data: getAvailabilityFromSchedule(DEFAULT_SCHEDULE).map((schedule) => ({ + days: schedule.days, + startTime: schedule.startTime, + endTime: schedule.endTime, + })), + }, + }, + }, + }); + + const createSchedule = schemaSchedulePublic.safeParse(data); + if (!createSchedule.success) { + throw new HttpError({ statusCode: 400, message: "Could not create new schedule" }); + } + + return { + schedule: createSchedule.data, + message: "Schedule created succesfully", + }; +} + +export default defaultResponder(postHandler); diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index 10536f5cea..c07846423f 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -1,128 +1,10 @@ -import type { NextApiRequest, NextApiResponse } from "next"; +import { defaultHandler } from "@calcom/lib/server"; -import { getAvailabilityFromSchedule, DEFAULT_SCHEDULE } from "@calcom/lib/availability"; - -import safeParseJSON from "@lib/helpers/safeParseJSON"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { ScheduleResponse, SchedulesResponse } from "@lib/types"; -import { - schemaScheduleBodyParams, - schemaSchedulePublic, - schemaCreateScheduleBodyParams, -} from "@lib/validations/schedule"; -async function createOrlistAllSchedules( - { method, body, userId, isAdmin, prisma }: NextApiRequest, - res: NextApiResponse -) { - body = safeParseJSON(body); - if (body.success !== undefined && !body.success) { - res.status(400).json({ message: body.message }); - return; - } - - const safe = schemaScheduleBodyParams.safeParse(body); - - if (!safe.success) { - res.status(400).json({ message: "Bad request" }); - return; - } - - const safeBody = safe.data; - - if (safeBody.userId && !isAdmin) { - res.status(401).json({ message: "Unauthorized" }); - return; - } else { - if (method === "GET") { - /** - * @swagger - * /schedules: - * get: - * operationId: listSchedules - * summary: Find all schedules - * tags: - * - schedules - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No schedules were found - */ - - const userIds = Array.isArray(safeBody.userId) ? safeBody.userId : [safeBody.userId || userId]; - - const data = await prisma.schedule.findMany({ - where: { - userId: { in: userIds }, - }, - include: { availability: true }, - ...(Array.isArray(body.userId) && { orderBy: { userId: "asc" } }), - }); - const schedules = data.map((schedule) => schemaSchedulePublic.parse(schedule)); - if (schedules) res.status(200).json({ schedules }); - else - (error: Error) => - res.status(404).json({ - message: "No Schedules were found", - error, - }); - } else if (method === "POST") { - /** - * @swagger - * /schedules: - * post: - * operationId: addSchedule - * summary: Creates a new schedule - * tags: - * - schedules - * responses: - * 201: - * description: OK, schedule created - * 400: - * description: Bad request. Schedule body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - const safe = schemaCreateScheduleBodyParams.safeParse(body); - if (body.userId && !isAdmin) { - res.status(401).json({ message: "Unauthorized" }); - return; - } - - if (!safe.success) { - res.status(400).json({ message: "Invalid request body" }); - return; - } - - const data = await prisma.schedule.create({ - data: { - ...safe.data, - userId: safe.data.userId || userId, - availability: { - createMany: { - data: getAvailabilityFromSchedule(DEFAULT_SCHEDULE).map((schedule) => ({ - days: schedule.days, - startTime: schedule.startTime, - endTime: schedule.endTime, - })), - }, - }, - }, - }); - const schedule = schemaSchedulePublic.parse(data); - - if (schedule) res.status(201).json({ schedule, message: "Schedule created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new schedule", - error, - }); - } else res.status(405).json({ message: `Method ${method} not allowed` }); - } -} - -export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllSchedules); +export default withMiddleware("HTTP_GET_OR_POST")( + defaultHandler({ + GET: import("./_get"), + POST: import("./_post"), + }) +); From 7aeb247b1a0c651ac8017b9f3457ef94e6e2077d Mon Sep 17 00:00:00 2001 From: Hariom Balhara Date: Tue, 11 Oct 2022 20:06:18 +0530 Subject: [PATCH 513/658] Delete unused file. If needed import from @calcom/core (#156) --- lib/utils/eventName.ts | 62 ------------------------------------------ 1 file changed, 62 deletions(-) delete mode 100644 lib/utils/eventName.ts diff --git a/lib/utils/eventName.ts b/lib/utils/eventName.ts deleted file mode 100644 index 5d7865fe94..0000000000 --- a/lib/utils/eventName.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { TFunction } from "next-i18next"; - -type EventNameObjectType = { - attendeeName: string; - eventType: string; - eventName?: string | null; - host: string; - location?: string; - t: TFunction; -}; - -export function getEventName(eventNameObj: EventNameObjectType, forAttendeeView = false) { - if (!eventNameObj.eventName) - return eventNameObj.t("event_between_users", { - eventName: eventNameObj.eventType, - host: eventNameObj.host, - attendeeName: eventNameObj.attendeeName, - }); - - let eventName = eventNameObj.eventName; - let locationString = ""; - - if (eventNameObj.eventName.includes("{LOCATION}")) { - switch (eventNameObj.location) { - case "inPerson": - locationString = "In Person"; - break; - case "userPhone": - case "phone": - locationString = "Phone"; - break; - case "integrations:daily": - locationString = "Cal Video"; - break; - case "integrations:zoom": - locationString = "Zoom"; - break; - case "integrations:huddle01": - locationString = "Huddle01"; - break; - case "integrations:tandem": - locationString = "Tandem"; - break; - case "integrations:office365_video": - locationString = "MS Teams"; - break; - case "integrations:jitsi": - locationString = "Jitsi"; - break; - } - eventName = eventName.replace("{LOCATION}", locationString); - } - - return ( - eventName - // Need this for compatibility with older event names - .replace("{USER}", eventNameObj.attendeeName) - .replace("{ATTENDEE}", eventNameObj.attendeeName) - .replace("{HOST}", eventNameObj.host) - .replace("{HOST/ATTENDEE}", forAttendeeView ? eventNameObj.host : eventNameObj.attendeeName) - ); -} From 4ba0395efa5ed9bc76892b7ed2aa4b2a5d2ae462 Mon Sep 17 00:00:00 2001 From: zomars Date: Tue, 11 Oct 2022 14:09:22 -0600 Subject: [PATCH 514/658] Permission fixes --- pages/api/bookings/_get.ts | 21 +++++++++++---------- pages/api/bookings/_post.ts | 2 +- pages/api/teams/[teamId]/_delete.ts | 13 ++++++++++--- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/pages/api/bookings/_get.ts b/pages/api/bookings/_get.ts index 527af2718f..0a1b2e66c8 100644 --- a/pages/api/bookings/_get.ts +++ b/pages/api/bookings/_get.ts @@ -1,11 +1,10 @@ import { Prisma } from "@prisma/client"; -import type { NextApiRequest, NextApiResponse } from "next"; +import type { NextApiRequest } from "next"; -import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import { BookingResponse, BookingsResponse } from "@lib/types"; import { schemaBookingReadPublic } from "@lib/validations/booking"; +import { schemaQuerySingleOrMultipleUserIds } from "@lib/validations/shared/queryUserId"; /** * @swagger @@ -23,15 +22,17 @@ import { schemaBookingReadPublic } from "@lib/validations/booking"; * 404: * description: No bookings were found */ -async function handler( - { userId, isAdmin, prisma }: NextApiRequest, - res: NextApiResponse -) { +async function handler(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; const args: Prisma.BookingFindManyArgs = isAdmin ? {} : { where: { userId } }; + /** Only admins can query other users */ + if (isAdmin && req.query.userId) { + const query = schemaQuerySingleOrMultipleUserIds.parse(req.query); + const userIds = Array.isArray(query.userId) ? query.userId : [query.userId || userId]; + args.where = { userId: { in: userIds } }; + } const data = await prisma.booking.findMany(args); - const bookings = data.map((booking) => schemaBookingReadPublic.parse(booking)); - if (!bookings) throw new HttpError({ statusCode: 401, message: "No Bookings were found" }); - res.status(200).json({ bookings }); + return { bookings: data.map((booking) => schemaBookingReadPublic.parse(booking)) }; } export default defaultResponder(handler); diff --git a/pages/api/bookings/_post.ts b/pages/api/bookings/_post.ts index da7d473d39..8968d65ae7 100644 --- a/pages/api/bookings/_post.ts +++ b/pages/api/bookings/_post.ts @@ -93,7 +93,7 @@ async function handler( ); bookings = allBookings.map((book) => schemaBookingReadPublic.parse(book)); } else { - // Event type not recurring, ceating as single one + // Event type not recurring, creating as single one const data = await prisma.booking.create({ data: { uid: uuidv4(), diff --git a/pages/api/teams/[teamId]/_delete.ts b/pages/api/teams/[teamId]/_delete.ts index c372e5dd79..9b8e723a9c 100644 --- a/pages/api/teams/[teamId]/_delete.ts +++ b/pages/api/teams/[teamId]/_delete.ts @@ -29,15 +29,22 @@ import { schemaQueryTeamId } from "@lib/validations/shared/queryTeamId"; * description: Authorization information is missing or invalid. */ export async function deleteHandler(req: NextApiRequest) { - const { prisma, query, userId } = req; + const { prisma, query } = req; const { teamId } = schemaQueryTeamId.parse(query); + await checkPermissions(req); + await prisma.team.delete({ where: { id: teamId } }); + return { message: `Team with id: ${teamId} deleted successfully` }; +} + +async function checkPermissions(req: NextApiRequest) { + const { userId, prisma, isAdmin } = req; + const { teamId } = schemaQueryTeamId.parse(req.query); + if (isAdmin) return; /** Only OWNERS can delete teams */ const _team = await prisma.team.findFirst({ where: { id: teamId, members: { some: { userId, role: "OWNER" } } }, }); if (!_team) throw new HttpError({ statusCode: 401, message: "Unauthorized: OWNER required" }); - await prisma.team.delete({ where: { id: teamId } }); - return { message: `Team with id: ${teamId} deleted successfully` }; } export default defaultResponder(deleteHandler); From f13694fd1300514e219122296a4f621581e93808 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Tue, 11 Oct 2022 14:14:03 -0600 Subject: [PATCH 515/658] Refactors event-types endpoints (#181) refs #175 --- lib/validations/event-type.ts | 37 ++-- lib/validations/shared/queryUserId.ts | 12 +- pages/api/event-types/[id].ts | 172 ------------------ .../api/event-types/[id]/_auth-middleware.ts | 17 ++ pages/api/event-types/[id]/_delete.ts | 52 ++++++ pages/api/event-types/[id]/_get.ts | 44 +++++ pages/api/event-types/[id]/_patch.ts | 54 ++++++ pages/api/event-types/[id]/index.ts | 18 ++ pages/api/event-types/_get.ts | 42 +++++ pages/api/event-types/_post.ts | 79 ++++++++ pages/api/event-types/index.ts | 144 +-------------- 11 files changed, 340 insertions(+), 331 deletions(-) delete mode 100644 pages/api/event-types/[id].ts create mode 100644 pages/api/event-types/[id]/_auth-middleware.ts create mode 100644 pages/api/event-types/[id]/_delete.ts create mode 100644 pages/api/event-types/[id]/_get.ts create mode 100644 pages/api/event-types/[id]/_patch.ts create mode 100644 pages/api/event-types/[id]/index.ts create mode 100644 pages/api/event-types/_get.ts create mode 100644 pages/api/event-types/_post.ts diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 16065e668c..8cf3fece84 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -3,9 +3,19 @@ import { z } from "zod"; import { _EventTypeModel as EventType } from "@calcom/prisma/zod"; import { Frequency } from "@lib/types"; -import { timeZone } from "@lib/validations/shared/timeZone"; import { jsonSchema } from "./shared/jsonSchema"; +import { schemaQueryUserId } from "./shared/queryUserId"; +import { timeZone } from "./shared/timeZone"; + +const recurringEventInputSchema = z.object({ + dtstart: z.string().optional(), + interval: z.number().int().optional(), + count: z.number().int().optional(), + freq: z.nativeEnum(Frequency).optional(), + until: z.string().optional(), + tzid: timeZone.optional(), +}); export const schemaEventTypeBaseBodyParams = EventType.pick({ title: true, @@ -13,7 +23,6 @@ export const schemaEventTypeBaseBodyParams = EventType.pick({ length: true, hidden: true, position: true, - userId: true, teamId: true, eventName: true, timeZone: true, @@ -33,7 +42,10 @@ export const schemaEventTypeBaseBodyParams = EventType.pick({ currency: true, slotInterval: true, successRedirectUrl: true, -}).partial(); + locations: true, +}) + .partial() + .strict(); const schemaEventTypeCreateParams = z .object({ @@ -41,14 +53,14 @@ const schemaEventTypeCreateParams = z slug: z.string(), description: z.string().optional().nullable(), length: z.number().int(), - locations: jsonSchema.optional(), metadata: z.any().optional(), - recurringEvent: jsonSchema.optional(), + recurringEvent: recurringEventInputSchema.optional(), }) .strict(); -export const schemaEventTypeCreateBodyParams = - schemaEventTypeBaseBodyParams.merge(schemaEventTypeCreateParams); +export const schemaEventTypeCreateBodyParams = schemaEventTypeBaseBodyParams + .merge(schemaEventTypeCreateParams) + .merge(schemaQueryUserId.partial()); const schemaEventTypeEditParams = z .object({ @@ -92,17 +104,6 @@ export const schemaEventTypeReadPublic = EventType.pick({ metadata: true, }).merge( z.object({ - recurringEvent: z - .object({ - dtstart: z.date().optional(), - interval: z.number().int().optional(), - count: z.number().int().optional(), - freq: z.nativeEnum(Frequency).optional(), - until: z.date().optional(), - tzid: timeZone.optional(), - }) - .optional() - .nullable(), locations: z .array( z.object({ diff --git a/lib/validations/shared/queryUserId.ts b/lib/validations/shared/queryUserId.ts index 94a7700003..94de53a214 100644 --- a/lib/validations/shared/queryUserId.ts +++ b/lib/validations/shared/queryUserId.ts @@ -1,18 +1,22 @@ import { withValidation } from "next-validations"; import { z } from "zod"; +import { stringOrNumber } from "@calcom/prisma/zod-utils"; + import { baseApiParams } from "./baseApiParams"; // Extracted out as utility function so can be reused // at different endpoints that require this validation. export const schemaQueryUserId = baseApiParams .extend({ - userId: z - .string() - .regex(/^\d+$/) - .transform((id) => parseInt(id)), + userId: stringOrNumber, }) .strict(); + +export const schemaQuerySingleOrMultipleUserIds = z.object({ + userId: z.union([stringOrNumber, z.array(stringOrNumber)]), +}); + export const withValidQueryUserId = withValidation({ schema: schemaQueryUserId, type: "Zod", diff --git a/pages/api/event-types/[id].ts b/pages/api/event-types/[id].ts deleted file mode 100644 index bd8c823489..0000000000 --- a/pages/api/event-types/[id].ts +++ /dev/null @@ -1,172 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { EventTypeResponse } from "@lib/types"; -import { schemaEventTypeEditBodyParams, schemaEventTypeReadPublic } from "@lib/validations/event-type"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -export async function eventTypeById( - { method, query, body, userId, isAdmin, prisma }: NextApiRequest, - res: NextApiResponse -) { - if (body.userId && !isAdmin) { - res.status(401).json({ message: "Unauthorized" }); - return; - } - const safeQuery = schemaQueryIdParseInt.safeParse(query); - if (!safeQuery.success) { - res.status(400).json({ message: "Your query was invalid" }); - return; - } - const data = await prisma.user.findUnique({ - where: { id: body.userId || userId }, - rejectOnNotFound: true, - select: { eventTypes: true }, - }); - const userEventTypes = data.eventTypes.map((eventType) => eventType.id); - if (!userEventTypes.includes(safeQuery.data.id)) { - res.status(401).json({ message: "Unauthorized" }); - return; - } else { - switch (method) { - /** - * @swagger - * /event-types/{id}: - * get: - * operationId: getEventTypeById - * summary: Find a eventType - * parameters: - * - in: path - * name: id - * example: 4 - * schema: - * type: integer - * required: true - * description: ID of the eventType to get - * security: - * - ApiKeyAuth: [] - * tags: - * - event-types - * externalDocs: - * url: https://docs.cal.com/event-types - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: EventType was not found - */ - case "GET": - await prisma.eventType - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaEventTypeReadPublic.parse(data)) - .then((event_type) => res.status(200).json({ event_type })) - .catch((error: Error) => - res.status(404).json({ - message: `EventType with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - /** - * @swagger - * /event-types/{id}: - * patch: - * operationId: editEventTypeById - * summary: Edit an existing eventType - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the eventType to edit - * security: - * - ApiKeyAuth: [] - * tags: - * - event-types - * externalDocs: - * url: https://docs.cal.com/event-types - * responses: - * 201: - * description: OK, eventType edited successfuly - * 400: - * description: Bad request. EventType body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - case "PATCH": - const safeBody = schemaEventTypeEditBodyParams.safeParse(body); - - if (!safeBody.success) { - { - res.status(400).json({ message: "Invalid request body" }); - return; - } - } - await prisma.eventType - .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) - .then((data) => schemaEventTypeReadPublic.parse(data)) - .then((event_type) => res.status(200).json({ event_type })) - .catch((error: Error) => - res.status(404).json({ - message: `EventType with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - /** - * @swagger - * /event-types/{id}: - * delete: - * operationId: removeEventTypeById - * summary: Remove an existing eventType - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the eventType to delete - * security: - * - ApiKeyAuth: [] - * tags: - * - event-types - * externalDocs: - * url: https://docs.cal.com/event-types - * responses: - * 201: - * description: OK, eventType removed successfuly - * 400: - * description: Bad request. EventType id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - case "DELETE": - await prisma.eventType - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ - message: `EventType with id: ${safeQuery.data.id} deleted`, - }) - ) - .catch((error: Error) => - res.status(404).json({ - message: `EventType with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } - } -} - -export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(eventTypeById)); diff --git a/pages/api/event-types/[id]/_auth-middleware.ts b/pages/api/event-types/[id]/_auth-middleware.ts new file mode 100644 index 0000000000..dd5fc90109 --- /dev/null +++ b/pages/api/event-types/[id]/_auth-middleware.ts @@ -0,0 +1,17 @@ +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; + +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +async function authMiddleware(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const { id } = schemaQueryIdParseInt.parse(req.query); + if (isAdmin) return; + const eventType = await prisma.eventType.findFirst({ + where: { id, users: { some: { id: userId } } }, + }); + if (!eventType) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); +} + +export default authMiddleware; diff --git a/pages/api/event-types/[id]/_delete.ts b/pages/api/event-types/[id]/_delete.ts new file mode 100644 index 0000000000..a4fbec2e2b --- /dev/null +++ b/pages/api/event-types/[id]/_delete.ts @@ -0,0 +1,52 @@ +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /event-types/{id}: + * delete: + * operationId: removeEventTypeById + * summary: Remove an existing eventType + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the eventType to delete + * security: + * - ApiKeyAuth: [] + * tags: + * - event-types + * externalDocs: + * url: https://docs.cal.com/event-types + * responses: + * 201: + * description: OK, eventType removed successfully + * 400: + * description: Bad request. EventType id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdParseInt.parse(query); + await checkPermissions(req); + await prisma.eventType.delete({ where: { id } }); + return { message: `Event Type with id: ${id} deleted successfully` }; +} + +async function checkPermissions(req: NextApiRequest) { + const { userId, prisma, isAdmin } = req; + const { id } = schemaQueryIdParseInt.parse(req.query); + if (isAdmin) return; + /** Only event type owners can delete it */ + const eventType = await prisma.eventType.findFirst({ where: { id, userId } }); + if (!eventType) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); +} + +export default defaultResponder(deleteHandler); diff --git a/pages/api/event-types/[id]/_get.ts b/pages/api/event-types/[id]/_get.ts new file mode 100644 index 0000000000..5e91666eed --- /dev/null +++ b/pages/api/event-types/[id]/_get.ts @@ -0,0 +1,44 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaAttendeeReadPublic } from "@lib/validations/attendee"; +import { schemaEventTypeReadPublic } from "@lib/validations/event-type"; +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /event-types/{id}: + * get: + * operationId: getEventTypeById + * summary: Find a eventType + * parameters: + * - in: path + * name: id + * example: 4 + * schema: + * type: integer + * required: true + * description: ID of the eventType to get + * security: + * - ApiKeyAuth: [] + * tags: + * - event-types + * externalDocs: + * url: https://docs.cal.com/event-types + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: EventType was not found + */ +export async function getHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdParseInt.parse(query); + const event_type = await prisma.eventType.findUnique({ where: { id } }); + return { event_type: schemaEventTypeReadPublic.parse(event_type) }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/event-types/[id]/_patch.ts b/pages/api/event-types/[id]/_patch.ts new file mode 100644 index 0000000000..28956e15df --- /dev/null +++ b/pages/api/event-types/[id]/_patch.ts @@ -0,0 +1,54 @@ +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaEventTypeEditBodyParams, schemaEventTypeReadPublic } from "@lib/validations/event-type"; +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /event-types/{id}: + * patch: + * operationId: editEventTypeById + * summary: Edit an existing eventType + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the eventType to edit + * security: + * - ApiKeyAuth: [] + * tags: + * - event-types + * externalDocs: + * url: https://docs.cal.com/event-types + * responses: + * 201: + * description: OK, eventType edited successfully + * 400: + * description: Bad request. EventType body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function patchHandler(req: NextApiRequest) { + const { prisma, query, body } = req; + const { id } = schemaQueryIdParseInt.parse(query); + const data = schemaEventTypeEditBodyParams.parse(body); + await checkPermissions(req); + const event_type = await prisma.eventType.update({ where: { id }, data }); + return { event_type: schemaEventTypeReadPublic.parse(event_type) }; +} + +async function checkPermissions(req: NextApiRequest) { + const { userId, prisma, isAdmin } = req; + const { id } = schemaQueryIdParseInt.parse(req.query); + if (isAdmin) return; + /** Only event type owners can modify it */ + const eventType = await prisma.eventType.findFirst({ where: { id, userId } }); + if (!eventType) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); +} + +export default defaultResponder(patchHandler); diff --git a/pages/api/event-types/[id]/index.ts b/pages/api/event-types/[id]/index.ts new file mode 100644 index 0000000000..7d92ee2906 --- /dev/null +++ b/pages/api/event-types/[id]/index.ts @@ -0,0 +1,18 @@ +import { NextApiRequest, NextApiResponse } from "next"; + +import { defaultHandler, defaultResponder } from "@calcom/lib/server"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; + +import authMiddleware from "./_auth-middleware"; + +export default withMiddleware("HTTP_GET_DELETE_PATCH")( + defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { + await authMiddleware(req); + return defaultHandler({ + GET: import("./_get"), + PATCH: import("./_patch"), + DELETE: import("./_delete"), + })(req, res); + }) +); diff --git a/pages/api/event-types/_get.ts b/pages/api/event-types/_get.ts new file mode 100644 index 0000000000..3a3b968b8b --- /dev/null +++ b/pages/api/event-types/_get.ts @@ -0,0 +1,42 @@ +import type { Prisma } from "@prisma/client"; +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaEventTypeReadPublic } from "@lib/validations/event-type"; +import { schemaQuerySingleOrMultipleUserIds } from "@lib/validations/shared/queryUserId"; + +/** + * @swagger + * /event-types: + * get: + * summary: Find all event types + * operationId: listEventTypes + * tags: + * - event-types + * externalDocs: + * url: https://docs.cal.com/event-types + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No event types were found + */ +async function getHandler(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const args: Prisma.EventTypeFindManyArgs = isAdmin ? {} : { where: { userId } }; + /** Only admins can query other users */ + if (!isAdmin && req.query.userId) throw new HttpError({ statusCode: 401, message: "ADMIN required" }); + if (isAdmin && req.query.userId) { + const query = schemaQuerySingleOrMultipleUserIds.parse(req.query); + const userIds = Array.isArray(query.userId) ? query.userId : [query.userId || userId]; + args.where = { userId: { in: userIds } }; + } + const data = await prisma.eventType.findMany(args); + return { event_types: data.map((attendee) => schemaEventTypeReadPublic.parse(attendee)) }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/event-types/_post.ts b/pages/api/event-types/_post.ts new file mode 100644 index 0000000000..75faa6d5c0 --- /dev/null +++ b/pages/api/event-types/_post.ts @@ -0,0 +1,79 @@ +import { HttpError } from "@/../../packages/lib/http-error"; +import type { Prisma } from "@prisma/client"; +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaEventTypeCreateBodyParams, schemaEventTypeReadPublic } from "@lib/validations/event-type"; + +/** + * @swagger + * /event-types: + * post: + * summary: Creates a new event type + * operationId: addEventType + * requestBody: + * description: Create a new event-type related to your user or team + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - title + * - slug + * - length + * - metadata + * properties: + * length: + * type: number + * example: 30 + * metadata: + * type: object + * example: {"smartContractAddress": "0x1234567890123456789012345678901234567890"} + * title: + * type: string + * example: My Event + * slug: + * type: string + * example: my-event + * tags: + * - event-types + * externalDocs: + * url: https://docs.cal.com/event-types + * responses: + * 201: + * description: OK, event type created + * 400: + * description: Bad request. EventType body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function postHandler(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const body = schemaEventTypeCreateBodyParams.parse(req.body); + let args: Prisma.EventTypeCreateArgs = { data: { ...body, userId, users: { connect: { id: userId } } } }; + + await checkPermissions(req); + + if (isAdmin && body.userId) args = { data: { ...body, users: { connect: { id: body.userId } } } }; + + const data = await prisma.eventType.create(args); + + return { + event_type: schemaEventTypeReadPublic.parse(data), + message: "Event type created successfully", + }; +} + +async function checkPermissions(req: NextApiRequest) { + const { isAdmin } = req; + const body = schemaEventTypeCreateBodyParams.parse(req.body); + /* Non-admin users can only create event types for themselves */ + if (!isAdmin && body.userId) + throw new HttpError({ statusCode: 401, message: "ADMIN required for `userId`" }); + /* Admin users are required to pass in a userId */ + if (isAdmin && !body.userId) throw new HttpError({ statusCode: 400, message: "`userId` required" }); +} + +export default defaultResponder(postHandler); diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index d5a203e67d..c07846423f 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -1,140 +1,10 @@ -import type { NextApiRequest, NextApiResponse } from "next"; +import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { EventTypeResponse, EventTypesResponse } from "@lib/types"; -import { schemaEventTypeCreateBodyParams, schemaEventTypeReadPublic } from "@lib/validations/event-type"; -async function createOrlistAllEventTypes( - { method, body, userId, isAdmin, prisma }: NextApiRequest, - res: NextApiResponse -) { - if (method === "GET") { - /** - * @swagger - * /event-types: - * get: - * summary: Find all event types - * operationId: listEventTypes - * tags: - * - event-types - * externalDocs: - * url: https://docs.cal.com/event-types - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No event types were found - */ - if (!isAdmin) { - const data = await prisma.user - .findUnique({ - where: { id: userId }, - rejectOnNotFound: true, - select: { eventTypes: true }, - }) - .catch((error) => res.status(404).json({ message: "No event types were found", error })); - // @todo: add validations back schemaReadEventType.parse - if (data) res.status(200).json({ event_types: data.eventTypes }); - else - (error: Error) => - res.status(404).json({ - message: "No EventTypes were found", - error, - }); - } else { - const data = await prisma.eventType.findMany({ - where: { - ...(Array.isArray(body.userId) - ? { userId: { in: body.userId } } - : { userId: body.userId || userId }), - }, - ...(Array.isArray(body.userId) && { orderBy: { userId: "asc" } }), - }); - const event_types = data.map((eventType) => schemaEventTypeReadPublic.parse(eventType)); - if (event_types) res.status(200).json({ event_types }); - } - } else if (method === "POST") { - /** - * @swagger - * /event-types: - * post: - * summary: Creates a new event type - * operationId: addEventType - * requestBody: - * description: Create a new event-type related to your user or team - * required: true - * content: - * application/json: - * schema: - * type: object - * required: - * - title - * - slug - * - length - * - metadata - * properties: - * length: - * type: number - * example: 30 - * metadata: - * type: object - * example: {"smartContractAddress": "0x1234567890123456789012345678901234567890"} - * title: - * type: string - * example: My Event - * slug: - * type: string - * example: my-event - * tags: - * - event-types - * externalDocs: - * url: https://docs.cal.com/event-types - * responses: - * 201: - * description: OK, event type created - * 400: - * description: Bad request. EventType body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - const safe = schemaEventTypeCreateBodyParams.safeParse(body); - if (!safe.success) { - res.status(400).json({ message: "Invalid request body", error: safe.error }); - return; - } - if (!isAdmin) { - const data = await prisma.eventType.create({ - data: { - ...safe.data, - userId, - users: { - connect: { - id: userId, - }, - }, - }, - }); - const event_type = schemaEventTypeReadPublic.parse(data); - if (data) res.status(201).json({ event_type, message: "EventType created successfully" }); - } else { - // if admin don't re-set userId from input - const data = await prisma.eventType.create({ - data: { - ...safe.data, - ...(!safe.data.userId && { userId }), - users: { - connect: { - id: safe.data.userId || userId, - }, - }, - }, - }); - const event_type = schemaEventTypeReadPublic.parse(data); - if (data) res.status(201).json({ event_type, message: "EventType created successfully" }); - } - } else res.status(405).json({ message: `Method ${method} not allowed` }); -} - -export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllEventTypes); +export default withMiddleware("HTTP_GET_OR_POST")( + defaultHandler({ + GET: import("./_get"), + POST: import("./_post"), + }) +); From 8c24c5c714a39c037e405d858d7e335caafe5df5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Thu, 13 Oct 2022 12:29:30 -0600 Subject: [PATCH 516/658] Refactor/booking logic (#183) refs #175 Reuses the same logic for creating bookings from the web app. Co-authored-by: Leo Giovanetti --- lib/utils/sendPayload.ts | 79 ------------------ lib/utils/webhookSubscriptions.ts | 40 ---------- lib/validations/booking.ts | 16 ++-- next-i18next.config.js | 10 +++ next.config.js | 2 + pages/api/bookings/[id]/_patch.ts | 2 +- pages/api/bookings/_post.ts | 128 ++---------------------------- test/lib/bookings/_post.test.ts | 76 ++++++++++++++---- tsconfig.json | 1 + 9 files changed, 88 insertions(+), 266 deletions(-) delete mode 100644 lib/utils/sendPayload.ts delete mode 100644 lib/utils/webhookSubscriptions.ts create mode 100644 next-i18next.config.js diff --git a/lib/utils/sendPayload.ts b/lib/utils/sendPayload.ts deleted file mode 100644 index e8d29a2d6d..0000000000 --- a/lib/utils/sendPayload.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -import { Webhook } from "@prisma/client"; -import { compile } from "handlebars"; - -// import type { CalendarEvent } from "@calcom/types/Calendar"; Add this to make it strict, change data: any to CalendarEvent type - -type ContentType = "application/json" | "application/x-www-form-urlencoded"; - -function applyTemplate(template: string, data: any, contentType: ContentType) { - const compiled = compile(template)(data); - if (contentType === "application/json") { - return JSON.stringify(jsonParse(compiled)); - } - return compiled; -} - -function jsonParse(jsonString: string) { - try { - return JSON.parse(jsonString); - } catch (e) { - // don't do anything. - console.error(`error jsonParsing in sendPayload`); - } - return false; -} - -const sendPayload = async ( - triggerEvent: string, - createdAt: string, - webhook: Pick, - data: any & { - metadata?: { [key: string]: string }; - rescheduleUid?: string; - bookingId?: number; - } -) => { - const { subscriberUrl, appId, payloadTemplate: template } = webhook; - if (!subscriberUrl || !data) { - throw new Error("Missing required elements to send webhook payload."); - } - - const contentType = - !template || jsonParse(template) ? "application/json" : "application/x-www-form-urlencoded"; - - data.description = data.description || data.additionalNotes; - - let body; - - /* Zapier id is hardcoded in the DB, we send the raw data for this case */ - if (appId === "zapier") { - body = JSON.stringify(data); - } else if (template) { - body = applyTemplate(template, data, contentType); - } else { - body = JSON.stringify({ - triggerEvent: triggerEvent, - createdAt: createdAt, - payload: data, - }); - } - - const response = await fetch(subscriberUrl, { - method: "POST", - headers: { - "Content-Type": contentType, - }, - body, - }); - - const text = await response.text(); - - return { - ok: response.ok, - status: response.status, - message: text, - }; -}; - -export default sendPayload; diff --git a/lib/utils/webhookSubscriptions.ts b/lib/utils/webhookSubscriptions.ts deleted file mode 100644 index 51de834f2d..0000000000 --- a/lib/utils/webhookSubscriptions.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { WebhookTriggerEvents, PrismaClient } from "@prisma/client"; - -export type GetSubscriberOptions = { - userId: number; - eventTypeId: number; - triggerEvent: WebhookTriggerEvents; -}; - -const getWebhooks = async (options: GetSubscriberOptions, prisma: PrismaClient) => { - const { userId, eventTypeId } = options; - const allWebhooks = await prisma.webhook.findMany({ - where: { - OR: [ - { - userId, - }, - { - eventTypeId, - }, - ], - AND: { - eventTriggers: { - has: options.triggerEvent, - }, - active: { - equals: true, - }, - }, - }, - select: { - subscriberUrl: true, - payloadTemplate: true, - appId: true, - }, - }); - - return allWebhooks; -}; - -export default getWebhooks; diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index 25e580059d..d5ee93da3e 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -1,8 +1,12 @@ import { z } from "zod"; import { _BookingModel as Booking } from "@calcom/prisma/zod"; +import { extendedBookingCreateBody } from "@calcom/prisma/zod-utils"; + +import { schemaQueryUserId } from "./shared/queryUserId"; const schemaBookingBaseBodyParams = Booking.pick({ + uid: true, userId: true, eventTypeId: true, title: true, @@ -10,17 +14,7 @@ const schemaBookingBaseBodyParams = Booking.pick({ endTime: true, }).partial(); -const schemaBookingCreateParams = z - .object({ - eventTypeId: z.number(), - title: z.string(), - startTime: z.date().or(z.string()), - endTime: z.date().or(z.string()), - recurringCount: z.number().optional(), - }) - .strict(); - -export const schemaBookingCreateBodyParams = schemaBookingBaseBodyParams.merge(schemaBookingCreateParams); +export const schemaBookingCreateBodyParams = extendedBookingCreateBody.merge(schemaQueryUserId.partial()); const schemaBookingEditParams = z .object({ diff --git a/next-i18next.config.js b/next-i18next.config.js new file mode 100644 index 0000000000..402b72363c --- /dev/null +++ b/next-i18next.config.js @@ -0,0 +1,10 @@ +const path = require("path"); +const i18nConfig = require("@calcom/config/next-i18next.config"); + +/** @type {import("next-i18next").UserConfig} */ +const config = { + ...i18nConfig, + localePath: path.resolve("../web/public/static/locales"), +}; + +module.exports = config; diff --git a/next.config.js b/next.config.js index 1031c0a949..9662874748 100644 --- a/next.config.js +++ b/next.config.js @@ -14,9 +14,11 @@ const withTM = require("next-transpile-modules")([ "@calcom/ui", ]); const { withAxiom } = require("next-axiom"); +const { i18n } = require("./next-i18next.config"); module.exports = withAxiom( withTM({ + i18n, async rewrites() { return { afterFiles: [ diff --git a/pages/api/bookings/[id]/_patch.ts b/pages/api/bookings/[id]/_patch.ts index d2700ae229..b47c4d20e1 100644 --- a/pages/api/bookings/[id]/_patch.ts +++ b/pages/api/bookings/[id]/_patch.ts @@ -39,7 +39,7 @@ import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformP * - bookings * responses: * 201: - * description: OK, booking edited successfuly + * description: OK, booking edited successfully * 400: * description: Bad request. Booking body is invalid. * 401: diff --git a/pages/api/bookings/_post.ts b/pages/api/bookings/_post.ts index 8968d65ae7..b76397d4a4 100644 --- a/pages/api/bookings/_post.ts +++ b/pages/api/bookings/_post.ts @@ -1,14 +1,6 @@ -import { HttpError } from "@/../../packages/lib/http-error"; -import { WebhookTriggerEvents } from "@prisma/client"; -import type { NextApiRequest, NextApiResponse } from "next"; -import { v4 as uuidv4 } from "uuid"; -import z from "zod"; +import type { NextApiRequest } from "next"; -import { BookingResponse, BookingsResponse } from "@calcom/api/lib/types"; -import sendPayload from "@calcom/api/lib/utils/sendPayload"; -import getWebhooks from "@calcom/api/lib/utils/webhookSubscriptions"; -import { schemaBookingCreateBodyParams, schemaBookingReadPublic } from "@calcom/api/lib/validations/booking"; -import { schemaEventTypeReadPublic } from "@calcom/api/lib/validations/event-type"; +import handleNewBooking from "@calcom/features/bookings/lib/handleNewBooking"; import { defaultResponder } from "@calcom/lib/server"; /** @@ -53,117 +45,11 @@ import { defaultResponder } from "@calcom/lib/server"; * 401: * description: Authorization information is missing or invalid. */ -async function handler( - { body, userId, isAdmin, prisma }: NextApiRequest, - res: NextApiResponse -) { - const booking = schemaBookingCreateBodyParams.parse(body); - if (!isAdmin) { - booking.userId = userId; - } - const eventTypeDb = await prisma.eventType.findUnique({ - where: { id: booking.eventTypeId }, - }); - if (!eventTypeDb) throw new HttpError({ statusCode: 400, message: "Invalid eventTypeId." }); - const eventType = schemaEventTypeReadPublic.parse(eventTypeDb); - let bookings: z.infer[]; - if (!eventType) throw new HttpError({ statusCode: 400, message: "Could not create new booking" }); - if (eventType.recurringEvent) { - console.log("Event type has recurring configuration"); - if (!booking.recurringCount) throw new HttpError({ statusCode: 400, message: "Missing recurringCount." }); - if (eventType.recurringEvent.count && booking.recurringCount > eventType?.recurringEvent.count) { - throw new HttpError({ statusCode: 400, message: "Invalid recurringCount." }); - } - // Event type is recurring, ceating each booking - const recurringEventId = uuidv4(); - const allBookings = await Promise.all( - Array.from(Array(booking.recurringCount).keys()).map(async () => { - return await prisma.booking.create({ - data: { - uid: uuidv4(), - recurringEventId, - eventTypeId: booking.eventTypeId, - title: booking.title, - startTime: booking.startTime, - endTime: booking.endTime, - userId: booking.userId, - }, - }); - }) - ); - bookings = allBookings.map((book) => schemaBookingReadPublic.parse(book)); - } else { - // Event type not recurring, creating as single one - const data = await prisma.booking.create({ - data: { - uid: uuidv4(), - eventTypeId: booking.eventTypeId, - title: booking.title, - startTime: booking.startTime, - endTime: booking.endTime, - userId: booking.userId, - }, - }); - bookings = [schemaBookingReadPublic.parse(data)]; - } - - await Promise.all( - bookings.map(async (booking) => { - const evt = { - type: eventType?.title || booking.title, - title: booking.title, - description: "", - additionalNotes: "", - customInputs: {}, - startTime: booking.startTime.toISOString(), - endTime: booking.endTime.toISOString(), - organizer: { - name: "", - email: "", - timeZone: "", - language: { - locale: "en", - }, - }, - attendees: [], - location: "", - destinationCalendar: null, - hideCalendar: false, - uid: booking.uid, - metadata: {}, - }; - console.log(`evt: ${evt}`); - - // Send Webhook call if hooked to BOOKING_CREATED - const triggerEvent = WebhookTriggerEvents.BOOKING_CREATED; - console.log(`Trigger Event: ${triggerEvent}`); - const subscriberOptions = { - userId, - eventTypeId: booking.eventTypeId as number, - triggerEvent, - }; - console.log(`subscriberOptions: ${subscriberOptions}`); - - const subscribers = await getWebhooks(subscriberOptions, prisma); - console.log(`subscribers: ${subscribers}`); - const bookingId = booking?.id; - await Promise.all( - subscribers.map((sub) => - sendPayload(triggerEvent, new Date().toISOString(), sub, { - ...evt, - bookingId, - }) - ) - ); - console.log("All promises resolved! About to send the response"); - }) - ); - - if (bookings.length > 1) { - res.status(201).json({ bookings, message: "Bookings created successfully." }); - } else { - res.status(201).json({ booking: bookings[0], message: "Booking created successfully." }); - } +async function handler(req: NextApiRequest) { + const { userId, isAdmin } = req; + if (isAdmin) req.userId = req.body.userId || userId; + const booking = await handleNewBooking(req); + return booking; } export default defaultResponder(handler); diff --git a/test/lib/bookings/_post.test.ts b/test/lib/bookings/_post.test.ts index 1fc3d0d108..8ba3295e79 100644 --- a/test/lib/bookings/_post.test.ts +++ b/test/lib/bookings/_post.test.ts @@ -1,19 +1,23 @@ -import { Booking, WebhookTriggerEvents } from "@prisma/client"; import { Request, Response } from "express"; import { NextApiRequest, NextApiResponse } from "next"; import { createMocks } from "node-mocks-http"; -import sendPayload from "@calcom/api/lib/utils/sendPayload"; -import handler from "@calcom/api/pages/api/bookings/_post"; import dayjs from "@calcom/dayjs"; -import { buildEventType, buildWebhook, buildBooking } from "@calcom/lib/test/builder"; +import sendPayload from "@calcom/features/webhooks/lib/sendPayload"; +import { buildBooking, buildEventType, buildWebhook, buildUser } from "@calcom/lib/test/builder"; import prisma from "@calcom/prisma"; import { prismaMock } from "../../../../../tests/config/singleton"; +import handler from "../../../pages/api/bookings/_post"; type CustomNextApiRequest = NextApiRequest & Request; type CustomNextApiResponse = NextApiResponse & Response; -jest.mock("@calcom/api/lib/utils/sendPayload"); +jest.mock("@calcom/features/webhooks/lib/sendPayload"); +jest.mock("@calcom/lib/server/i18n", () => { + return { + getTranslation: (key: string) => key, + }; +}); describe("POST /api/bookings", () => { describe("Errors", () => { @@ -29,7 +33,7 @@ describe("POST /api/bookings", () => { expect(JSON.parse(res._getData())).toEqual( expect.objectContaining({ message: - "'invalid_type' in 'eventTypeId': Required; 'invalid_type' in 'title': Required; 'invalid_type' in 'startTime': Required; 'invalid_type' in 'startTime': Required; 'invalid_type' in 'endTime': Required; 'invalid_type' in 'endTime': Required", + "'invalid_type' in 'email': Required; 'invalid_type' in 'end': Required; 'invalid_type' in 'eventTypeId': Required; 'invalid_type' in 'location': Required; 'invalid_type' in 'name': Required; 'invalid_type' in 'start': Required; 'invalid_type' in 'timeZone': Required; 'invalid_type' in 'language': Required; 'invalid_type' in 'customInputs': Required; 'invalid_type' in 'metadata': Required", }) ); }); @@ -53,7 +57,8 @@ describe("POST /api/bookings", () => { expect(res._getStatusCode()).toBe(400); expect(JSON.parse(res._getData())).toEqual( expect.objectContaining({ - message: "Invalid eventTypeId.", + message: + "'invalid_type' in 'email': Required; 'invalid_type' in 'end': Required; 'invalid_type' in 'location': Required; 'invalid_type' in 'name': Required; 'invalid_type' in 'start': Required; 'invalid_type' in 'timeZone': Required; 'invalid_type' in 'language': Required; 'invalid_type' in 'customInputs': Required; 'invalid_type' in 'metadata': Required", }) ); }); @@ -79,7 +84,8 @@ describe("POST /api/bookings", () => { expect(res._getStatusCode()).toBe(400); expect(JSON.parse(res._getData())).toEqual( expect.objectContaining({ - message: "Missing recurringCount.", + message: + "'invalid_type' in 'email': Required; 'invalid_type' in 'end': Required; 'invalid_type' in 'location': Required; 'invalid_type' in 'name': Required; 'invalid_type' in 'start': Required; 'invalid_type' in 'timeZone': Required; 'invalid_type' in 'language': Required; 'invalid_type' in 'customInputs': Required; 'invalid_type' in 'metadata': Required", }) ); }); @@ -106,29 +112,71 @@ describe("POST /api/bookings", () => { expect(res._getStatusCode()).toBe(400); expect(JSON.parse(res._getData())).toEqual( expect.objectContaining({ - message: "Invalid recurringCount.", + message: + "'invalid_type' in 'email': Required; 'invalid_type' in 'end': Required; 'invalid_type' in 'location': Required; 'invalid_type' in 'name': Required; 'invalid_type' in 'start': Required; 'invalid_type' in 'timeZone': Required; 'invalid_type' in 'language': Required; 'invalid_type' in 'customInputs': Required; 'invalid_type' in 'metadata': Required", + }) + ); + }); + + test("No available users", async () => { + const { req, res } = createMocks({ + method: "POST", + body: { + name: "test", + start: dayjs().format(), + end: dayjs().add(1, "day").format(), + eventTypeId: 2, + email: "test@example.com", + location: "Cal.com Video", + timeZone: "America/Montevideo", + language: "en", + customInputs: [], + metadata: {}, + userId: 4, + }, + prisma, + }); + + prismaMock.eventType.findUniqueOrThrow.mockResolvedValue(buildEventType({ users: [] })); + + await handler(req, res); + console.log({ statusCode: res._getStatusCode(), data: JSON.parse(res._getData()) }); + + expect(res._getStatusCode()).toBe(500); + expect(JSON.parse(res._getData())).toEqual( + expect.objectContaining({ + message: "No available users found.", }) ); }); }); - describe("Success", () => { + xdescribe("Success", () => { describe("Regular event-type", () => { test("Creates one single booking", async () => { const { req, res } = createMocks({ method: "POST", body: { - title: "test", + name: "test", + start: dayjs().format(), + end: dayjs().add(1, "day").format(), eventTypeId: 2, - startTime: dayjs().toDate(), - endTime: dayjs().add(1, "day").toDate(), + email: "test@example.com", + location: "Cal.com Video", + timeZone: "America/Montevideo", + language: "en", + customInputs: [], + metadata: {}, + userId: 4, }, prisma, }); - prismaMock.eventType.findUnique.mockResolvedValue(buildEventType()); + prismaMock.eventType.findUniqueOrThrow.mockResolvedValue(buildEventType({ users: [buildUser()] })); + prismaMock.booking.findMany.mockResolvedValue([]); await handler(req, res); + console.log({ statusCode: res._getStatusCode(), data: JSON.parse(res._getData()) }); expect(prismaMock.booking.create).toHaveBeenCalledTimes(1); }); diff --git a/tsconfig.json b/tsconfig.json index c230406ae4..3b72d5ec74 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,6 +2,7 @@ "extends": "@calcom/tsconfig/nextjs.json", "compilerOptions": { "strict": true, + "jsx": "react-jsx", "baseUrl": ".", "paths": { "@api/*": ["pages/api/*"], From 6ba70a72597521ee2b2f8450853e002538775ebd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Thu, 13 Oct 2022 12:30:48 -0600 Subject: [PATCH 517/658] Refactor/custom inputs (#184) refs #175 To be merged after #183 --- lib/validations/event-type-custom-input.ts | 24 +-- pages/api/custom-inputs/[id].ts | 151 ------------------ .../custom-inputs/[id]/_auth-middleware.ts | 19 +++ pages/api/custom-inputs/[id]/_delete.ts | 36 +++++ pages/api/custom-inputs/[id]/_get.ts | 37 +++++ pages/api/custom-inputs/[id]/_patch.ts | 41 +++++ pages/api/custom-inputs/[id]/index.ts | 18 +++ pages/api/custom-inputs/_get.ts | 30 ++++ pages/api/custom-inputs/_post.ts | 48 ++++++ pages/api/custom-inputs/index.ts | 95 +---------- 10 files changed, 241 insertions(+), 258 deletions(-) delete mode 100644 pages/api/custom-inputs/[id].ts create mode 100644 pages/api/custom-inputs/[id]/_auth-middleware.ts create mode 100644 pages/api/custom-inputs/[id]/_delete.ts create mode 100644 pages/api/custom-inputs/[id]/_get.ts create mode 100644 pages/api/custom-inputs/[id]/_patch.ts create mode 100644 pages/api/custom-inputs/[id]/index.ts create mode 100644 pages/api/custom-inputs/_get.ts create mode 100644 pages/api/custom-inputs/_post.ts diff --git a/lib/validations/event-type-custom-input.ts b/lib/validations/event-type-custom-input.ts index 560d3d7684..8a9fb3dbbe 100644 --- a/lib/validations/event-type-custom-input.ts +++ b/lib/validations/event-type-custom-input.ts @@ -1,27 +1,13 @@ -import { z } from "zod"; - import { _EventTypeCustomInputModel as EventTypeCustomInput } from "@calcom/prisma/zod"; export const schemaEventTypeCustomInputBaseBodyParams = EventTypeCustomInput.omit({ id: true, - eventTypeId: true, -}).partial(); +}); export const schemaEventTypeCustomInputPublic = EventTypeCustomInput.omit({}); -const schemaEventTypeCustomInputRequiredParams = z.object({ - label: z.string(), - required: z.boolean(), - type: z.enum(["TEXT", "TEXTLONG", "NUMBER", "BOOL"]), - eventType: z.object({ - connect: z.object({ - id: z.number().optional(), - }), - // FIXME: Provide valid EventTypeModel schema here, but not sure how yet. - create: z.any(), - }), -}); +export const schemaEventTypeCustomInputBodyParams = schemaEventTypeCustomInputBaseBodyParams.strict(); -export const schemaEventTypeCustomInputBodyParams = schemaEventTypeCustomInputBaseBodyParams.merge( - schemaEventTypeCustomInputRequiredParams -); +export const schemaEventTypeCustomInputEditBodyParams = schemaEventTypeCustomInputBaseBodyParams + .partial() + .strict(); diff --git a/pages/api/custom-inputs/[id].ts b/pages/api/custom-inputs/[id].ts deleted file mode 100644 index 5b778714ad..0000000000 --- a/pages/api/custom-inputs/[id].ts +++ /dev/null @@ -1,151 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { EventTypeCustomInputResponse } from "@lib/types"; -import { - schemaEventTypeCustomInputBodyParams, - schemaEventTypeCustomInputPublic, -} from "@lib/validations/event-type-custom-input"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; - -/** - * @swagger - * /custom-inputs/{id}: - * get: - * summary: Find a eventTypeCustomInput - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the eventTypeCustomInput to get - * tags: - * - custom-inputs - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: EventType was not found - * patch: - * summary: Edit an existing eventTypeCustomInput - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the eventTypeCustomInput to edit - * tags: - * - custom-inputs - * responses: - * 201: - * description: OK, eventTypeCustomInput edited successfuly - * 400: - * description: Bad request. EventType body is invalid. - * 401: - * description: Authorization information is missing or invalid. - * delete: - * summary: Remove an existing eventTypeCustomInput - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the eventTypeCustomInput to delete - * tags: - * - custom-inputs - * responses: - * 201: - * description: OK, eventTypeCustomInput removed successfuly - * 400: - * description: Bad request. EventType id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ -async function eventTypeById( - { method, query, body, userId, prisma }: NextApiRequest, - res: NextApiResponse -) { - const safeQuery = schemaQueryIdParseInt.safeParse(query); - const safeBody = schemaEventTypeCustomInputBodyParams.safeParse(body); - if (!safeQuery.success) { - res.status(400).json({ message: "Your query was invalid" }); - return; - } - const data = await prisma.eventType.findMany({ where: { userId } }); - const userEventTypes = data.map((eventType) => eventType.id); - const userEventTypeCustomInputs = await prisma.eventTypeCustomInput.findMany({ - where: { eventType: userEventTypes }, - }); - const userEventTypeCustomInputIds = userEventTypeCustomInputs.map( - (eventTypeCustomInput) => eventTypeCustomInput.id - ); - if (!userEventTypeCustomInputIds.includes(safeQuery.data.id)) - res.status(401).json({ message: "Unauthorized" }); - else { - switch (method) { - case "GET": - await prisma.eventTypeCustomInput - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaEventTypeCustomInputPublic.parse(data)) - .then((event_type_custom_input) => res.status(200).json({ event_type_custom_input })) - .catch((error: Error) => - res.status(404).json({ - message: `EventType with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - - case "PATCH": - if (!safeBody.success) { - { - res.status(400).json({ message: "Invalid request body" }); - return; - } - } - await prisma.eventTypeCustomInput - .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) - .then((data) => schemaEventTypeCustomInputPublic.parse(data)) - .then((event_type_custom_input) => res.status(200).json({ event_type_custom_input })) - .catch((error: Error) => - res.status(404).json({ - message: `EventType with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - - case "DELETE": - await prisma.eventTypeCustomInput - .delete({ - where: { id: safeQuery.data.id }, - }) - .then(() => - res.status(200).json({ - message: `CustomInputEventType with id: ${safeQuery.data.id} deleted`, - }) - ) - .catch((error: Error) => - res.status(404).json({ - message: `EventType with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } - } -} - -export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(eventTypeById)); diff --git a/pages/api/custom-inputs/[id]/_auth-middleware.ts b/pages/api/custom-inputs/[id]/_auth-middleware.ts new file mode 100644 index 0000000000..1f4aff75f5 --- /dev/null +++ b/pages/api/custom-inputs/[id]/_auth-middleware.ts @@ -0,0 +1,19 @@ +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; + +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +async function authMiddleware(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const { id } = schemaQueryIdParseInt.parse(req.query); + // Admins can just skip this check + if (isAdmin) return; + // Check if the current user can access the event type of this input + const eventTypeCustomInput = await prisma.eventTypeCustomInput.findFirst({ + where: { id, eventType: { userId } }, + }); + if (!eventTypeCustomInput) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); +} + +export default authMiddleware; diff --git a/pages/api/custom-inputs/[id]/_delete.ts b/pages/api/custom-inputs/[id]/_delete.ts new file mode 100644 index 0000000000..aa1e09e3f1 --- /dev/null +++ b/pages/api/custom-inputs/[id]/_delete.ts @@ -0,0 +1,36 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /custom-inputs/{id}: + * delete: + * summary: Remove an existing eventTypeCustomInput + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the eventTypeCustomInput to delete + * tags: + * - custom-inputs + * responses: + * 201: + * description: OK, eventTypeCustomInput removed successfully + * 400: + * description: Bad request. EventType id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdParseInt.parse(query); + await prisma.eventTypeCustomInput.delete({ where: { id } }); + return { message: `CustomInputEventType with id: ${id} deleted successfully` }; +} + +export default defaultResponder(deleteHandler); diff --git a/pages/api/custom-inputs/[id]/_get.ts b/pages/api/custom-inputs/[id]/_get.ts new file mode 100644 index 0000000000..b3b7ce8668 --- /dev/null +++ b/pages/api/custom-inputs/[id]/_get.ts @@ -0,0 +1,37 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaEventTypeCustomInputPublic } from "@lib/validations/event-type-custom-input"; +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /custom-inputs/{id}: + * get: + * summary: Find a eventTypeCustomInput + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the eventTypeCustomInput to get + * tags: + * - custom-inputs + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: EventType was not found + */ +export async function getHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdParseInt.parse(query); + const data = await prisma.eventTypeCustomInput.findUniqueOrThrow({ where: { id } }); + return { event_type_custom_input: schemaEventTypeCustomInputPublic.parse(data) }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/custom-inputs/[id]/_patch.ts b/pages/api/custom-inputs/[id]/_patch.ts new file mode 100644 index 0000000000..034d45f37b --- /dev/null +++ b/pages/api/custom-inputs/[id]/_patch.ts @@ -0,0 +1,41 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { + schemaEventTypeCustomInputEditBodyParams, + schemaEventTypeCustomInputPublic, +} from "@lib/validations/event-type-custom-input"; +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /custom-inputs/{id}: + * patch: + * summary: Edit an existing eventTypeCustomInput + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the eventTypeCustomInput to edit + * tags: + * - custom-inputs + * responses: + * 201: + * description: OK, eventTypeCustomInput edited successfully + * 400: + * description: Bad request. EventType body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function patchHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdParseInt.parse(query); + const data = schemaEventTypeCustomInputEditBodyParams.parse(req.body); + const result = await prisma.eventTypeCustomInput.update({ where: { id }, data }); + return { event_type_custom_input: schemaEventTypeCustomInputPublic.parse(result) }; +} + +export default defaultResponder(patchHandler); diff --git a/pages/api/custom-inputs/[id]/index.ts b/pages/api/custom-inputs/[id]/index.ts new file mode 100644 index 0000000000..7d92ee2906 --- /dev/null +++ b/pages/api/custom-inputs/[id]/index.ts @@ -0,0 +1,18 @@ +import { NextApiRequest, NextApiResponse } from "next"; + +import { defaultHandler, defaultResponder } from "@calcom/lib/server"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; + +import authMiddleware from "./_auth-middleware"; + +export default withMiddleware("HTTP_GET_DELETE_PATCH")( + defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { + await authMiddleware(req); + return defaultHandler({ + GET: import("./_get"), + PATCH: import("./_patch"), + DELETE: import("./_delete"), + })(req, res); + }) +); diff --git a/pages/api/custom-inputs/_get.ts b/pages/api/custom-inputs/_get.ts new file mode 100644 index 0000000000..0a2d30d9d4 --- /dev/null +++ b/pages/api/custom-inputs/_get.ts @@ -0,0 +1,30 @@ +import type { Prisma } from "@prisma/client"; +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaEventTypeCustomInputPublic } from "@lib/validations/event-type-custom-input"; + +/** + * @swagger + * /custom-inputs: + * get: + * summary: Find all eventTypeCustomInputs + * tags: + * - custom-inputs + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No eventTypeCustomInputs were found + */ +async function getHandler(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const args: Prisma.EventTypeCustomInputFindManyArgs = isAdmin ? {} : { where: { eventType: { userId } } }; + const data = await prisma.eventTypeCustomInput.findMany(args); + return { event_type_custom_inputs: data.map((v) => schemaEventTypeCustomInputPublic.parse(v)) }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/custom-inputs/_post.ts b/pages/api/custom-inputs/_post.ts new file mode 100644 index 0000000000..ea9da7da4f --- /dev/null +++ b/pages/api/custom-inputs/_post.ts @@ -0,0 +1,48 @@ +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { + schemaEventTypeCustomInputBodyParams, + schemaEventTypeCustomInputPublic, +} from "@lib/validations/event-type-custom-input"; + +/** + * @swagger + * /custom-inputs: + * post: + * summary: Creates a new eventTypeCustomInput + * tags: + * - custom-inputs + * responses: + * 201: + * description: OK, eventTypeCustomInput created + * 400: + * description: Bad request. EventTypeCustomInput body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function postHandler(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const { eventTypeId, ...body } = schemaEventTypeCustomInputBodyParams.parse(req.body); + + if (!isAdmin) { + /* We check that the user has access to the event type he's trying to add a custom input to. */ + const eventType = await prisma.eventType.findFirst({ + where: { id: eventTypeId, userId }, + }); + if (!eventType) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + } + + const data = await prisma.eventTypeCustomInput.create({ + data: { ...body, eventType: { connect: { id: eventTypeId } } }, + }); + + return { + event_type_custom_input: schemaEventTypeCustomInputPublic.parse(data), + message: "EventTypeCustomInput created successfully", + }; +} + +export default defaultResponder(postHandler); diff --git a/pages/api/custom-inputs/index.ts b/pages/api/custom-inputs/index.ts index 17500249aa..c07846423f 100644 --- a/pages/api/custom-inputs/index.ts +++ b/pages/api/custom-inputs/index.ts @@ -1,91 +1,10 @@ -import type { NextApiRequest, NextApiResponse } from "next"; +import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { EventTypeCustomInputResponse, EventTypeCustomInputsResponse } from "@lib/types"; -import { - schemaEventTypeCustomInputBodyParams, - schemaEventTypeCustomInputPublic, -} from "@lib/validations/event-type-custom-input"; -async function createOrlistAllEventTypeCustomInputs( - { userId, method, body, prisma }: NextApiRequest, - res: NextApiResponse -) { - const data = await prisma.eventType.findMany({ where: { userId } }); - const userEventTypes: number[] = data.map((eventType) => eventType.id); - if (method === "GET") { - /** - * @swagger - * /custom-inputs: - * get: - * summary: Find all eventTypeCustomInputs - * tags: - * - custom-inputs - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No eventTypeCustomInputs were found - */ - const data = await prisma.eventTypeCustomInput.findMany({ where: { eventType: userEventTypes } }); - const event_type_custom_inputs = data.map((eventTypeCustomInput) => - schemaEventTypeCustomInputPublic.parse(eventTypeCustomInput) - ); - if (event_type_custom_inputs) res.status(200).json({ event_type_custom_inputs }); - else - (error: Error) => - res.status(404).json({ - message: "No EventTypeCustomInputs were found", - error, - }); - } else if (method === "POST") { - /** - * @swagger - * /custom-inputs: - * post: - * summary: Creates a new eventTypeCustomInput - * tags: - * - custom-inputs - * responses: - * 201: - * description: OK, eventTypeCustomInput created - * 400: - * description: Bad request. EventTypeCustomInput body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - const safe = schemaEventTypeCustomInputBodyParams.safeParse(body); - if (!safe.success) { - res.status(400).json({ message: "Invalid request body" }); - return; - } - // Since we're supporting a create or connect relation on eventType, we need to treat them differently - // When using connect on event type, check if userId is the owner of the event - if (safe.data.eventType.connect && !userEventTypes.includes(safe.data.eventType.connect.id as number)) { - const data = await prisma.eventTypeCustomInput.create({ data: { ...safe.data } }); - const event_type_custom_input = schemaEventTypeCustomInputPublic.parse(data); - if (event_type_custom_input) - res - .status(201) - .json({ event_type_custom_input, message: "EventTypeCustomInput created successfully" }); - // When creating, no need - // FIXME: we might want to pass userId to the new created/linked eventType, though. - } else if (safe.data.eventType.create) { - const data = await prisma.eventTypeCustomInput.create({ data: { ...safe.data } }); - const event_type_custom_input = schemaEventTypeCustomInputPublic.parse(data); - if (event_type_custom_input) - res - .status(201) - .json({ event_type_custom_input, message: "EventTypeCustomInput created successfully" }); - } else - (error: Error) => - res.status(400).json({ - message: "Could not create new eventTypeCustomInput", - error, - }); - } else res.status(405).json({ message: `Method ${method} not allowed` }); -} - -export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllEventTypeCustomInputs); +export default withMiddleware("HTTP_GET_OR_POST")( + defaultHandler({ + GET: import("./_get"), + POST: import("./_post"), + }) +); From 31610dd17871df50532fbbedcbd221f3d6b7a4cf Mon Sep 17 00:00:00 2001 From: zomars Date: Thu, 13 Oct 2022 13:14:58 -0600 Subject: [PATCH 518/658] Adds missing description field to patch --- lib/validations/event-type.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 8cf3fece84..462990d65e 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -19,6 +19,7 @@ const recurringEventInputSchema = z.object({ export const schemaEventTypeBaseBodyParams = EventType.pick({ title: true, + description: true, slug: true, length: true, hidden: true, From e3fa0e546be8b9f1d2b5bc9b4d44eb59ab9678d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Thu, 13 Oct 2022 14:54:38 -0600 Subject: [PATCH 519/658] Refactor schedule endpoints (#185) --- lib/validations/schedule.ts | 13 +- lib/validations/shared/timeZone.ts | 4 +- pages/api/schedules/[id]/_auth-middleware.ts | 19 ++ pages/api/schedules/[id]/_delete.ts | 41 ++++ pages/api/schedules/[id]/_get.ts | 38 ++++ pages/api/schedules/[id]/_patch.ts | 39 ++++ pages/api/schedules/[id]/index.ts | 196 ++----------------- pages/api/schedules/_get.ts | 43 ++-- pages/api/schedules/_post.ts | 52 ++--- 9 files changed, 201 insertions(+), 244 deletions(-) create mode 100644 pages/api/schedules/[id]/_auth-middleware.ts create mode 100644 pages/api/schedules/[id]/_delete.ts create mode 100644 pages/api/schedules/[id]/_get.ts create mode 100644 pages/api/schedules/[id]/_patch.ts diff --git a/lib/validations/schedule.ts b/lib/validations/schedule.ts index f8571c06c1..51a3fbe1af 100644 --- a/lib/validations/schedule.ts +++ b/lib/validations/schedule.ts @@ -3,21 +3,16 @@ import { z } from "zod"; import dayjs from "@calcom/dayjs"; import { _ScheduleModel as Schedule, _AvailabilityModel as Availability } from "@calcom/prisma/zod"; -const schemaScheduleBaseBodyParams = Schedule.omit({ id: true }).partial(); +import { timeZone } from "./shared/timeZone"; -const schemaScheduleRequiredParams = z.object({ - name: z.string().optional(), - userId: z.union([z.number(), z.array(z.number())]).optional(), -}); - -export const schemaScheduleBodyParams = schemaScheduleBaseBodyParams.merge(schemaScheduleRequiredParams); +const schemaScheduleBaseBodyParams = Schedule.omit({ id: true, timeZone: true }).partial(); export const schemaSingleScheduleBodyParams = schemaScheduleBaseBodyParams.merge( - z.object({ userId: z.number().optional() }) + z.object({ userId: z.number().optional(), timeZone: timeZone.optional() }) ); export const schemaCreateScheduleBodyParams = schemaScheduleBaseBodyParams.merge( - z.object({ userId: z.number().optional(), name: z.string() }) + z.object({ userId: z.number().optional(), name: z.string(), timeZone }) ); export const schemaSchedulePublic = z diff --git a/lib/validations/shared/timeZone.ts b/lib/validations/shared/timeZone.ts index 13019690d0..e94b0afa09 100644 --- a/lib/validations/shared/timeZone.ts +++ b/lib/validations/shared/timeZone.ts @@ -2,4 +2,6 @@ import tzdata from "tzdata"; import * as z from "zod"; // @note: This is a custom validation that checks if the timezone is valid and exists in the tzdb library -export const timeZone = z.string().refine((tz: string) => Object.keys(tzdata.zones).includes(tz)); +export const timeZone = z.string().refine((tz: string) => Object.keys(tzdata.zones).includes(tz), { + message: `Expected one of the following: ${Object.keys(tzdata.zones).join(", ")}`, +}); diff --git a/pages/api/schedules/[id]/_auth-middleware.ts b/pages/api/schedules/[id]/_auth-middleware.ts new file mode 100644 index 0000000000..18139171bf --- /dev/null +++ b/pages/api/schedules/[id]/_auth-middleware.ts @@ -0,0 +1,19 @@ +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; + +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +async function authMiddleware(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const { id } = schemaQueryIdParseInt.parse(req.query); + // Admins can just skip this check + if (isAdmin) return; + // Check if the current user can access the schedule + const schedule = await prisma.schedule.findFirst({ + where: { id, userId }, + }); + if (!schedule) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); +} + +export default authMiddleware; diff --git a/pages/api/schedules/[id]/_delete.ts b/pages/api/schedules/[id]/_delete.ts new file mode 100644 index 0000000000..a6a7f39cc8 --- /dev/null +++ b/pages/api/schedules/[id]/_delete.ts @@ -0,0 +1,41 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /schedules/{id}: + * delete: + * operationId: removeScheduleById + * summary: Remove an existing schedule + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the schedule to delete + * tags: + * - schedules + * responses: + * 201: + * description: OK, schedule removed successfully + * 400: + * description: Bad request. Schedule id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdParseInt.parse(query); + + /* If we're deleting any default user schedule, we unset it */ + await prisma.user.updateMany({ where: { defaultScheduleId: id }, data: { defaultScheduleId: undefined } }); + + await prisma.schedule.delete({ where: { id } }); + return { message: `Schedule with id: ${id} deleted successfully` }; +} + +export default defaultResponder(deleteHandler); diff --git a/pages/api/schedules/[id]/_get.ts b/pages/api/schedules/[id]/_get.ts new file mode 100644 index 0000000000..8421a3ec8e --- /dev/null +++ b/pages/api/schedules/[id]/_get.ts @@ -0,0 +1,38 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaSchedulePublic } from "@lib/validations/schedule"; +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /schedules/{id}: + * get: + * operationId: getScheduleById + * summary: Find a schedule + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the schedule to get + * tags: + * - schedules + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Schedule was not found + */ +export async function getHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdParseInt.parse(query); + const data = await prisma.schedule.findUniqueOrThrow({ where: { id }, include: { availability: true } }); + return { schedule: schemaSchedulePublic.parse(data) }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/schedules/[id]/_patch.ts b/pages/api/schedules/[id]/_patch.ts new file mode 100644 index 0000000000..528c2ea98d --- /dev/null +++ b/pages/api/schedules/[id]/_patch.ts @@ -0,0 +1,39 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaSchedulePublic, schemaSingleScheduleBodyParams } from "@lib/validations/schedule"; +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; + +/** + * @swagger + * /schedules/{id}: + * patch: + * operationId: editScheduleById + * summary: Edit an existing schedule + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the schedule to edit + * tags: + * - schedules + * responses: + * 201: + * description: OK, schedule edited successfully + * 400: + * description: Bad request. Schedule body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function patchHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdParseInt.parse(query); + const data = schemaSingleScheduleBodyParams.parse(req.body); + const result = await prisma.schedule.update({ where: { id }, data, include: { availability: true } }); + return { schedule: schemaSchedulePublic.parse(result) }; +} + +export default defaultResponder(patchHandler); diff --git a/pages/api/schedules/[id]/index.ts b/pages/api/schedules/[id]/index.ts index 9dbb75470a..cbff13f006 100644 --- a/pages/api/schedules/[id]/index.ts +++ b/pages/api/schedules/[id]/index.ts @@ -1,188 +1,18 @@ import type { NextApiRequest, NextApiResponse } from "next"; -import safeParseJSON from "@lib/helpers/safeParseJSON"; +import { defaultHandler, defaultResponder } from "@calcom/lib/server"; + import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { ScheduleResponse } from "@lib/types"; -import { schemaSingleScheduleBodyParams, schemaSchedulePublic } from "@lib/validations/schedule"; -import { - schemaQueryIdParseInt, - withValidQueryIdTransformParseInt, -} from "@lib/validations/shared/queryIdTransformParseInt"; -export async function scheduleById( - { method, query, body, userId, isAdmin, prisma }: NextApiRequest, - res: NextApiResponse -) { - body = safeParseJSON(body); - if (!body.success) { - res.status(400).json({ message: body.message }); - return; - } +import authMiddleware from "./_auth-middleware"; - const safeBody = schemaSingleScheduleBodyParams.safeParse(body); - if (!safeBody.success) { - res.status(400).json({ message: "Bad request" }); - return; - } - - const safeQuery = schemaQueryIdParseInt.safeParse(query); - if (safeBody.data.userId && !isAdmin) { - res.status(401).json({ message: "Unauthorized" }); - return; - } - if (!safeQuery.success) { - res.status(400).json({ message: "Your query was invalid" }); - return; - } - const userSchedules = await prisma.schedule.findMany({ where: { userId: safeBody.data.userId || userId } }); - const userScheduleIds = userSchedules.map((schedule) => schedule.id); - if (!userScheduleIds.includes(safeQuery.data.id)) { - res.status(401).json({ message: "Unauthorized" }); - return; - } else { - switch (method) { - /** - * @swagger - * /schedules/{id}: - * get: - * operationId: getScheduleById - * summary: Find a schedule - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the schedule to get - * tags: - * - schedules - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Schedule was not found - */ - case "GET": - await prisma.schedule - .findUnique({ - where: { id: safeQuery.data.id }, - include: { availability: true }, - }) - .then((data) => schemaSchedulePublic.parse(data)) - .then((schedule) => res.status(200).json({ schedule })) - .catch((error: Error) => - res.status(404).json({ - message: `Schedule with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - - /** - * @swagger - * /schedules/{id}: - * patch: - * operationId: editScheduleById - * summary: Edit an existing schedule - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the schedule to edit - * tags: - * - schedules - * responses: - * 201: - * description: OK, schedule edited successfuly - * 400: - * description: Bad request. Schedule body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - case "PATCH": - if (!safeBody.success) { - { - res.status(400).json({ message: "Invalid request body" }); - return; - } - } - - delete safeBody.data.userId; - - await prisma.schedule - .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) - .then((data) => schemaSchedulePublic.parse(data)) - .then((schedule) => res.status(200).json({ schedule })) - .catch((error: Error) => - res.status(404).json({ - message: `Schedule with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - - /** - * @swagger - * /schedules/{id}: - * delete: - * operationId: removeScheduleById - * summary: Remove an existing schedule - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the schedule to delete - * tags: - * - schedules - * responses: - * 201: - * description: OK, schedule removed successfuly - * 400: - * description: Bad request. Schedule id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - case "DELETE": - // Look for user to check if schedule is user's default - const user = await prisma.user.findUnique({ where: { id: userId } }); - if (!user) throw new Error("User not found"); - if (user.defaultScheduleId === safeQuery.data.id) { - // unset default - await prisma.user.update({ - where: { - id: userId, - }, - data: { - defaultScheduleId: undefined, - }, - }); - } - await prisma.schedule - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ - message: `Schedule with id: ${safeQuery.data.id} deleted successfully`, - }) - ) - .catch((error: Error) => - res.status(404).json({ - message: `Schedule with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } - } -} - -export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdTransformParseInt(scheduleById)); +export default withMiddleware("HTTP_GET_DELETE_PATCH")( + defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { + await authMiddleware(req); + return defaultHandler({ + GET: import("./_get"), + PATCH: import("./_patch"), + DELETE: import("./_delete"), + })(req, res); + }) +); diff --git a/pages/api/schedules/_get.ts b/pages/api/schedules/_get.ts index 40d3c9a1a6..b909ef9ce6 100644 --- a/pages/api/schedules/_get.ts +++ b/pages/api/schedules/_get.ts @@ -1,3 +1,4 @@ +import type { Prisma } from "@prisma/client"; import type { NextApiRequest } from "next"; import { z } from "zod"; @@ -5,6 +6,7 @@ import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; import { schemaSchedulePublic } from "@lib/validations/schedule"; +import { schemaQuerySingleOrMultipleUserIds } from "@lib/validations/shared/queryUserId"; export const schemaUserIds = z .union([z.string(), z.array(z.string())]) @@ -26,34 +28,25 @@ export const schemaUserIds = z * 404: * description: No schedules were found */ -async function handler({ body, prisma, userId, isAdmin, query }: NextApiRequest) { - let userIds: number[] = [userId]; +async function handler(req: NextApiRequest) { + const { prisma, userId, isAdmin } = req; + const args: Prisma.ScheduleFindManyArgs = isAdmin ? {} : { where: { userId } }; + args.include = { availability: true }; - if (!isAdmin && query.userId) { - // throw 403 Forbidden when the userId is given but user is not an admin - throw new HttpError({ statusCode: 403 }); - } - // When isAdmin && userId is given parse it and use it instead of the current (admin) user. - else if (query.userId) { - const result = schemaUserIds.safeParse(query.userId); - if (result.success && result.data) { - userIds = result.data; - } - } + if (!isAdmin && req.query.userId) + throw new HttpError({ + statusCode: 401, + message: "Unauthorized: Only admins can query other users", + }); - const data = await prisma.schedule.findMany({ - where: { - userId: { in: userIds }, - }, - include: { availability: true }, - ...(Array.isArray(body.userId) && { orderBy: { userId: "asc" } }), - }); - const schedules = data.map((schedule) => schemaSchedulePublic.parse(schedule)); - if (schedules) { - return { schedules }; + if (isAdmin && req.query.userId) { + const query = schemaQuerySingleOrMultipleUserIds.parse(req.query); + const userIds = Array.isArray(query.userId) ? query.userId : [query.userId || userId]; + args.where = { userId: { in: userIds } }; + if (Array.isArray(query.userId)) args.orderBy = { userId: "asc" }; } - - throw new HttpError({ statusCode: 404, message: "No schedules were found" }); + const data = await prisma.schedule.findMany(args); + return { schedules: data.map((s) => schemaSchedulePublic.parse(s)) }; } export default defaultResponder(handler); diff --git a/pages/api/schedules/_post.ts b/pages/api/schedules/_post.ts index cb6399d247..6bf631afe2 100644 --- a/pages/api/schedules/_post.ts +++ b/pages/api/schedules/_post.ts @@ -1,7 +1,8 @@ -import { HttpError } from "@/../../packages/lib/http-error"; +import type { Prisma } from "@prisma/client"; import type { NextApiRequest } from "next"; import { DEFAULT_SCHEDULE, getAvailabilityFromSchedule } from "@calcom/lib/availability"; +import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; import { schemaCreateScheduleBodyParams, schemaSchedulePublic } from "@lib/validations/schedule"; @@ -22,36 +23,35 @@ import { schemaCreateScheduleBodyParams, schemaSchedulePublic } from "@lib/valid * 401: * description: Authorization information is missing or invalid. */ -async function postHandler({ body, userId, isAdmin, prisma }: NextApiRequest) { - const parsedBody = schemaCreateScheduleBodyParams.parse(body); - if (parsedBody.userId && !isAdmin) { - throw new HttpError({ statusCode: 403 }); - } +async function postHandler(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const body = schemaCreateScheduleBodyParams.parse(req.body); + let args: Prisma.ScheduleCreateArgs = { data: { ...body, userId } }; - const data = await prisma.schedule.create({ - data: { - ...parsedBody, - userId: parsedBody.userId || userId, - availability: { - createMany: { - data: getAvailabilityFromSchedule(DEFAULT_SCHEDULE).map((schedule) => ({ - days: schedule.days, - startTime: schedule.startTime, - endTime: schedule.endTime, - })), - }, - }, + /* If ADMIN we create the schedule for selected user */ + if (isAdmin && body.userId) args = { data: { ...body, userId: body.userId } }; + + if (!isAdmin && body.userId) + throw new HttpError({ statusCode: 403, message: "ADMIN required for `userId`" }); + + // We create default availabilities for the schedule + args.data.availability = { + createMany: { + data: getAvailabilityFromSchedule(DEFAULT_SCHEDULE).map((schedule) => ({ + days: schedule.days, + startTime: schedule.startTime, + endTime: schedule.endTime, + })), }, - }); + }; + // We include the recently created availability + args.include = { availability: true }; - const createSchedule = schemaSchedulePublic.safeParse(data); - if (!createSchedule.success) { - throw new HttpError({ statusCode: 400, message: "Could not create new schedule" }); - } + const data = await prisma.schedule.create(args); return { - schedule: createSchedule.data, - message: "Schedule created succesfully", + schedule: schemaSchedulePublic.parse(data), + message: "Schedule created successfully", }; } From ccf0a40b67511981f840fd67e349548a4d9634ad Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 14 Oct 2022 11:42:05 -0600 Subject: [PATCH 520/658] Misc fixes --- lib/validations/booking.ts | 1 + next-i18next.config.js | 1 + tsconfig.json | 27 +++++++++++++++++++++------ 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index d5ee93da3e..72f1e10be5 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -10,6 +10,7 @@ const schemaBookingBaseBodyParams = Booking.pick({ userId: true, eventTypeId: true, title: true, + description: true, startTime: true, endTime: true, }).partial(); diff --git a/next-i18next.config.js b/next-i18next.config.js index 402b72363c..c985d846fc 100644 --- a/next-i18next.config.js +++ b/next-i18next.config.js @@ -4,6 +4,7 @@ const i18nConfig = require("@calcom/config/next-i18next.config"); /** @type {import("next-i18next").UserConfig} */ const config = { ...i18nConfig, + localeDetection: false, localePath: path.resolve("../web/public/static/locales"), }; diff --git a/tsconfig.json b/tsconfig.json index 3b72d5ec74..3e4341ce5e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,14 +2,29 @@ "extends": "@calcom/tsconfig/nextjs.json", "compilerOptions": { "strict": true, - "jsx": "react-jsx", + "jsx": "preserve", "baseUrl": ".", "paths": { - "@api/*": ["pages/api/*"], - "@lib/*": ["lib/*"], - "@/*": ["*"] + "@api/*": [ + "pages/api/*" + ], + "@lib/*": [ + "lib/*" + ], + "@/*": [ + "*" + ] } }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "../../packages/types/next-auth.d.ts"], - "exclude": ["node_modules", "templates", "auth"] + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + "../../packages/types/next-auth.d.ts" + ], + "exclude": [ + "node_modules", + "templates", + "auth" + ] } From 9c35ff2d2e8086c0e1091f4f3afbf67901012cdf Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 14 Oct 2022 11:42:31 -0600 Subject: [PATCH 521/658] Locale fixes --- next.config.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/next.config.js b/next.config.js index 9662874748..0e22193499 100644 --- a/next.config.js +++ b/next.config.js @@ -26,11 +26,13 @@ module.exports = withAxiom( { source: "/v:version/:rest*", destination: "/api/v:version/:rest*", + locale: false, }, // This redirects requests to api/v*/ to /api/ passing version as a query parameter. { source: "/api/v:version/:rest*", destination: "/api/:rest*?version=:version", + locale: false, }, ], fallback: [ @@ -39,6 +41,7 @@ module.exports = withAxiom( { source: "/:path*", destination: `/api/:path*`, + locale: false, }, ], }; From ad35d3a5cd2a4c6686b5c075487dd90e15fdbe1b Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 14 Oct 2022 12:57:50 -0600 Subject: [PATCH 522/658] Linting --- pages/api/booking-references/_post.ts | 1 - pages/api/event-types/[id]/_get.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/pages/api/booking-references/_post.ts b/pages/api/booking-references/_post.ts index b5ed53b79d..b1675a7f76 100644 --- a/pages/api/booking-references/_post.ts +++ b/pages/api/booking-references/_post.ts @@ -1,7 +1,6 @@ import type { Prisma } from "@prisma/client"; import type { NextApiRequest } from "next"; -import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; import { diff --git a/pages/api/event-types/[id]/_get.ts b/pages/api/event-types/[id]/_get.ts index 5e91666eed..13301a9f38 100644 --- a/pages/api/event-types/[id]/_get.ts +++ b/pages/api/event-types/[id]/_get.ts @@ -2,7 +2,6 @@ import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; -import { schemaAttendeeReadPublic } from "@lib/validations/attendee"; import { schemaEventTypeReadPublic } from "@lib/validations/event-type"; import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; From d38015c737521899310f08b67dccc5da16b6f706 Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 14 Oct 2022 13:02:53 -0600 Subject: [PATCH 523/658] Locale fixes --- next-i18next.config.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/next-i18next.config.js b/next-i18next.config.js index c985d846fc..a64f3380b0 100644 --- a/next-i18next.config.js +++ b/next-i18next.config.js @@ -3,8 +3,10 @@ const i18nConfig = require("@calcom/config/next-i18next.config"); /** @type {import("next-i18next").UserConfig} */ const config = { - ...i18nConfig, - localeDetection: false, + i18n: { + ...i18nConfig, + localeDetection: false, + }, localePath: path.resolve("../web/public/static/locales"), }; From 7708ee83a1182bf0704d0d1beb23940762ee3a1e Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 14 Oct 2022 13:16:46 -0600 Subject: [PATCH 524/658] Locale fixes --- next-i18next.config.js | 5 +---- next.config.js | 5 ++++- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/next-i18next.config.js b/next-i18next.config.js index a64f3380b0..402b72363c 100644 --- a/next-i18next.config.js +++ b/next-i18next.config.js @@ -3,10 +3,7 @@ const i18nConfig = require("@calcom/config/next-i18next.config"); /** @type {import("next-i18next").UserConfig} */ const config = { - i18n: { - ...i18nConfig, - localeDetection: false, - }, + ...i18nConfig, localePath: path.resolve("../web/public/static/locales"), }; diff --git a/next.config.js b/next.config.js index 0e22193499..8c56d42d09 100644 --- a/next.config.js +++ b/next.config.js @@ -18,7 +18,10 @@ const { i18n } = require("./next-i18next.config"); module.exports = withAxiom( withTM({ - i18n, + i18n: { + ...i18n, + localeDetection: false, + }, async rewrites() { return { afterFiles: [ From 11ffdccb4ab6d901ecc16dcaceb0fa648ce86038 Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 14 Oct 2022 13:26:30 -0600 Subject: [PATCH 525/658] Removes locale altogehter @see https://github.com/vercel/next.js/issues/29000 --- next.config.js | 8 -------- 1 file changed, 8 deletions(-) diff --git a/next.config.js b/next.config.js index 8c56d42d09..1031c0a949 100644 --- a/next.config.js +++ b/next.config.js @@ -14,14 +14,9 @@ const withTM = require("next-transpile-modules")([ "@calcom/ui", ]); const { withAxiom } = require("next-axiom"); -const { i18n } = require("./next-i18next.config"); module.exports = withAxiom( withTM({ - i18n: { - ...i18n, - localeDetection: false, - }, async rewrites() { return { afterFiles: [ @@ -29,13 +24,11 @@ module.exports = withAxiom( { source: "/v:version/:rest*", destination: "/api/v:version/:rest*", - locale: false, }, // This redirects requests to api/v*/ to /api/ passing version as a query parameter. { source: "/api/v:version/:rest*", destination: "/api/:rest*?version=:version", - locale: false, }, ], fallback: [ @@ -44,7 +37,6 @@ module.exports = withAxiom( { source: "/:path*", destination: `/api/:path*`, - locale: false, }, ], }; From 25d3d123199a3b77df32205e69e65baca1dba48b Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 14 Oct 2022 15:52:09 -0600 Subject: [PATCH 526/658] Adds custom inputs to eventTypes responses --- lib/validations/event-type.ts | 3 ++- pages/api/event-types/[id]/_get.ts | 2 +- pages/api/event-types/_get.ts | 4 +++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 462990d65e..ce168925d0 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -import { _EventTypeModel as EventType } from "@calcom/prisma/zod"; +import { _EventTypeCustomInputModel, _EventTypeModel as EventType } from "@calcom/prisma/zod"; import { Frequency } from "@lib/types"; @@ -116,5 +116,6 @@ export const schemaEventTypeReadPublic = EventType.pick({ ) .nullable(), metadata: jsonSchema.nullable(), + customInputs: _EventTypeCustomInputModel.array().optional(), }) ); diff --git a/pages/api/event-types/[id]/_get.ts b/pages/api/event-types/[id]/_get.ts index 13301a9f38..5ce12e2c86 100644 --- a/pages/api/event-types/[id]/_get.ts +++ b/pages/api/event-types/[id]/_get.ts @@ -36,7 +36,7 @@ import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformP export async function getHandler(req: NextApiRequest) { const { prisma, query } = req; const { id } = schemaQueryIdParseInt.parse(query); - const event_type = await prisma.eventType.findUnique({ where: { id } }); + const event_type = await prisma.eventType.findUnique({ where: { id }, include: { customInputs: true } }); return { event_type: schemaEventTypeReadPublic.parse(event_type) }; } diff --git a/pages/api/event-types/_get.ts b/pages/api/event-types/_get.ts index 3a3b968b8b..b126da8a28 100644 --- a/pages/api/event-types/_get.ts +++ b/pages/api/event-types/_get.ts @@ -27,7 +27,9 @@ import { schemaQuerySingleOrMultipleUserIds } from "@lib/validations/shared/quer */ async function getHandler(req: NextApiRequest) { const { userId, isAdmin, prisma } = req; - const args: Prisma.EventTypeFindManyArgs = isAdmin ? {} : { where: { userId } }; + const args: Prisma.EventTypeFindManyArgs = isAdmin + ? {} + : { where: { userId }, include: { customInputs: true } }; /** Only admins can query other users */ if (!isAdmin && req.query.userId) throw new HttpError({ statusCode: 401, message: "ADMIN required" }); if (isAdmin && req.query.userId) { From 37fa76315a99595e8e070903c6b5dcc0e248ab93 Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 14 Oct 2022 15:52:17 -0600 Subject: [PATCH 527/658] Allow to update booking description --- lib/validations/booking.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index 72f1e10be5..31deb5cff5 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -30,6 +30,7 @@ export const schemaBookingEditBodyParams = schemaBookingBaseBodyParams.merge(sch export const schemaBookingReadPublic = Booking.pick({ id: true, userId: true, + description: true, eventTypeId: true, uid: true, title: true, From 00bd908916b5eb6518781330b0082336b15eaaf5 Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 14 Oct 2022 17:41:28 -0600 Subject: [PATCH 528/658] Fixes permission errors --- pages/api/attendees/[id]/_auth-middleware.ts | 2 +- pages/api/attendees/_post.ts | 2 +- pages/api/availability/_get.ts | 2 +- pages/api/booking-references/[id]/_auth-middleware.ts | 2 +- pages/api/custom-inputs/[id]/_auth-middleware.ts | 2 +- pages/api/custom-inputs/_post.ts | 2 +- pages/api/event-types/[id]/_auth-middleware.ts | 2 +- pages/api/event-types/[id]/_delete.ts | 2 +- pages/api/event-types/[id]/_patch.ts | 2 +- pages/api/schedules/[id]/_auth-middleware.ts | 2 +- pages/api/users/[userId]/_delete.ts | 2 +- pages/api/users/[userId]/_get.ts | 2 +- pages/api/users/[userId]/_patch.ts | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/pages/api/attendees/[id]/_auth-middleware.ts b/pages/api/attendees/[id]/_auth-middleware.ts index ab27cf266e..ca01477033 100644 --- a/pages/api/attendees/[id]/_auth-middleware.ts +++ b/pages/api/attendees/[id]/_auth-middleware.ts @@ -14,7 +14,7 @@ async function authMiddleware(req: NextApiRequest) { where: { id: query.id, booking: { userId } }, }); // Flatten and merge all the attendees in one array - if (!attendee) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + if (!attendee) throw new HttpError({ statusCode: 403, message: "Forbidden" }); } export default authMiddleware; diff --git a/pages/api/attendees/_post.ts b/pages/api/attendees/_post.ts index 1e5ff8199f..106007019d 100644 --- a/pages/api/attendees/_post.ts +++ b/pages/api/attendees/_post.ts @@ -56,7 +56,7 @@ async function postHandler(req: NextApiRequest) { select: { id: true }, }); // Here we make sure to only return attendee's of the user's own bookings. - if (!userBooking) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + if (!userBooking) throw new HttpError({ statusCode: 403, message: "Forbidden" }); } const data = await prisma.attendee.create({ diff --git a/pages/api/availability/_get.ts b/pages/api/availability/_get.ts index 590970fb70..7dee66c194 100644 --- a/pages/api/availability/_get.ts +++ b/pages/api/availability/_get.ts @@ -43,7 +43,7 @@ async function handler(req: NextApiRequest) { where: { id: { in: allMemberIds } }, select: availabilityUserSelect, }); - if (!isAdmin) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + if (!isAdmin) throw new HttpError({ statusCode: 403, message: "Forbidden" }); const availabilities = members.map(async (user) => { return { userId: user.id, diff --git a/pages/api/booking-references/[id]/_auth-middleware.ts b/pages/api/booking-references/[id]/_auth-middleware.ts index f8a83b3bd2..51c14abe62 100644 --- a/pages/api/booking-references/[id]/_auth-middleware.ts +++ b/pages/api/booking-references/[id]/_auth-middleware.ts @@ -13,7 +13,7 @@ async function authMiddleware(req: NextApiRequest) { const bookingReference = await prisma.bookingReference.findFirst({ where: { id, booking: { userId } }, }); - if (!bookingReference) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + if (!bookingReference) throw new HttpError({ statusCode: 403, message: "Forbidden" }); } export default authMiddleware; diff --git a/pages/api/custom-inputs/[id]/_auth-middleware.ts b/pages/api/custom-inputs/[id]/_auth-middleware.ts index 1f4aff75f5..932b968f0e 100644 --- a/pages/api/custom-inputs/[id]/_auth-middleware.ts +++ b/pages/api/custom-inputs/[id]/_auth-middleware.ts @@ -13,7 +13,7 @@ async function authMiddleware(req: NextApiRequest) { const eventTypeCustomInput = await prisma.eventTypeCustomInput.findFirst({ where: { id, eventType: { userId } }, }); - if (!eventTypeCustomInput) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + if (!eventTypeCustomInput) throw new HttpError({ statusCode: 403, message: "Forbidden" }); } export default authMiddleware; diff --git a/pages/api/custom-inputs/_post.ts b/pages/api/custom-inputs/_post.ts index ea9da7da4f..3e1cee11c2 100644 --- a/pages/api/custom-inputs/_post.ts +++ b/pages/api/custom-inputs/_post.ts @@ -32,7 +32,7 @@ async function postHandler(req: NextApiRequest) { const eventType = await prisma.eventType.findFirst({ where: { id: eventTypeId, userId }, }); - if (!eventType) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + if (!eventType) throw new HttpError({ statusCode: 403, message: "Forbidden" }); } const data = await prisma.eventTypeCustomInput.create({ diff --git a/pages/api/event-types/[id]/_auth-middleware.ts b/pages/api/event-types/[id]/_auth-middleware.ts index dd5fc90109..ba6a4da699 100644 --- a/pages/api/event-types/[id]/_auth-middleware.ts +++ b/pages/api/event-types/[id]/_auth-middleware.ts @@ -11,7 +11,7 @@ async function authMiddleware(req: NextApiRequest) { const eventType = await prisma.eventType.findFirst({ where: { id, users: { some: { id: userId } } }, }); - if (!eventType) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + if (!eventType) throw new HttpError({ statusCode: 403, message: "Forbidden" }); } export default authMiddleware; diff --git a/pages/api/event-types/[id]/_delete.ts b/pages/api/event-types/[id]/_delete.ts index a4fbec2e2b..54b776d801 100644 --- a/pages/api/event-types/[id]/_delete.ts +++ b/pages/api/event-types/[id]/_delete.ts @@ -46,7 +46,7 @@ async function checkPermissions(req: NextApiRequest) { if (isAdmin) return; /** Only event type owners can delete it */ const eventType = await prisma.eventType.findFirst({ where: { id, userId } }); - if (!eventType) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + if (!eventType) throw new HttpError({ statusCode: 403, message: "Forbidden" }); } export default defaultResponder(deleteHandler); diff --git a/pages/api/event-types/[id]/_patch.ts b/pages/api/event-types/[id]/_patch.ts index 28956e15df..fc0ba28baa 100644 --- a/pages/api/event-types/[id]/_patch.ts +++ b/pages/api/event-types/[id]/_patch.ts @@ -48,7 +48,7 @@ async function checkPermissions(req: NextApiRequest) { if (isAdmin) return; /** Only event type owners can modify it */ const eventType = await prisma.eventType.findFirst({ where: { id, userId } }); - if (!eventType) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + if (!eventType) throw new HttpError({ statusCode: 403, message: "Forbidden" }); } export default defaultResponder(patchHandler); diff --git a/pages/api/schedules/[id]/_auth-middleware.ts b/pages/api/schedules/[id]/_auth-middleware.ts index 18139171bf..ad884d5c5d 100644 --- a/pages/api/schedules/[id]/_auth-middleware.ts +++ b/pages/api/schedules/[id]/_auth-middleware.ts @@ -13,7 +13,7 @@ async function authMiddleware(req: NextApiRequest) { const schedule = await prisma.schedule.findFirst({ where: { id, userId }, }); - if (!schedule) throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + if (!schedule) throw new HttpError({ statusCode: 403, message: "Forbidden" }); } export default authMiddleware; diff --git a/pages/api/users/[userId]/_delete.ts b/pages/api/users/[userId]/_delete.ts index 391e341244..9d512985eb 100644 --- a/pages/api/users/[userId]/_delete.ts +++ b/pages/api/users/[userId]/_delete.ts @@ -34,7 +34,7 @@ export async function deleteHandler(req: NextApiRequest) { const query = schemaQueryUserId.parse(req.query); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user if (!isAdmin && query.userId !== req.userId) - throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + throw new HttpError({ statusCode: 403, message: "Forbidden" }); const user = await prisma.user.findUnique({ where: { id: query.userId } }); if (!user) throw new HttpError({ statusCode: 404, message: "User not found" }); diff --git a/pages/api/users/[userId]/_get.ts b/pages/api/users/[userId]/_get.ts index e379c5fbf1..ba9c8f61b5 100644 --- a/pages/api/users/[userId]/_get.ts +++ b/pages/api/users/[userId]/_get.ts @@ -36,7 +36,7 @@ export async function getHandler(req: NextApiRequest) { const query = schemaQueryUserId.parse(req.query); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user if (!isAdmin && query.userId !== req.userId) - throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + throw new HttpError({ statusCode: 403, message: "Forbidden" }); const data = await prisma.user.findUnique({ where: { id: query.userId } }); const user = schemaUserReadPublic.parse(data); return { user }; diff --git a/pages/api/users/[userId]/_patch.ts b/pages/api/users/[userId]/_patch.ts index 9e6fee7f91..aca10a89bb 100644 --- a/pages/api/users/[userId]/_patch.ts +++ b/pages/api/users/[userId]/_patch.ts @@ -56,7 +56,7 @@ export async function patchHandler(req: NextApiRequest) { const query = schemaQueryUserId.parse(req.query); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user if (!isAdmin && query.userId !== req.userId) - throw new HttpError({ statusCode: 401, message: "Unauthorized" }); + throw new HttpError({ statusCode: 403, message: "Forbidden" }); const body = schemaUserEditBodyParams.parse(req.body); const userSchedules = await prisma.schedule.findMany({ From 07b011424f8a8f83f8846cde08c6b30419096c3d Mon Sep 17 00:00:00 2001 From: zomars Date: Sat, 15 Oct 2022 10:54:22 -0600 Subject: [PATCH 529/658] Formatting --- pages/api/users/[userId]/_delete.ts | 3 +-- pages/api/users/[userId]/_get.ts | 3 +-- pages/api/users/[userId]/_patch.ts | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/pages/api/users/[userId]/_delete.ts b/pages/api/users/[userId]/_delete.ts index 9d512985eb..46ab08e5f9 100644 --- a/pages/api/users/[userId]/_delete.ts +++ b/pages/api/users/[userId]/_delete.ts @@ -33,8 +33,7 @@ export async function deleteHandler(req: NextApiRequest) { const { prisma, isAdmin } = req; const query = schemaQueryUserId.parse(req.query); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user - if (!isAdmin && query.userId !== req.userId) - throw new HttpError({ statusCode: 403, message: "Forbidden" }); + if (!isAdmin && query.userId !== req.userId) throw new HttpError({ statusCode: 403, message: "Forbidden" }); const user = await prisma.user.findUnique({ where: { id: query.userId } }); if (!user) throw new HttpError({ statusCode: 404, message: "User not found" }); diff --git a/pages/api/users/[userId]/_get.ts b/pages/api/users/[userId]/_get.ts index ba9c8f61b5..360103560b 100644 --- a/pages/api/users/[userId]/_get.ts +++ b/pages/api/users/[userId]/_get.ts @@ -35,8 +35,7 @@ export async function getHandler(req: NextApiRequest) { const query = schemaQueryUserId.parse(req.query); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user - if (!isAdmin && query.userId !== req.userId) - throw new HttpError({ statusCode: 403, message: "Forbidden" }); + if (!isAdmin && query.userId !== req.userId) throw new HttpError({ statusCode: 403, message: "Forbidden" }); const data = await prisma.user.findUnique({ where: { id: query.userId } }); const user = schemaUserReadPublic.parse(data); return { user }; diff --git a/pages/api/users/[userId]/_patch.ts b/pages/api/users/[userId]/_patch.ts index aca10a89bb..9af08bb210 100644 --- a/pages/api/users/[userId]/_patch.ts +++ b/pages/api/users/[userId]/_patch.ts @@ -55,8 +55,7 @@ export async function patchHandler(req: NextApiRequest) { const { prisma, isAdmin } = req; const query = schemaQueryUserId.parse(req.query); // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user - if (!isAdmin && query.userId !== req.userId) - throw new HttpError({ statusCode: 403, message: "Forbidden" }); + if (!isAdmin && query.userId !== req.userId) throw new HttpError({ statusCode: 403, message: "Forbidden" }); const body = schemaUserEditBodyParams.parse(req.body); const userSchedules = await prisma.schedule.findMany({ From ce2df7641f8979539c5a81c5b2005583565dde80 Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Wed, 19 Oct 2022 17:03:54 +0100 Subject: [PATCH 530/658] Feature/additional fields (#189) Added timeZone, attendees.(email, name, timeZone, locale), user.(email, name, timeZone, locale) & metadata --- lib/validations/booking.ts | 23 +++++++++- pages/api/bookings/[id]/_get.ts | 4 ++ pages/api/bookings/_get.ts | 4 ++ pages/api/bookings/_post.ts | 2 +- pages/api/docs.ts | 81 +++++++++++++++++++++++++++++++++ 5 files changed, 111 insertions(+), 3 deletions(-) diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index 31deb5cff5..9d70d4c6d5 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -import { _BookingModel as Booking } from "@calcom/prisma/zod"; +import { _BookingModel as Booking, _AttendeeModel, _UserModel } from "@calcom/prisma/zod"; import { extendedBookingCreateBody } from "@calcom/prisma/zod-utils"; import { schemaQueryUserId } from "./shared/queryUserId"; @@ -27,7 +27,22 @@ const schemaBookingEditParams = z export const schemaBookingEditBodyParams = schemaBookingBaseBodyParams.merge(schemaBookingEditParams); -export const schemaBookingReadPublic = Booking.pick({ +export const schemaBookingReadPublic = Booking.extend({ + attendees: z.array( + _AttendeeModel.pick({ + email: true, + name: true, + timeZone: true, + locale: true, + }) + ), + user: _UserModel.pick({ + email: true, + name: true, + timeZone: true, + locale: true, + }), +}).pick({ id: true, userId: true, description: true, @@ -36,4 +51,8 @@ export const schemaBookingReadPublic = Booking.pick({ title: true, startTime: true, endTime: true, + timeZone: true, + attendees: true, + user: true, + metadata: true, }); diff --git a/pages/api/bookings/[id]/_get.ts b/pages/api/bookings/[id]/_get.ts index 567312261a..bcf74dc647 100644 --- a/pages/api/bookings/[id]/_get.ts +++ b/pages/api/bookings/[id]/_get.ts @@ -23,6 +23,10 @@ import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformP * responses: * 200: * description: OK + * content: + * application/json: + * schema: + * $ref: "#/components/schemas/Booking" * 401: * description: Authorization information is missing or invalid. * 404: diff --git a/pages/api/bookings/_get.ts b/pages/api/bookings/_get.ts index 0a1b2e66c8..322d8161f1 100644 --- a/pages/api/bookings/_get.ts +++ b/pages/api/bookings/_get.ts @@ -17,6 +17,10 @@ import { schemaQuerySingleOrMultipleUserIds } from "@lib/validations/shared/quer * responses: * 200: * description: OK + * content: + * application/json: + * schema: + * $ref: "#/components/schemas/ArrayOfBookings" * 401: * description: Authorization information is missing or invalid. * 404: diff --git a/pages/api/bookings/_post.ts b/pages/api/bookings/_post.ts index b76397d4a4..af3099dd85 100644 --- a/pages/api/bookings/_post.ts +++ b/pages/api/bookings/_post.ts @@ -26,7 +26,7 @@ import { defaultResponder } from "@calcom/lib/server"; * endTime: * type: string * example: 1970-01-01T17:00:00.000Z - * recurringCount: + * recurringCount: * type: number * example: 8 * tags: diff --git a/pages/api/docs.ts b/pages/api/docs.ts index d339043741..37fdddc06a 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -22,6 +22,87 @@ const swaggerHandler = withSwagger({ }, components: { securitySchemes: { ApiKeyAuth: { type: "apiKey", in: "query", name: "apiKey" } }, + schemas: { + ArrayOfBookings: { + type: "array", + items: { + $ref: "#/components/schemas/Booking", + }, + }, + Booking: { + properties: { + id: { + type: "number", + }, + description: { + type: "string", + }, + eventTypeId: { + type: "number", + }, + uid: { + type: "string", + format: "uuid", + }, + title: { + type: "string", + }, + startTime: { + type: "string", + format: "date-time", + }, + endTime: { + type: "string", + format: "date-time", + }, + timeZone: { + type: "string", + example: "Europe/London", + }, + attendees: { + type: "array", + items: { + properties: { + email: { + type: "string", + example: "example@cal.com", + }, + name: { + type: "string", + }, + timeZone: { + type: "string", + example: "Europe/London", + }, + locale: { + type: "string", + example: "en", + }, + }, + }, + }, + user: { + properties: { + email: { + type: "string", + example: "example@cal.com", + }, + name: { + type: "string", + }, + timeZone: { + type: "string", + example: "Europe/London", + }, + locale: { + type: "string", + example: "en", + }, + }, + }, + }, + }, + }, }, security: [{ ApiKeyAuth: [] }], tags: [ From 03d5f51ceb516d941aa07bcc70bf56a104c1a8a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Wed, 19 Oct 2022 12:26:12 -0600 Subject: [PATCH 531/658] Refactor/webhooks (#186) refs #175 --- lib/validations/shared/queryIdString.ts | 1 + lib/validations/webhook.ts | 49 +++--- next.config.js | 5 + pages/api/hooks/[id].ts | 177 -------------------- pages/api/hooks/index.ts | 93 ---------- pages/api/webhooks/[id]/_auth-middleware.ts | 19 +++ pages/api/webhooks/[id]/_delete.ts | 41 +++++ pages/api/webhooks/[id]/_get.ts | 42 +++++ pages/api/webhooks/[id]/_patch.ts | 62 +++++++ pages/api/webhooks/[id]/index.ts | 18 ++ pages/api/webhooks/_get.ts | 47 ++++++ pages/api/webhooks/_post.ts | 59 +++++++ pages/api/webhooks/index.ts | 10 ++ 13 files changed, 327 insertions(+), 296 deletions(-) delete mode 100644 pages/api/hooks/[id].ts delete mode 100644 pages/api/hooks/index.ts create mode 100644 pages/api/webhooks/[id]/_auth-middleware.ts create mode 100644 pages/api/webhooks/[id]/_delete.ts create mode 100644 pages/api/webhooks/[id]/_get.ts create mode 100644 pages/api/webhooks/[id]/_patch.ts create mode 100644 pages/api/webhooks/[id]/index.ts create mode 100644 pages/api/webhooks/_get.ts create mode 100644 pages/api/webhooks/_post.ts create mode 100644 pages/api/webhooks/index.ts diff --git a/lib/validations/shared/queryIdString.ts b/lib/validations/shared/queryIdString.ts index 718e26123f..97bdfa4b15 100644 --- a/lib/validations/shared/queryIdString.ts +++ b/lib/validations/shared/queryIdString.ts @@ -5,6 +5,7 @@ import { baseApiParams } from "./baseApiParams"; // Extracted out as utility function so can be reused // at different endpoints that require this validation. +/** Used for UUID style id queries */ export const schemaQueryIdAsString = baseApiParams .extend({ id: z.string(), diff --git a/lib/validations/webhook.ts b/lib/validations/webhook.ts index f5de69c45a..91d8560195 100644 --- a/lib/validations/webhook.ts +++ b/lib/validations/webhook.ts @@ -1,49 +1,40 @@ import { z } from "zod"; +import { WEBHOOK_TRIGGER_EVENTS } from "@calcom/features/webhooks/lib/constants"; import { _WebhookModel as Webhook } from "@calcom/prisma/zod"; -export const WebhookTriggerEvents = { - BOOKING_CREATED: "BOOKING_CREATED", - BOOKING_RESCHEDULED: "BOOKING_RESCHEDULED", - BOOKING_CANCELLED: "BOOKING_CANCELLED", -}; - -export const WEBHOOK_TRIGGER_EVENTS = [ - WebhookTriggerEvents.BOOKING_CANCELLED, - WebhookTriggerEvents.BOOKING_CREATED, - WebhookTriggerEvents.BOOKING_RESCHEDULED, -] as ["BOOKING_CANCELLED", "BOOKING_CREATED", "BOOKING_RESCHEDULED"]; - const schemaWebhookBaseBodyParams = Webhook.pick({ - id: true, userId: true, eventTypeId: true, eventTriggers: true, active: true, subscriberUrl: true, payloadTemplate: true, -}).partial(); +}); export const schemaWebhookCreateParams = z .object({ - subscriberUrl: z.string().url(), - eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array(), - active: z.boolean(), + // subscriberUrl: z.string().url(), + // eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array(), + // active: z.boolean(), payloadTemplate: z.string().optional().nullable(), eventTypeId: z.number().optional(), - appId: z.string().optional().nullable(), + userId: z.number().optional(), + // API shouldn't mess with Apps webhooks yet (ie. Zapier) + // appId: z.string().optional().nullable(), }) .strict(); export const schemaWebhookCreateBodyParams = schemaWebhookBaseBodyParams.merge(schemaWebhookCreateParams); -export const schemaWebhookEditBodyParams = schemaWebhookBaseBodyParams.merge( - z.object({ - payloadTemplate: z.string().optional(), - eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array().optional(), - subscriberUrl: z.string().optional(), - }) -); +export const schemaWebhookEditBodyParams = schemaWebhookBaseBodyParams + .merge( + z.object({ + eventTriggers: z.enum(WEBHOOK_TRIGGER_EVENTS).array().optional(), + }) + ) + .partial() + .strict(); export const schemaWebhookReadPublic = Webhook.pick({ id: true, @@ -51,8 +42,14 @@ export const schemaWebhookReadPublic = Webhook.pick({ eventTypeId: true, payloadTemplate: true, eventTriggers: true, + // FIXME: We have some invalid urls saved in the DB + // subscriberUrl: true, /** @todo: find out how to properly add back and validate those. */ // eventType: true, // app: true, appId: true, -}); +}).merge( + z.object({ + subscriberUrl: z.string(), + }) +); diff --git a/next.config.js b/next.config.js index 1031c0a949..7cbb49652e 100644 --- a/next.config.js +++ b/next.config.js @@ -30,6 +30,11 @@ module.exports = withAxiom( source: "/api/v:version/:rest*", destination: "/api/:rest*?version=:version", }, + // Keeps backwards compatibility with old webhook URLs + { + source: "/api/hooks/:rest*", + destination: "/api/webhooks/:rest*", + }, ], fallback: [ // These rewrites are checked after both pages/public files diff --git a/pages/api/hooks/[id].ts b/pages/api/hooks/[id].ts deleted file mode 100644 index 4c0e51ab69..0000000000 --- a/pages/api/hooks/[id].ts +++ /dev/null @@ -1,177 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { WebhookResponse } from "@lib/types"; -import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; -import { schemaWebhookEditBodyParams, schemaWebhookReadPublic } from "@lib/validations/webhook"; - -export async function WebhookById( - { method, query, body, userId, prisma }: NextApiRequest, - res: NextApiResponse -) { - const safeQuery = schemaQueryIdAsString.safeParse(query); - if (!safeQuery.success) { - res.status(400).json({ message: "Your query was invalid" }); - return; - } - const data = await prisma.webhook.findMany({ where: { userId } }); - const userWebhooks = data.map((webhook) => webhook.id); - if (!userWebhooks.includes(safeQuery.data.id)) res.status(401).json({ message: "Unauthorized" }); - else { - switch (method) { - /** - * @swagger - * /hooks/{id}: - * get: - * summary: Find a webhook - * operationId: getWebhookById - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the webhook to get - * security: - * - ApiKeyAuth: [] - * tags: - * - hooks - * externalDocs: - * url: https://docs.cal.com/hooks - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Webhook was not found - */ - case "GET": - await prisma.webhook - .findUnique({ where: { id: safeQuery.data.id } }) - .then((data) => schemaWebhookReadPublic.parse(data)) - .then((webhook) => res.status(200).json({ webhook })) - .catch((error: Error) => - res.status(404).json({ - message: `Webhook with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - /** - * @swagger - * /hooks/{id}: - * patch: - * summary: Edit an existing webhook - * operationId: editWebhookById - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the webhook to edit - * security: - * - ApiKeyAuth: [] - * tags: - * - hooks - * externalDocs: - * url: https://docs.cal.com/hooks - * responses: - * 201: - * description: OK, webhook edited successfuly - * 400: - * description: Bad request. Webhook body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - case "PATCH": - const safeBody = schemaWebhookEditBodyParams.safeParse(body); - if (!safeBody.success) { - { - res.status(400).json({ message: "Invalid request body" }); - return; - } - } - if (safeBody.data.eventTypeId) { - const team = await prisma.team.findFirst({ - where: { - eventTypes: { - some: { - id: safeBody.data.eventTypeId, - }, - }, - }, - include: { - members: true, - }, - }); - - // Team should be available and the user should be a member of the team - if (!team?.members.some((membership) => membership.userId === userId)) { - res.status(401).json({ message: "Unauthorized" }); - return; - } - } - await prisma.webhook - .update({ where: { id: safeQuery.data.id }, data: safeBody.data }) - .then((data) => schemaWebhookReadPublic.parse(data)) - .then((webhook) => res.status(200).json({ webhook })) - .catch((error: Error) => - res.status(404).json({ - message: `Webhook with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - /** - * @swagger - * /hooks/{id}: - * delete: - * summary: Remove an existing hook - * operationId: removeWebhookById - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: Numeric ID of the hooks to delete - * security: - * - ApiKeyAuth: [] - * tags: - * - hooks - * externalDocs: - * url: https://docs.cal.com/hooks - * responses: - * 201: - * description: OK, hook removed successfuly - * 400: - * description: Bad request. hook id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - case "DELETE": - await prisma.webhook - .delete({ where: { id: safeQuery.data.id } }) - .then(() => - res.status(200).json({ - message: `Webhook with id: ${safeQuery.data.id} deleted`, - }) - ) - .catch((error: Error) => - res.status(404).json({ - message: `Webhook with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } - } -} - -export default withMiddleware("HTTP_GET_DELETE_PATCH")(WebhookById); diff --git a/pages/api/hooks/index.ts b/pages/api/hooks/index.ts deleted file mode 100644 index 0bdb7470bf..0000000000 --- a/pages/api/hooks/index.ts +++ /dev/null @@ -1,93 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; -import { v4 as uuidv4 } from "uuid"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { WebhookResponse, WebhooksResponse } from "@lib/types"; -import { schemaWebhookCreateBodyParams } from "@lib/validations/webhook"; - -async function createOrlistAllWebhooks( - { method, body, userId, prisma }: NextApiRequest, - res: NextApiResponse -) { - if (method === "GET") { - /** - * @swagger - * /hooks: - * get: - * summary: Find all webhooks - * operationId: listWebhooks - * tags: - * - hooks - * externalDocs: - * url: https://docs.cal.com/webhooks - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No webhooks were found - */ - const webhooks = await prisma.webhook - .findMany({ where: { userId } }) - .catch((error) => console.log(error)); - if (!webhooks) { - console.log(); - res.status(404).json({ message: "No webhooks were found" }); - } else res.status(200).json({ webhooks }); - } else if (method === "POST") { - /** - * @swagger - * /hooks: - * post: - * summary: Creates a new webhook - * operationId: addWebhook - * tags: - * - webhooks - * externalDocs: - * url: https://docs.cal.com/webhooks - * responses: - * 201: - * description: OK, webhook created - * 400: - * description: Bad request. webhook body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - const safe = schemaWebhookCreateBodyParams.safeParse(body); - if (!safe.success) { - res.status(400).json({ message: "Invalid request body" }); - return; - } - if (safe.data.eventTypeId) { - const team = await prisma.team.findFirst({ - where: { - eventTypes: { - some: { - id: safe.data.eventTypeId, - }, - }, - }, - include: { - members: true, - }, - }); - - // Team should be available and the user should be a member of the team - if (!team?.members.some((membership) => membership.userId === userId)) { - res.status(401).json({ message: "Unauthorized" }); - return; - } - } - const data = await prisma.webhook.create({ data: { id: uuidv4(), ...safe.data, userId } }); - if (data) res.status(201).json({ webhook: data, message: "Webhook created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new webhook", - error, - }); - } else res.status(405).json({ message: `Method ${method} not allowed` }); -} - -export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllWebhooks); diff --git a/pages/api/webhooks/[id]/_auth-middleware.ts b/pages/api/webhooks/[id]/_auth-middleware.ts new file mode 100644 index 0000000000..ef45e638ed --- /dev/null +++ b/pages/api/webhooks/[id]/_auth-middleware.ts @@ -0,0 +1,19 @@ +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; + +import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; + +async function authMiddleware(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const { id } = schemaQueryIdAsString.parse(req.query); + // Admins can just skip this check + if (isAdmin) return; + // Check if the current user can access the webhook + const webhook = await prisma.webhook.findFirst({ + where: { id, appId: null, OR: [{ userId }, { eventType: { team: { members: { some: { userId } } } } }] }, + }); + if (!webhook) throw new HttpError({ statusCode: 403, message: "Forbidden" }); +} + +export default authMiddleware; diff --git a/pages/api/webhooks/[id]/_delete.ts b/pages/api/webhooks/[id]/_delete.ts new file mode 100644 index 0000000000..cb0998bd94 --- /dev/null +++ b/pages/api/webhooks/[id]/_delete.ts @@ -0,0 +1,41 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; + +/** + * @swagger + * /webhooks/{id}: + * delete: + * summary: Remove an existing hook + * operationId: removeWebhookById + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the hooks to delete + * security: + * - ApiKeyAuth: [] + * tags: + * - hooks + * externalDocs: + * url: https://docs.cal.com/hooks + * responses: + * 201: + * description: OK, hook removed successfully + * 400: + * description: Bad request. hook id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdAsString.parse(query); + await prisma.webhook.delete({ where: { id } }); + return { message: `Schedule with id: ${id} deleted successfully` }; +} + +export default defaultResponder(deleteHandler); diff --git a/pages/api/webhooks/[id]/_get.ts b/pages/api/webhooks/[id]/_get.ts new file mode 100644 index 0000000000..3b9639c2c6 --- /dev/null +++ b/pages/api/webhooks/[id]/_get.ts @@ -0,0 +1,42 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; +import { schemaWebhookReadPublic } from "@lib/validations/webhook"; + +/** + * @swagger + * /webhooks/{id}: + * get: + * summary: Find a webhook + * operationId: getWebhookById + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the webhook to get + * security: + * - ApiKeyAuth: [] + * tags: + * - hooks + * externalDocs: + * url: https://docs.cal.com/hooks + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Webhook was not found + */ +export async function getHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdAsString.parse(query); + const data = await prisma.webhook.findUniqueOrThrow({ where: { id } }); + return { webhook: schemaWebhookReadPublic.parse(data) }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/webhooks/[id]/_patch.ts b/pages/api/webhooks/[id]/_patch.ts new file mode 100644 index 0000000000..dbcc8c8306 --- /dev/null +++ b/pages/api/webhooks/[id]/_patch.ts @@ -0,0 +1,62 @@ +import type { Prisma } from "@prisma/client"; +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; +import { schemaWebhookEditBodyParams, schemaWebhookReadPublic } from "@lib/validations/webhook"; + +/** + * @swagger + * /webhooks/{id}: + * patch: + * summary: Edit an existing webhook + * operationId: editWebhookById + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: Numeric ID of the webhook to edit + * security: + * - ApiKeyAuth: [] + * tags: + * - hooks + * externalDocs: + * url: https://docs.cal.com/hooks + * responses: + * 201: + * description: OK, webhook edited successfully + * 400: + * description: Bad request. Webhook body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function patchHandler(req: NextApiRequest) { + const { prisma, query, userId, isAdmin } = req; + const { id } = schemaQueryIdAsString.parse(query); + const { eventTypeId, userId: bodyUserId, ...data } = schemaWebhookEditBodyParams.parse(req.body); + const args: Prisma.WebhookUpdateArgs = { where: { id }, data }; + + if (eventTypeId) { + const where: Prisma.EventTypeWhereInput = { id: eventTypeId }; + if (!isAdmin) where.userId = userId; + await prisma.eventType.findFirstOrThrow({ where }); + args.data.eventTypeId = eventTypeId; + } + + if (!isAdmin && bodyUserId) throw new HttpError({ statusCode: 403, message: `ADMIN required for userId` }); + + if (isAdmin && bodyUserId) { + const where: Prisma.UserWhereInput = { id: userId }; + await prisma.user.findFirstOrThrow({ where }); + args.data.userId = userId; + } + + const result = await prisma.webhook.update(args); + return { webhook: schemaWebhookReadPublic.parse(result) }; +} + +export default defaultResponder(patchHandler); diff --git a/pages/api/webhooks/[id]/index.ts b/pages/api/webhooks/[id]/index.ts new file mode 100644 index 0000000000..cbff13f006 --- /dev/null +++ b/pages/api/webhooks/[id]/index.ts @@ -0,0 +1,18 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import { defaultHandler, defaultResponder } from "@calcom/lib/server"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; + +import authMiddleware from "./_auth-middleware"; + +export default withMiddleware("HTTP_GET_DELETE_PATCH")( + defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { + await authMiddleware(req); + return defaultHandler({ + GET: import("./_get"), + PATCH: import("./_patch"), + DELETE: import("./_delete"), + })(req, res); + }) +); diff --git a/pages/api/webhooks/_get.ts b/pages/api/webhooks/_get.ts new file mode 100644 index 0000000000..fbf4665561 --- /dev/null +++ b/pages/api/webhooks/_get.ts @@ -0,0 +1,47 @@ +import type { Prisma } from "@prisma/client"; +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaQuerySingleOrMultipleUserIds } from "@lib/validations/shared/queryUserId"; +import { schemaWebhookReadPublic } from "@lib/validations/webhook"; + +/** + * @swagger + * /webhooks: + * get: + * summary: Find all webhooks + * operationId: listWebhooks + * tags: + * - hooks + * externalDocs: + * url: https://docs.cal.com/webhooks + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No webhooks were found + */ +async function getHandler(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const args: Prisma.WebhookFindManyArgs = isAdmin + ? {} + : { where: { OR: [{ eventType: { userId } }, { userId }] } }; + + /** Only admins can query other users */ + if (!isAdmin && req.query.userId) throw new HttpError({ statusCode: 403, message: "ADMIN required" }); + if (isAdmin && req.query.userId) { + const query = schemaQuerySingleOrMultipleUserIds.parse(req.query); + const userIds = Array.isArray(query.userId) ? query.userId : [query.userId || userId]; + args.where = { OR: [{ eventType: { userId: { in: userIds } } }, { userId: { in: userIds } }] }; + if (Array.isArray(query.userId)) args.orderBy = { userId: "asc", eventType: { userId: "asc" } }; + } + + const data = await prisma.webhook.findMany(args); + return { webhooks: data.map((v) => schemaWebhookReadPublic.parse(v)) }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/webhooks/_post.ts b/pages/api/webhooks/_post.ts new file mode 100644 index 0000000000..dd7f97dd87 --- /dev/null +++ b/pages/api/webhooks/_post.ts @@ -0,0 +1,59 @@ +import type { Prisma } from "@prisma/client"; +import type { NextApiRequest } from "next"; +import { v4 as uuidv4 } from "uuid"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaWebhookCreateBodyParams, schemaWebhookReadPublic } from "@lib/validations/webhook"; + +/** + * @swagger + * /hooks: + * post: + * summary: Creates a new webhook + * operationId: addWebhook + * tags: + * - webhooks + * externalDocs: + * url: https://docs.cal.com/webhooks + * responses: + * 201: + * description: OK, webhook created + * 400: + * description: Bad request. webhook body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function postHandler(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const { eventTypeId, userId: bodyUserId, ...body } = schemaWebhookCreateBodyParams.parse(req.body); + const args: Prisma.WebhookCreateArgs = { data: { id: uuidv4(), ...body } }; + + // If no event type, we assume is for the current user. If admin we run more checks below... + if (!eventTypeId) args.data.userId = userId; + + if (eventTypeId) { + const where: Prisma.EventTypeWhereInput = { id: eventTypeId }; + if (!isAdmin) where.userId = userId; + await prisma.eventType.findFirstOrThrow({ where }); + args.data.eventTypeId = eventTypeId; + } + + if (!isAdmin && bodyUserId) throw new HttpError({ statusCode: 403, message: `ADMIN required for userId` }); + + if (isAdmin && bodyUserId) { + const where: Prisma.UserWhereInput = { id: userId }; + await prisma.user.findFirstOrThrow({ where }); + args.data.userId = userId; + } + + const data = await prisma.webhook.create(args); + + return { + webhook: schemaWebhookReadPublic.parse(data), + message: "Webhook created successfully", + }; +} + +export default defaultResponder(postHandler); diff --git a/pages/api/webhooks/index.ts b/pages/api/webhooks/index.ts new file mode 100644 index 0000000000..c07846423f --- /dev/null +++ b/pages/api/webhooks/index.ts @@ -0,0 +1,10 @@ +import { defaultHandler } from "@calcom/lib/server"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; + +export default withMiddleware("HTTP_GET_OR_POST")( + defaultHandler({ + GET: import("./_get"), + POST: import("./_post"), + }) +); From ecd20d63c91612904542ed03a5b02809c1269802 Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Wed, 19 Oct 2022 19:35:34 +0100 Subject: [PATCH 532/658] Added attendees & user (#192) --- pages/api/bookings/[id]/_get.ts | 5 ++++- pages/api/bookings/_get.ts | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/pages/api/bookings/[id]/_get.ts b/pages/api/bookings/[id]/_get.ts index bcf74dc647..ea83d649aa 100644 --- a/pages/api/bookings/[id]/_get.ts +++ b/pages/api/bookings/[id]/_get.ts @@ -35,7 +35,10 @@ import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformP export async function getHandler(req: NextApiRequest) { const { prisma, query } = req; const { id } = schemaQueryIdParseInt.parse(query); - const booking = await prisma.booking.findUnique({ where: { id } }); + const booking = await prisma.booking.findUnique({ + where: { id }, + include: { attendees: true, user: true }, + }); return { booking: schemaBookingReadPublic.parse(booking) }; } diff --git a/pages/api/bookings/_get.ts b/pages/api/bookings/_get.ts index 322d8161f1..d6c7d65a2a 100644 --- a/pages/api/bookings/_get.ts +++ b/pages/api/bookings/_get.ts @@ -29,6 +29,10 @@ import { schemaQuerySingleOrMultipleUserIds } from "@lib/validations/shared/quer async function handler(req: NextApiRequest) { const { userId, isAdmin, prisma } = req; const args: Prisma.BookingFindManyArgs = isAdmin ? {} : { where: { userId } }; + args.include = { + attendees: true, + user: true, + }; /** Only admins can query other users */ if (isAdmin && req.query.userId) { const query = schemaQuerySingleOrMultipleUserIds.parse(req.query); From 1f9be423adaa605846c16773d2266b4629439b2b Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Thu, 20 Oct 2022 18:26:43 +0100 Subject: [PATCH 533/658] Set start and endTime to iso8601 (#198) --- lib/validations/booking.ts | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index 9d70d4c6d5..727ff0b1db 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -1,7 +1,7 @@ import { z } from "zod"; import { _BookingModel as Booking, _AttendeeModel, _UserModel } from "@calcom/prisma/zod"; -import { extendedBookingCreateBody } from "@calcom/prisma/zod-utils"; +import { extendedBookingCreateBody, iso8601 } from "@calcom/prisma/zod-utils"; import { schemaQueryUserId } from "./shared/queryUserId"; @@ -20,28 +20,32 @@ export const schemaBookingCreateBodyParams = extendedBookingCreateBody.merge(sch const schemaBookingEditParams = z .object({ title: z.string().optional(), - startTime: z.date().optional(), - endTime: z.date().optional(), + startTime: iso8601.optional(), + endTime: iso8601.optional(), }) .strict(); export const schemaBookingEditBodyParams = schemaBookingBaseBodyParams.merge(schemaBookingEditParams); export const schemaBookingReadPublic = Booking.extend({ - attendees: z.array( - _AttendeeModel.pick({ + attendees: z + .array( + _AttendeeModel.pick({ + email: true, + name: true, + timeZone: true, + locale: true, + }) + ) + .optional(), + user: _UserModel + .pick({ email: true, name: true, timeZone: true, locale: true, }) - ), - user: _UserModel.pick({ - email: true, - name: true, - timeZone: true, - locale: true, - }), + .optional(), }).pick({ id: true, userId: true, From f4d52b88a42b5491f34a4ccf651ee4c2dae1591a Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Thu, 20 Oct 2022 18:27:01 +0100 Subject: [PATCH 534/658] Changed req to query to allow passing in userId, not session (#197) --- pages/api/users/[userId]/_patch.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/pages/api/users/[userId]/_patch.ts b/pages/api/users/[userId]/_patch.ts index 9af08bb210..dd136a26ee 100644 --- a/pages/api/users/[userId]/_patch.ts +++ b/pages/api/users/[userId]/_patch.ts @@ -42,14 +42,16 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations * required: true * description: ID of the user to edit * tags: - * - users + * - users * responses: - * 201: + * 200: * description: OK, user edited successfuly * 400: - * description: Bad request. User body is invalid. + * description: Bad request. User body is invalid. * 401: - * description: Authorization information is missing or invalid. + * description: Authorization information is missing or invalid. + * 403: + * description: Insufficient permissions to access resource. */ export async function patchHandler(req: NextApiRequest) { const { prisma, isAdmin } = req; @@ -59,7 +61,7 @@ export async function patchHandler(req: NextApiRequest) { const body = schemaUserEditBodyParams.parse(req.body); const userSchedules = await prisma.schedule.findMany({ - where: { userId: req.userId }, + where: { userId: query.userId }, }); const userSchedulesIds = userSchedules.map((schedule) => schedule.id); // @note: here we make sure user can only make as default his own scheudles @@ -70,7 +72,7 @@ export async function patchHandler(req: NextApiRequest) { }); } const data = await prisma.user.update({ - where: { id: req.userId }, + where: { id: query.userId }, data: body, }); const user = schemaUserReadPublic.parse(data); From 109377b65cad6370371e200d78c17b8cceeb6405 Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Thu, 20 Oct 2022 18:27:24 +0100 Subject: [PATCH 535/658] Returns bookings in response where user is attending (#196) --- pages/api/bookings/_get.ts | 46 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/pages/api/bookings/_get.ts b/pages/api/bookings/_get.ts index d6c7d65a2a..20f1117923 100644 --- a/pages/api/bookings/_get.ts +++ b/pages/api/bookings/_get.ts @@ -1,6 +1,7 @@ import { Prisma } from "@prisma/client"; import type { NextApiRequest } from "next"; +import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; import { schemaBookingReadPublic } from "@lib/validations/booking"; @@ -28,16 +29,57 @@ import { schemaQuerySingleOrMultipleUserIds } from "@lib/validations/shared/quer */ async function handler(req: NextApiRequest) { const { userId, isAdmin, prisma } = req; - const args: Prisma.BookingFindManyArgs = isAdmin ? {} : { where: { userId } }; + const args: Prisma.BookingFindManyArgs = {}; args.include = { attendees: true, user: true, }; + /** Only admins can query other users */ if (isAdmin && req.query.userId) { const query = schemaQuerySingleOrMultipleUserIds.parse(req.query); const userIds = Array.isArray(query.userId) ? query.userId : [query.userId || userId]; - args.where = { userId: { in: userIds } }; + const users = await prisma.user.findMany({ + where: { id: { in: userIds } }, + select: { email: true }, + }); + const userEmails = users.map((u) => u.email); + args.where = { + OR: [ + { userId: { in: userIds } }, + { + attendees: { + some: { + email: { in: userEmails }, + }, + }, + }, + ], + }; + } else if (!isAdmin) { + const user = await prisma.user.findUnique({ + where: { id: userId }, + select: { + email: true, + }, + }); + if (!user) { + throw new HttpError({ message: "User not found", statusCode: 500 }); + } + args.where = { + OR: [ + { + userId, + }, + { + attendees: { + some: { + email: user.email, + }, + }, + }, + ], + }; } const data = await prisma.booking.findMany(args); return { bookings: data.map((booking) => schemaBookingReadPublic.parse(booking)) }; From f66ed50ecb307e2a60b41b88aa9211f3ce5d599e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Thu, 20 Oct 2022 11:35:02 -0600 Subject: [PATCH 536/658] Selected Calendars endpoints refactor (#193) refs #175 --- lib/validations/selected-calendar.ts | 57 +++-- package.json | 2 +- pages/api/selected-calendars/[id].ts | 210 ------------------ .../[id]/_auth-middleware.ts | 16 ++ pages/api/selected-calendars/[id]/_delete.ts | 49 ++++ pages/api/selected-calendars/[id]/_get.ts | 51 +++++ pages/api/selected-calendars/[id]/_patch.ts | 66 ++++++ pages/api/selected-calendars/[id]/index.ts | 18 ++ pages/api/selected-calendars/_get.ts | 44 ++++ pages/api/selected-calendars/_post.ts | 60 +++++ pages/api/selected-calendars/index.ts | 96 +------- 11 files changed, 352 insertions(+), 317 deletions(-) delete mode 100644 pages/api/selected-calendars/[id].ts create mode 100644 pages/api/selected-calendars/[id]/_auth-middleware.ts create mode 100644 pages/api/selected-calendars/[id]/_delete.ts create mode 100644 pages/api/selected-calendars/[id]/_get.ts create mode 100644 pages/api/selected-calendars/[id]/_patch.ts create mode 100644 pages/api/selected-calendars/[id]/index.ts create mode 100644 pages/api/selected-calendars/_get.ts create mode 100644 pages/api/selected-calendars/_post.ts diff --git a/lib/validations/selected-calendar.ts b/lib/validations/selected-calendar.ts index ffdc54b96a..e1b2138e51 100644 --- a/lib/validations/selected-calendar.ts +++ b/lib/validations/selected-calendar.ts @@ -1,25 +1,48 @@ -import { z } from "zod"; +import z from "zod"; import { _SelectedCalendarModel as SelectedCalendar } from "@calcom/prisma/zod"; -export const schemaSelectedCalendarBaseBodyParams = SelectedCalendar.omit({ userId: true }).partial(); +import { schemaQueryIdAsString } from "./shared/queryIdString"; +import { schemaQueryIdParseInt } from "./shared/queryIdTransformParseInt"; + +export const schemaSelectedCalendarBaseBodyParams = SelectedCalendar; export const schemaSelectedCalendarPublic = SelectedCalendar.omit({}); -const schemaSelectedCalendarRequiredParams = z.object({ - externalId: z.string(), - integration: z.string(), - user: z.object({ - connect: z.object({ - id: z.number().optional(), - username: z.string().optional(), - email: z.string().optional(), - }), - // FIXME: Provide valid UserModel schema here, but not sure how yet. - create: z.any(), - }), +export const schemaSelectedCalendarBodyParams = schemaSelectedCalendarBaseBodyParams.partial({ + userId: true, }); -export const schemaSelectedCalendarBodyParams = schemaSelectedCalendarBaseBodyParams.merge( - schemaSelectedCalendarRequiredParams -); +export const schemaSelectedCalendarUpdateBodyParams = schemaSelectedCalendarBaseBodyParams.partial(); + +export const selectedCalendarIdSchema = schemaQueryIdAsString.transform((v, ctx) => { + /** We can assume the first part is the userId since it's an integer */ + const [userIdStr, ...rest] = v.id.split("_"); + /** We can assume that the remainder is both the integration type and external id combined */ + const integration_externalId = rest.join("_"); + /** + * Since we only handle calendars here we can split by `_calendar_` and re add it later on. + * This handle special cases like `google_calendar_c_blabla@group.calendar.google.com` and + * `hubspot_other_calendar`. + **/ + const [_integration, externalId] = integration_externalId.split("_calendar_"); + const userIdInt = schemaQueryIdParseInt.safeParse({ id: userIdStr }); + if (!userIdInt.success) { + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "userId is not a number" }); + return z.NEVER; + } + if (!_integration) { + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "Missing integration" }); + return z.NEVER; + } + if (!externalId) { + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "Missing externalId" }); + return z.NEVER; + } + return { + userId: userIdInt.data.id, + /** We re-add the split `_calendar` string */ + integration: `${_integration}_calendar`, + externalId, + }; +}); diff --git a/package.json b/package.json index 0d6430d98c..1484a4d8e8 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,6 @@ "typescript": "^4.7.4", "tzdata": "^1.0.30", "uuid": "^8.3.2", - "zod": "^3.18.0" + "zod": "^3.19.1" } } diff --git a/pages/api/selected-calendars/[id].ts b/pages/api/selected-calendars/[id].ts deleted file mode 100644 index ea2037fba3..0000000000 --- a/pages/api/selected-calendars/[id].ts +++ /dev/null @@ -1,210 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { SelectedCalendarResponse } from "@lib/types"; -import { - schemaSelectedCalendarBodyParams, - schemaSelectedCalendarPublic, -} from "@lib/validations/selected-calendar"; -import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; - -export async function selectedCalendarById( - { method, query, body, userId, prisma }: NextApiRequest, - res: NextApiResponse -) { - const safeQuery = schemaQueryIdAsString.safeParse(query); - const safeBody = schemaSelectedCalendarBodyParams.safeParse(body); - if (!safeQuery.success) { - res.status(400).json({ message: "Your query was invalid" }); - return; - } - // This is how we set the userId and externalId in the query for managing compoundId. - const [paramUserId, integration, externalId] = safeQuery.data.id.split("_"); - if (userId !== parseInt(paramUserId)) res.status(401).json({ message: "Unauthorized" }); - else { - switch (method) { - /** - * @swagger - * /selected-calendars/{userId}_{integration}_{externalId}: - * get: - * operationId: getSelectedCalendarById - * summary: Find a selected calendar by providing the compoundId(userId_integration_externalId) separated by `_` - * parameters: - * - in: path - * name: userId - * schema: - * type: integer - * required: true - * description: userId of the selected calendar to get - * - in: path - * name: externalId - * schema: - * type: string - * required: true - * description: externalId of the selected calendar to get - * - in: path - * name: integration - * schema: - * type: string - * required: true - * description: integration of the selected calendar to get - * tags: - * - selected-calendars - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: SelectedCalendar was not found - */ - case "GET": - await prisma.selectedCalendar - .findUnique({ - where: { - userId_integration_externalId: { - userId: userId, - integration: integration, - externalId: externalId, - }, - }, - }) - .then((selectedCalendar) => schemaSelectedCalendarPublic.parse(selectedCalendar)) - .then((selected_calendar) => res.status(200).json({ selected_calendar })) - .catch((error: Error) => - res.status(404).json({ - message: `SelectedCalendar with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - - /** - * @swagger - * /selected-calendars/{userId}_{integration}_{externalId}: - * patch: - * operationId: editSelectedCalendarById - * summary: Edit a selected calendar - * parameters: - * - in: path - * name: userId - * schema: - * type: integer - * required: true - * description: userId of the selected calendar to get - * - in: path - * name: externalId - * schema: - * type: string - * required: true - * description: externalId of the selected calendar to get - * - in: path - * name: integration - * schema: - * type: string - * required: true - * description: integration of the selected calendar to get - * tags: - * - selected-calendars - * responses: - * 201: - * description: OK, selected-calendar edited successfuly - * 400: - * description: Bad request. SelectedCalendar body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - case "PATCH": - if (!safeBody.success) { - { - res.status(400).json({ message: "Invalid request body" }); - return; - } - } - await prisma.selectedCalendar - .update({ - where: { - userId_integration_externalId: { - userId: userId, - integration: integration, - externalId: externalId, - }, - }, - data: safeBody.data, - }) - .then((selectedCalendar) => schemaSelectedCalendarPublic.parse(selectedCalendar)) - .then((selected_calendar) => res.status(200).json({ selected_calendar })) - .catch((error: Error) => - res.status(404).json({ - message: `SelectedCalendar with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - /** - * @swagger - * /selected-calendars/{userId}_{integration}_{externalId}: - * delete: - * operationId: removeSelectedCalendarById - * summary: Remove a selected calendar - * parameters: - * - in: path - * name: userId - * schema: - * type: integer - * required: true - * description: userId of the selected calendar to get - * - in: path - * name: externalId - * schema: - * type: integer - * required: true - * description: externalId of the selected-calendar to get - * - in: path - * name: integration - * schema: - * type: string - * required: true - * description: integration of the selected calendar to get - * tags: - * - selected-calendars - * responses: - * 201: - * description: OK, selected-calendar removed successfuly - * 400: - * description: Bad request. SelectedCalendar id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - case "DELETE": - await prisma.selectedCalendar - .delete({ - where: { - userId_integration_externalId: { - userId: userId, - integration: integration, - externalId: externalId, - }, - }, - }) - .then(() => - res.status(200).json({ - message: `SelectedCalendar with id: ${safeQuery.data.id} deleted successfully`, - }) - ) - .catch((error: Error) => - res.status(404).json({ - message: `SelectedCalendar with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } - } -} - -export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdString(selectedCalendarById)); diff --git a/pages/api/selected-calendars/[id]/_auth-middleware.ts b/pages/api/selected-calendars/[id]/_auth-middleware.ts new file mode 100644 index 0000000000..1a9c74f305 --- /dev/null +++ b/pages/api/selected-calendars/[id]/_auth-middleware.ts @@ -0,0 +1,16 @@ +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; + +import { selectedCalendarIdSchema } from "@lib/validations/selected-calendar"; + +async function authMiddleware(req: NextApiRequest) { + const { userId, isAdmin } = req; + const { userId: queryUserId } = selectedCalendarIdSchema.parse(req.query); + // Admins can just skip this check + if (isAdmin) return; + // Check if the current user requesting is the same as the one being requested + if (userId !== queryUserId) throw new HttpError({ statusCode: 403, message: "Forbidden" }); +} + +export default authMiddleware; diff --git a/pages/api/selected-calendars/[id]/_delete.ts b/pages/api/selected-calendars/[id]/_delete.ts new file mode 100644 index 0000000000..c187adebbf --- /dev/null +++ b/pages/api/selected-calendars/[id]/_delete.ts @@ -0,0 +1,49 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { selectedCalendarIdSchema } from "@lib/validations/selected-calendar"; + +/** + * @swagger + * /selected-calendars/{userId}_{integration}_{externalId}: + * delete: + * operationId: removeSelectedCalendarById + * summary: Remove a selected calendar + * parameters: + * - in: path + * name: userId + * schema: + * type: integer + * required: true + * description: userId of the selected calendar to get + * - in: path + * name: externalId + * schema: + * type: integer + * required: true + * description: externalId of the selected-calendar to get + * - in: path + * name: integration + * schema: + * type: string + * required: true + * description: integration of the selected calendar to get + * tags: + * - selected-calendars + * responses: + * 201: + * description: OK, selected-calendar removed successfully + * 400: + * description: Bad request. SelectedCalendar id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteHandler(req: NextApiRequest) { + const { prisma, query } = req; + const userId_integration_externalId = selectedCalendarIdSchema.parse(query); + await prisma.selectedCalendar.delete({ where: { userId_integration_externalId } }); + return { message: `Selected Calendar with id: ${query.id} deleted successfully` }; +} + +export default defaultResponder(deleteHandler); diff --git a/pages/api/selected-calendars/[id]/_get.ts b/pages/api/selected-calendars/[id]/_get.ts new file mode 100644 index 0000000000..7dd8d9e055 --- /dev/null +++ b/pages/api/selected-calendars/[id]/_get.ts @@ -0,0 +1,51 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaSelectedCalendarPublic, selectedCalendarIdSchema } from "@lib/validations/selected-calendar"; + +/** + * @swagger + * /selected-calendars/{userId}_{integration}_{externalId}: + * get: + * operationId: getSelectedCalendarById + * summary: Find a selected calendar by providing the compoundId(userId_integration_externalId) separated by `_` + * parameters: + * - in: path + * name: userId + * schema: + * type: integer + * required: true + * description: userId of the selected calendar to get + * - in: path + * name: externalId + * schema: + * type: string + * required: true + * description: externalId of the selected calendar to get + * - in: path + * name: integration + * schema: + * type: string + * required: true + * description: integration of the selected calendar to get + * tags: + * - selected-calendars + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: SelectedCalendar was not found + */ +export async function getHandler(req: NextApiRequest) { + const { prisma, query } = req; + const userId_integration_externalId = selectedCalendarIdSchema.parse(query); + const data = await prisma.selectedCalendar.findUniqueOrThrow({ + where: { userId_integration_externalId }, + }); + return { selected_calendar: schemaSelectedCalendarPublic.parse(data) }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/selected-calendars/[id]/_patch.ts b/pages/api/selected-calendars/[id]/_patch.ts new file mode 100644 index 0000000000..064bee1dbc --- /dev/null +++ b/pages/api/selected-calendars/[id]/_patch.ts @@ -0,0 +1,66 @@ +import type { Prisma } from "@prisma/client"; +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { + schemaSelectedCalendarPublic, + schemaSelectedCalendarUpdateBodyParams, + selectedCalendarIdSchema, +} from "@lib/validations/selected-calendar"; + +/** + * @swagger + * /selected-calendars/{userId}_{integration}_{externalId}: + * patch: + * operationId: editSelectedCalendarById + * summary: Edit a selected calendar + * parameters: + * - in: path + * name: userId + * schema: + * type: integer + * required: true + * description: userId of the selected calendar to get + * - in: path + * name: externalId + * schema: + * type: string + * required: true + * description: externalId of the selected calendar to get + * - in: path + * name: integration + * schema: + * type: string + * required: true + * description: integration of the selected calendar to get + * tags: + * - selected-calendars + * responses: + * 201: + * description: OK, selected-calendar edited successfully + * 400: + * description: Bad request. SelectedCalendar body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function patchHandler(req: NextApiRequest) { + const { prisma, query, userId, isAdmin } = req; + const userId_integration_externalId = selectedCalendarIdSchema.parse(query); + const { userId: bodyUserId, ...data } = schemaSelectedCalendarUpdateBodyParams.parse(req.body); + const args: Prisma.SelectedCalendarUpdateArgs = { where: { userId_integration_externalId }, data }; + + if (!isAdmin && bodyUserId) throw new HttpError({ statusCode: 403, message: `ADMIN required for userId` }); + + if (isAdmin && bodyUserId) { + const where: Prisma.UserWhereInput = { id: userId }; + await prisma.user.findFirstOrThrow({ where }); + args.data.userId = userId; + } + + const result = await prisma.selectedCalendar.update(args); + return { selected_calendar: schemaSelectedCalendarPublic.parse(result) }; +} + +export default defaultResponder(patchHandler); diff --git a/pages/api/selected-calendars/[id]/index.ts b/pages/api/selected-calendars/[id]/index.ts new file mode 100644 index 0000000000..cbff13f006 --- /dev/null +++ b/pages/api/selected-calendars/[id]/index.ts @@ -0,0 +1,18 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import { defaultHandler, defaultResponder } from "@calcom/lib/server"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; + +import authMiddleware from "./_auth-middleware"; + +export default withMiddleware("HTTP_GET_DELETE_PATCH")( + defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { + await authMiddleware(req); + return defaultHandler({ + GET: import("./_get"), + PATCH: import("./_patch"), + DELETE: import("./_delete"), + })(req, res); + }) +); diff --git a/pages/api/selected-calendars/_get.ts b/pages/api/selected-calendars/_get.ts new file mode 100644 index 0000000000..ebbbe19b5c --- /dev/null +++ b/pages/api/selected-calendars/_get.ts @@ -0,0 +1,44 @@ +import type { Prisma } from "@prisma/client"; +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaSelectedCalendarPublic } from "@lib/validations/selected-calendar"; +import { schemaQuerySingleOrMultipleUserIds } from "@lib/validations/shared/queryUserId"; + +/** + * @swagger + * /selected-calendars: + * get: + * operationId: listSelectedCalendars + * summary: Find all selected calendars + * tags: + * - selected-calendars + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No selected calendars were found + */ +async function getHandler(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + /* Admin gets all selected calendar by default, otherwise only the user's ones */ + const args: Prisma.SelectedCalendarFindManyArgs = isAdmin ? {} : { where: { userId } }; + + /** Only admins can query other users */ + if (!isAdmin && req.query.userId) throw new HttpError({ statusCode: 403, message: "ADMIN required" }); + if (isAdmin && req.query.userId) { + const query = schemaQuerySingleOrMultipleUserIds.parse(req.query); + const userIds = Array.isArray(query.userId) ? query.userId : [query.userId || userId]; + args.where = { userId: { in: userIds } }; + if (Array.isArray(query.userId)) args.orderBy = { userId: "asc" }; + } + + const data = await prisma.selectedCalendar.findMany(args); + return { selected_calendars: data.map((v) => schemaSelectedCalendarPublic.parse(v)) }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/selected-calendars/_post.ts b/pages/api/selected-calendars/_post.ts new file mode 100644 index 0000000000..2118c5348f --- /dev/null +++ b/pages/api/selected-calendars/_post.ts @@ -0,0 +1,60 @@ +import type { Prisma } from "@prisma/client"; +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { + schemaSelectedCalendarBodyParams, + schemaSelectedCalendarPublic, +} from "@lib/validations/selected-calendar"; + +/** + * @swagger + * /selected-calendars: + * get: + * operationId: addSelectedCalendars + * summary: Find all selected calendars + * tags: + * - selected-calendars + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No selected calendars were found + * post: + * summary: Creates a new selected calendar + * tags: + * - selected-calendars + * responses: + * 201: + * description: OK, selected calendar created + * 400: + * description: Bad request. SelectedCalendar body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function postHandler(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const { userId: bodyUserId, ...body } = schemaSelectedCalendarBodyParams.parse(req.body); + const args: Prisma.SelectedCalendarCreateArgs = { data: { ...body, userId } }; + + if (!isAdmin && bodyUserId) throw new HttpError({ statusCode: 403, message: `ADMIN required for userId` }); + + if (isAdmin && bodyUserId) { + const where: Prisma.UserWhereInput = { id: bodyUserId }; + await prisma.user.findFirstOrThrow({ where }); + args.data.userId = userId; + } + + const data = await prisma.selectedCalendar.create(args); + + return { + selected_calendar: schemaSelectedCalendarPublic.parse(data), + message: "Selected Calendar created successfully", + }; +} + +export default defaultResponder(postHandler); diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index 3ab69494a8..c07846423f 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -1,92 +1,10 @@ -import type { NextApiRequest, NextApiResponse } from "next"; +import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { SelectedCalendarResponse, SelectedCalendarsResponse } from "@lib/types"; -import { - schemaSelectedCalendarBodyParams, - schemaSelectedCalendarPublic, -} from "@lib/validations/selected-calendar"; -async function createOrlistAllSelectedCalendars( - { method, body, userId, prisma }: NextApiRequest, - res: NextApiResponse -) { - if (method === "GET") { - /** - * @swagger - * /selected-calendars: - * get: - * operationId: listSelectedCalendars - * summary: Find all selected calendars - * tags: - * - selected-calendars - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No selected calendars were found - */ - const data = await prisma.selectedCalendar.findMany({ where: { userId } }); - const selected_calendars = data.map((selected_calendar) => - schemaSelectedCalendarPublic.parse(selected_calendar) - ); - if (selected_calendars) res.status(200).json({ selected_calendars }); - else - (error: Error) => - res.status(404).json({ - message: "No SelectedCalendars were found", - error, - }); - } else if (method === "POST") { - /** - * @swagger - * /selected-calendars: - * get: - * operationId: addSelectedCalendars - * summary: Find all selected calendars - * tags: - * - selected-calendars - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No selected calendars were found - * post: - * summary: Creates a new selected calendar - * tags: - * - selected-calendars - * responses: - * 201: - * description: OK, selected calendar created - * 400: - * description: Bad request. SelectedCalendar body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - const safe = schemaSelectedCalendarBodyParams.safeParse(body); - if (!safe.success) { - res.status(400).json({ message: "Invalid request body" }); - return; - } - // Create new selectedCalendar connecting it to current userId - const data = await prisma.selectedCalendar.create({ - data: { ...safe.data, user: { connect: { id: userId } } }, - }); - const selected_calendar = schemaSelectedCalendarPublic.parse(data); - - if (selected_calendar) - res.status(201).json({ selected_calendar, message: "SelectedCalendar created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new selected calendar", - error, - }); - } else res.status(405).json({ message: `Method ${method} not allowed` }); -} - -export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllSelectedCalendars); +export default withMiddleware("HTTP_GET_OR_POST")( + defaultHandler({ + GET: import("./_get"), + POST: import("./_post"), + }) +); From debc8dbafb3d8dfc02b08fdbc9a6fabfb78be14b Mon Sep 17 00:00:00 2001 From: Leo Giovanetti Date: Thu, 20 Oct 2022 20:49:57 -0300 Subject: [PATCH 537/658] Using abstracted booking cancellation (#191) Implemented `DELETE /booking/:uid` as well as `DELETE /booking/:uid/cancel` based on abstracted cancellation logic from webapp. PR dependant on https://github.com/calcom/cal.com/pull/5105 Co-authored-by: Alex van Andel --- pages/api/bookings/[id]/_delete.ts | 53 +++++++++++++++++++++--------- pages/api/bookings/[id]/cancel.ts | 14 ++++++++ 2 files changed, 51 insertions(+), 16 deletions(-) create mode 100644 pages/api/bookings/[id]/cancel.ts diff --git a/pages/api/bookings/[id]/_delete.ts b/pages/api/bookings/[id]/_delete.ts index 46014f5785..d03f1c7abd 100644 --- a/pages/api/bookings/[id]/_delete.ts +++ b/pages/api/bookings/[id]/_delete.ts @@ -1,37 +1,58 @@ import type { NextApiRequest } from "next"; +import handleCancelBooking from "@calcom/features/bookings/lib/handleCancelBooking"; import { defaultResponder } from "@calcom/lib/server"; +import { schemaBookingCancelParams } from "@calcom/prisma/zod-utils"; import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; /** * @swagger - * /bookings/{id}: + * /bookings/{id}/cancel: * delete: - * summary: Remove an existing booking - * operationId: removeBookingById + * summary: Booking cancellation + * operationId: cancelBookingById + * requestBody: + * content: + * application/json: + * schema: + * type: object + * properties: + * allRemainingBookings: + * type: boolean + * reason: + * type: string * parameters: * - in: path * name: id * schema: * type: integer * required: true - * description: ID of the booking to delete + * description: ID of the booking to cancel * tags: - * - bookings + * - bookings * responses: - * 201: - * description: OK, booking removed successfuly + * 200: + * description: OK, booking cancelled successfuly * 400: - * description: Bad request. Booking id is invalid. - * 401: - * description: Authorization information is missing or invalid. + * description: | + * Message | Cause + * :--|:-- + * Booking not found| The provided id didn't correspond to any existing booking. + * Cannot cancel past events| The provided id matched an existing booking with a past startDate. + * User not found| The userId did not matched an existing user. + * 404: + * description: User not found */ -export async function deleteHandler(req: NextApiRequest) { - const { prisma, query } = req; - const { id } = schemaQueryIdParseInt.parse(query); - await prisma.booking.delete({ where: { id } }); - return { message: `Booking with id: ${id} deleted successfully` }; +async function handler(req: NextApiRequest) { + const { id } = schemaQueryIdParseInt.parse(req.query); + const { allRemainingBookings, cancellationReason } = schemaBookingCancelParams.parse({ + ...req.body, + cancellationReason: req.body.reason, + }); + // Normalizing for universal handler + req.body = { id, allRemainingBookings, cancellationReason }; + return await handleCancelBooking(req); } -export default defaultResponder(deleteHandler); +export default defaultResponder(handler); diff --git a/pages/api/bookings/[id]/cancel.ts b/pages/api/bookings/[id]/cancel.ts new file mode 100644 index 0000000000..d450678e85 --- /dev/null +++ b/pages/api/bookings/[id]/cancel.ts @@ -0,0 +1,14 @@ +import { NextApiRequest, NextApiResponse } from "next"; + +import { defaultHandler } from "@calcom/lib/server"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; + +import authMiddleware from "./_auth-middleware"; + +export default withMiddleware()(async (req: NextApiRequest, res: NextApiResponse) => { + await authMiddleware(req); + return defaultHandler({ + DELETE: import("./_delete"), + })(req, res); +}); From dee0f6a415fad44c52a9d9e9c043b66eff77c5de Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Fri, 21 Oct 2022 00:58:20 +0100 Subject: [PATCH 538/658] Remove GET /availabilities (#188) Follows-up on earlier discussions about the relationships of /availabilities and /schedules. `GET /schedules/:id` returns a schedule with associated availabilities in the `availabilities` property. It gives more context and less consumer work to perform GET actions using this endpoint. Other endpoints of this collection do make sense. Proposing also to rename the /availabilities collection to /availability; given after this it always involves one and only one /availability record in CRUD. --- pages/api/availabilities/_get.ts | 58 ------------------------------- pages/api/availabilities/index.ts | 3 +- pages/api/docs.ts | 5 ++- 3 files changed, 5 insertions(+), 61 deletions(-) delete mode 100644 pages/api/availabilities/_get.ts diff --git a/pages/api/availabilities/_get.ts b/pages/api/availabilities/_get.ts deleted file mode 100644 index b0649b5b16..0000000000 --- a/pages/api/availabilities/_get.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type { NextApiRequest } from "next"; - -import { HttpError } from "@calcom/lib/http-error"; -import { defaultResponder } from "@calcom/lib/server"; - -import { schemaAvailabilityReadBodyParams } from "@lib/validations/availability"; - -/** - * @swagger - * /availabilities: - * get: - * operationId: listAvailabilities - * summary: Find all availabilities - * tags: - * - availabilities - * externalDocs: - * url: https://docs.cal.com/availability - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No availabilities were found - */ -async function handler(req: NextApiRequest) { - const { userId, isAdmin, prisma } = req; - const body = schemaAvailabilityReadBodyParams.parse(req.body || {}); - - if (body.userId && !isAdmin) - throw new HttpError({ - statusCode: 401, - message: "Unauthorized: Only admins can request other users' availabilities", - }); - - const userIds = Array.isArray(body.userId) ? body.userId : [body.userId || userId]; - - let availabilities = await prisma.availability.findMany({ - where: { Schedule: { userId: { in: userIds } } }, - include: { Schedule: { select: { userId: true } } }, - ...(Array.isArray(body.userId) && { orderBy: { userId: "asc" } }), - }); - - /** - * IDK if this a special requirement but, since availabilities aren't directly related to a user. - * We manually override the `userId` field so the user doesn't need to query the scheduleId just - * to get the user that it belongs to... OR... we can just access `availability.Schedule.userId` instead - * but at this point I'm afraid to break something so we will have both for now... ¯\_(ツ)_/¯ - */ - availabilities = availabilities.map((a) => ({ ...a, userId: a.Schedule?.userId || null })); - - if (!availabilities.length) - throw new HttpError({ statusCode: 404, message: "No Availabilities were found" }); - - return { availabilities }; -} - -export default defaultResponder(handler); diff --git a/pages/api/availabilities/index.ts b/pages/api/availabilities/index.ts index c07846423f..3980d611ff 100644 --- a/pages/api/availabilities/index.ts +++ b/pages/api/availabilities/index.ts @@ -2,9 +2,8 @@ import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -export default withMiddleware("HTTP_GET_OR_POST")( +export default withMiddleware()( defaultHandler({ - GET: import("./_get"), POST: import("./_post"), }) ); diff --git a/pages/api/docs.ts b/pages/api/docs.ts index 37fdddc06a..230f4da80f 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -114,7 +114,10 @@ const swaggerHandler = withSwagger({ { name: "schedules" }, { name: "teams" }, { name: "memberships" }, - { name: "availabilities" }, + { + name: "availabilities", + description: "Allows modifying unique availabilities tied to a schedule.", + }, { name: "custom-inputs" }, { name: "event-references" }, { name: "booking-references" }, From adfada993e9787becc6340cf27b5d9c9d85fd56d Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Fri, 21 Oct 2022 13:19:31 +0100 Subject: [PATCH 539/658] Remove the Signup from /api and remove @calcom/ui dep (#201) Also adds missing dependencies --- auth/README.md | 15 ---- auth/signup.tsx | 182 ------------------------------------------------ next.config.js | 1 - package.json | 8 +++ 4 files changed, 8 insertions(+), 198 deletions(-) delete mode 100644 auth/README.md delete mode 100644 auth/signup.tsx diff --git a/auth/README.md b/auth/README.md deleted file mode 100644 index c4c0e5a19d..0000000000 --- a/auth/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# Signup for self-hosted EE - -In order to open the signup, please replace the contents of the file in - -`cal.com/apps/web/pages/auth/signup.tsx` - -with the contents of the new file provided here in the @calcom/api repo at the folder: -`/auth/signup.tsx` - -Once you do, if you run your cal.com self-hosted instance and go to: -`http://localhost:3000/auth/signup` - -You should see the signup page, and your users should be able to create new accounts. - -Please, keep in mind this will create git conflict resolutions if you try to git pull from main, where the signup.tsx file will still be different. We will find a better workaround for this soon in order to make it pain free. diff --git a/auth/signup.tsx b/auth/signup.tsx deleted file mode 100644 index 6a04c71ecc..0000000000 --- a/auth/signup.tsx +++ /dev/null @@ -1,182 +0,0 @@ -import { GetServerSidePropsContext } from "next"; -import { signIn } from "next-auth/react"; -import { useRouter } from "next/router"; -import { FormProvider, SubmitHandler, useForm } from "react-hook-form"; - -import { useLocale } from "@calcom/lib/hooks/useLocale"; -import { Alert } from "@calcom/ui/Alert"; -import Button from "@calcom/ui/Button"; -import { EmailField, PasswordField, TextField } from "@calcom/ui/form/fields"; -import { HeadSeo } from "@calcom/web/components/seo/head-seo"; -import { asStringOrNull } from "@calcom/web/lib/asStringOrNull"; -import { WEBAPP_URL } from "@calcom/web/lib/config/constants"; -import prisma from "@calcom/web/lib/prisma"; -import { isSAMLLoginEnabled } from "@calcom/web/lib/saml"; -import { IS_GOOGLE_LOGIN_ENABLED } from "@calcom/web/server/lib/constants"; -import { ssrInit } from "@calcom/web/server/lib/ssr"; - -type FormValues = { - username: string; - email: string; - password: string; - passwordcheck: string; - apiError: string; -}; - -export default function Signup() { - const { t } = useLocale(); - const router = useRouter(); - const methods = useForm(); - const { - register, - formState: { errors, isSubmitting }, - } = methods; - - const handleErrors = async (resp: Response) => { - if (!resp.ok) { - const err = await resp.json(); - throw new Error(err.message); - } - }; - - const signUp: SubmitHandler = async (data) => { - await fetch("/api/auth/signup", { - body: JSON.stringify({ - ...data, - }), - headers: { - "Content-Type": "application/json", - }, - method: "POST", - }) - .then(handleErrors) - .then( - async () => - await signIn("Cal.com", { - callbackUrl: (`${WEBAPP_URL}/${router.query.callbackUrl}` || "") as string, - }) - ) - .catch((err) => { - methods.setError("apiError", { message: err.message }); - }); - }; - - return ( -
- -
-

- {t("create_your_account")} -

-
-
-
- -
- {errors.apiError && } -
- - {process.env.NEXT_PUBLIC_WEBSITE_URL}/ - - } - labelProps={{ className: "block text-sm font-medium text-gray-700" }} - className="block w-full min-w-0 flex-grow rounded-none rounded-r-sm border-gray-300 lowercase focus:border-black focus:ring-black sm:text-sm" - {...register("username")} - required - /> - - - - value === methods.watch("password") || (t("error_password_mismatch") as string), - })} - className="mt-1 block w-full rounded-md border border-gray-300 px-3 py-2 shadow-sm focus:border-black focus:outline-none focus:ring-black sm:text-sm" - /> -
-
- - -
- -
-
-
-
- ); -} - -export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { - const ssr = await ssrInit(ctx); - const token = asStringOrNull(ctx.query.token); - if (token) { - const verificationToken = await prisma.verificationToken.findUnique({ - where: { - token, - }, - }); - if (verificationToken) { - const existingUser = await prisma.user.findFirst({ - where: { - AND: [ - { - email: verificationToken?.identifier, - }, - { - emailVerified: { - not: null, - }, - }, - ], - }, - }); - - if (existingUser) { - return { - redirect: { - permanent: false, - destination: "/auth/login?callbackUrl=" + `${WEBAPP_URL}/${ctx.query.callbackUrl}`, - }, - }; - } - } - } - - return { - props: { - isGoogleLoginEnabled: IS_GOOGLE_LOGIN_ENABLED, - isSAMLLoginEnabled, - trpcState: ssr.dehydrate(), - }, - }; -}; diff --git a/next.config.js b/next.config.js index 7cbb49652e..568fe06270 100644 --- a/next.config.js +++ b/next.config.js @@ -11,7 +11,6 @@ const withTM = require("next-transpile-modules")([ "@calcom/lib", "@calcom/prisma", "@calcom/trpc", - "@calcom/ui", ]); const { withAxiom } = require("next-axiom"); diff --git a/package.json b/package.json index 1484a4d8e8..b6fe3c392d 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,14 @@ "dependencies": { "@calcom/prisma": "*", "@calcom/trpc": "*", + "@calcom/embed-core": "*", + "@calcom/app-store": "*", + "@calcom/core": "*", + "@calcom/dayjs": "*", + "@calcom/emails": "*", + "@calcom/embed-snippet": "*", + "@calcom/features": "*", + "@calcom/lib": "*", "@sentry/nextjs": "^6.19.7", "bcryptjs": "^2.4.3", "memory-cache": "^0.2.0", From 9448e67ed0822999755aa57ca0b7f6e004bfbf90 Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Fri, 21 Oct 2022 14:04:20 +0100 Subject: [PATCH 540/658] Added status: true to booking model (#203) --- lib/validations/booking.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index 727ff0b1db..b6e3832140 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -59,4 +59,5 @@ export const schemaBookingReadPublic = Booking.extend({ attendees: true, user: true, metadata: true, + status: true, }); From b30995456c2333d74d073981e52bd7beeb281f33 Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Fri, 21 Oct 2022 14:13:19 +0100 Subject: [PATCH 541/658] Bring back @calcom/ui --- next.config.js | 1 + package.json | 1 + 2 files changed, 2 insertions(+) diff --git a/next.config.js b/next.config.js index 568fe06270..7cbb49652e 100644 --- a/next.config.js +++ b/next.config.js @@ -11,6 +11,7 @@ const withTM = require("next-transpile-modules")([ "@calcom/lib", "@calcom/prisma", "@calcom/trpc", + "@calcom/ui", ]); const { withAxiom } = require("next-axiom"); diff --git a/package.json b/package.json index b6fe3c392d..ebdb500e63 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "@calcom/embed-snippet": "*", "@calcom/features": "*", "@calcom/lib": "*", + "@calcom/ui": "*", "@sentry/nextjs": "^6.19.7", "bcryptjs": "^2.4.3", "memory-cache": "^0.2.0", From 7617cd43e1d0cb4b01f6be1dd29ba1c881a2d3a1 Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 21 Oct 2022 12:55:15 -0600 Subject: [PATCH 542/658] Patching bodyUserId requests --- pages/api/selected-calendars/[id]/_patch.ts | 4 ++-- pages/api/selected-calendars/_post.ts | 2 +- pages/api/webhooks/_post.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pages/api/selected-calendars/[id]/_patch.ts b/pages/api/selected-calendars/[id]/_patch.ts index 064bee1dbc..ae78b67fc6 100644 --- a/pages/api/selected-calendars/[id]/_patch.ts +++ b/pages/api/selected-calendars/[id]/_patch.ts @@ -54,9 +54,9 @@ export async function patchHandler(req: NextApiRequest) { if (!isAdmin && bodyUserId) throw new HttpError({ statusCode: 403, message: `ADMIN required for userId` }); if (isAdmin && bodyUserId) { - const where: Prisma.UserWhereInput = { id: userId }; + const where: Prisma.UserWhereInput = { id: bodyUserId }; await prisma.user.findFirstOrThrow({ where }); - args.data.userId = userId; + args.data.userId = bodyUserId; } const result = await prisma.selectedCalendar.update(args); diff --git a/pages/api/selected-calendars/_post.ts b/pages/api/selected-calendars/_post.ts index 2118c5348f..08ca7e4e41 100644 --- a/pages/api/selected-calendars/_post.ts +++ b/pages/api/selected-calendars/_post.ts @@ -46,7 +46,7 @@ async function postHandler(req: NextApiRequest) { if (isAdmin && bodyUserId) { const where: Prisma.UserWhereInput = { id: bodyUserId }; await prisma.user.findFirstOrThrow({ where }); - args.data.userId = userId; + args.data.userId = bodyUserId; } const data = await prisma.selectedCalendar.create(args); diff --git a/pages/api/webhooks/_post.ts b/pages/api/webhooks/_post.ts index dd7f97dd87..f87b8ffe57 100644 --- a/pages/api/webhooks/_post.ts +++ b/pages/api/webhooks/_post.ts @@ -43,9 +43,9 @@ async function postHandler(req: NextApiRequest) { if (!isAdmin && bodyUserId) throw new HttpError({ statusCode: 403, message: `ADMIN required for userId` }); if (isAdmin && bodyUserId) { - const where: Prisma.UserWhereInput = { id: userId }; + const where: Prisma.UserWhereInput = { id: bodyUserId }; await prisma.user.findFirstOrThrow({ where }); - args.data.userId = userId; + args.data.userId = bodyUserId; } const data = await prisma.webhook.create(args); From 6522600c426b3d69880e1fdfb99912bd84eefbf3 Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 21 Oct 2022 12:55:35 -0600 Subject: [PATCH 543/658] Add missing bodyUserId --- pages/api/webhooks/[id]/_patch.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/api/webhooks/[id]/_patch.ts b/pages/api/webhooks/[id]/_patch.ts index dbcc8c8306..cb645e4363 100644 --- a/pages/api/webhooks/[id]/_patch.ts +++ b/pages/api/webhooks/[id]/_patch.ts @@ -50,9 +50,9 @@ export async function patchHandler(req: NextApiRequest) { if (!isAdmin && bodyUserId) throw new HttpError({ statusCode: 403, message: `ADMIN required for userId` }); if (isAdmin && bodyUserId) { - const where: Prisma.UserWhereInput = { id: userId }; + const where: Prisma.UserWhereInput = { id: bodyUserId }; await prisma.user.findFirstOrThrow({ where }); - args.data.userId = userId; + args.data.userId = bodyUserId; } const result = await prisma.webhook.update(args); From d93fd26a1e2777fac5809e0ad78b9cf62b5da769 Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 21 Oct 2022 13:30:09 -0600 Subject: [PATCH 544/658] Removed unused methods middleware --- pages/api/attendees/[id]/index.ts | 2 +- pages/api/attendees/index.ts | 2 +- pages/api/availabilities/[id]/index.ts | 2 +- pages/api/availability/index.ts | 2 +- pages/api/booking-references/[id]/index.ts | 2 +- pages/api/booking-references/index.ts | 2 +- pages/api/bookings/[id]/index.ts | 2 +- pages/api/bookings/index.ts | 2 +- pages/api/custom-inputs/[id]/index.ts | 2 +- pages/api/custom-inputs/index.ts | 2 +- pages/api/event-types/[id]/index.ts | 2 +- pages/api/event-types/index.ts | 2 +- pages/api/me/index.ts | 2 +- pages/api/schedules/[id]/index.ts | 2 +- pages/api/schedules/index.ts | 2 +- pages/api/selected-calendars/[id]/index.ts | 2 +- pages/api/selected-calendars/index.ts | 2 +- pages/api/teams/[teamId]/availability/index.ts | 2 +- pages/api/teams/[teamId]/index.ts | 2 +- pages/api/teams/index.ts | 2 +- pages/api/users/[userId]/availability/index.ts | 2 +- pages/api/users/[userId]/index.ts | 2 +- pages/api/users/index.ts | 2 +- pages/api/webhooks/[id]/index.ts | 2 +- pages/api/webhooks/index.ts | 2 +- 25 files changed, 25 insertions(+), 25 deletions(-) diff --git a/pages/api/attendees/[id]/index.ts b/pages/api/attendees/[id]/index.ts index 7d92ee2906..8c4a8b8cb4 100644 --- a/pages/api/attendees/[id]/index.ts +++ b/pages/api/attendees/[id]/index.ts @@ -6,7 +6,7 @@ import { withMiddleware } from "@lib/helpers/withMiddleware"; import authMiddleware from "./_auth-middleware"; -export default withMiddleware("HTTP_GET_DELETE_PATCH")( +export default withMiddleware()( defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { await authMiddleware(req); return defaultHandler({ diff --git a/pages/api/attendees/index.ts b/pages/api/attendees/index.ts index c07846423f..4c33cbe75d 100644 --- a/pages/api/attendees/index.ts +++ b/pages/api/attendees/index.ts @@ -2,7 +2,7 @@ import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -export default withMiddleware("HTTP_GET_OR_POST")( +export default withMiddleware()( defaultHandler({ GET: import("./_get"), POST: import("./_post"), diff --git a/pages/api/availabilities/[id]/index.ts b/pages/api/availabilities/[id]/index.ts index 7d92ee2906..8c4a8b8cb4 100644 --- a/pages/api/availabilities/[id]/index.ts +++ b/pages/api/availabilities/[id]/index.ts @@ -6,7 +6,7 @@ import { withMiddleware } from "@lib/helpers/withMiddleware"; import authMiddleware from "./_auth-middleware"; -export default withMiddleware("HTTP_GET_DELETE_PATCH")( +export default withMiddleware()( defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { await authMiddleware(req); return defaultHandler({ diff --git a/pages/api/availability/index.ts b/pages/api/availability/index.ts index fe6357f6bc..c5c5f832e5 100644 --- a/pages/api/availability/index.ts +++ b/pages/api/availability/index.ts @@ -2,7 +2,7 @@ import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -export default withMiddleware("HTTP_GET")( +export default withMiddleware()( defaultHandler({ GET: import("./_get"), }) diff --git a/pages/api/booking-references/[id]/index.ts b/pages/api/booking-references/[id]/index.ts index 7d92ee2906..8c4a8b8cb4 100644 --- a/pages/api/booking-references/[id]/index.ts +++ b/pages/api/booking-references/[id]/index.ts @@ -6,7 +6,7 @@ import { withMiddleware } from "@lib/helpers/withMiddleware"; import authMiddleware from "./_auth-middleware"; -export default withMiddleware("HTTP_GET_DELETE_PATCH")( +export default withMiddleware()( defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { await authMiddleware(req); return defaultHandler({ diff --git a/pages/api/booking-references/index.ts b/pages/api/booking-references/index.ts index c07846423f..4c33cbe75d 100644 --- a/pages/api/booking-references/index.ts +++ b/pages/api/booking-references/index.ts @@ -2,7 +2,7 @@ import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -export default withMiddleware("HTTP_GET_OR_POST")( +export default withMiddleware()( defaultHandler({ GET: import("./_get"), POST: import("./_post"), diff --git a/pages/api/bookings/[id]/index.ts b/pages/api/bookings/[id]/index.ts index 7d92ee2906..8c4a8b8cb4 100644 --- a/pages/api/bookings/[id]/index.ts +++ b/pages/api/bookings/[id]/index.ts @@ -6,7 +6,7 @@ import { withMiddleware } from "@lib/helpers/withMiddleware"; import authMiddleware from "./_auth-middleware"; -export default withMiddleware("HTTP_GET_DELETE_PATCH")( +export default withMiddleware()( defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { await authMiddleware(req); return defaultHandler({ diff --git a/pages/api/bookings/index.ts b/pages/api/bookings/index.ts index c07846423f..4c33cbe75d 100644 --- a/pages/api/bookings/index.ts +++ b/pages/api/bookings/index.ts @@ -2,7 +2,7 @@ import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -export default withMiddleware("HTTP_GET_OR_POST")( +export default withMiddleware()( defaultHandler({ GET: import("./_get"), POST: import("./_post"), diff --git a/pages/api/custom-inputs/[id]/index.ts b/pages/api/custom-inputs/[id]/index.ts index 7d92ee2906..8c4a8b8cb4 100644 --- a/pages/api/custom-inputs/[id]/index.ts +++ b/pages/api/custom-inputs/[id]/index.ts @@ -6,7 +6,7 @@ import { withMiddleware } from "@lib/helpers/withMiddleware"; import authMiddleware from "./_auth-middleware"; -export default withMiddleware("HTTP_GET_DELETE_PATCH")( +export default withMiddleware()( defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { await authMiddleware(req); return defaultHandler({ diff --git a/pages/api/custom-inputs/index.ts b/pages/api/custom-inputs/index.ts index c07846423f..4c33cbe75d 100644 --- a/pages/api/custom-inputs/index.ts +++ b/pages/api/custom-inputs/index.ts @@ -2,7 +2,7 @@ import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -export default withMiddleware("HTTP_GET_OR_POST")( +export default withMiddleware()( defaultHandler({ GET: import("./_get"), POST: import("./_post"), diff --git a/pages/api/event-types/[id]/index.ts b/pages/api/event-types/[id]/index.ts index 7d92ee2906..8c4a8b8cb4 100644 --- a/pages/api/event-types/[id]/index.ts +++ b/pages/api/event-types/[id]/index.ts @@ -6,7 +6,7 @@ import { withMiddleware } from "@lib/helpers/withMiddleware"; import authMiddleware from "./_auth-middleware"; -export default withMiddleware("HTTP_GET_DELETE_PATCH")( +export default withMiddleware()( defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { await authMiddleware(req); return defaultHandler({ diff --git a/pages/api/event-types/index.ts b/pages/api/event-types/index.ts index c07846423f..4c33cbe75d 100644 --- a/pages/api/event-types/index.ts +++ b/pages/api/event-types/index.ts @@ -2,7 +2,7 @@ import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -export default withMiddleware("HTTP_GET_OR_POST")( +export default withMiddleware()( defaultHandler({ GET: import("./_get"), POST: import("./_post"), diff --git a/pages/api/me/index.ts b/pages/api/me/index.ts index fe6357f6bc..c5c5f832e5 100644 --- a/pages/api/me/index.ts +++ b/pages/api/me/index.ts @@ -2,7 +2,7 @@ import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -export default withMiddleware("HTTP_GET")( +export default withMiddleware()( defaultHandler({ GET: import("./_get"), }) diff --git a/pages/api/schedules/[id]/index.ts b/pages/api/schedules/[id]/index.ts index cbff13f006..e0839f1eff 100644 --- a/pages/api/schedules/[id]/index.ts +++ b/pages/api/schedules/[id]/index.ts @@ -6,7 +6,7 @@ import { withMiddleware } from "@lib/helpers/withMiddleware"; import authMiddleware from "./_auth-middleware"; -export default withMiddleware("HTTP_GET_DELETE_PATCH")( +export default withMiddleware()( defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { await authMiddleware(req); return defaultHandler({ diff --git a/pages/api/schedules/index.ts b/pages/api/schedules/index.ts index c07846423f..4c33cbe75d 100644 --- a/pages/api/schedules/index.ts +++ b/pages/api/schedules/index.ts @@ -2,7 +2,7 @@ import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -export default withMiddleware("HTTP_GET_OR_POST")( +export default withMiddleware()( defaultHandler({ GET: import("./_get"), POST: import("./_post"), diff --git a/pages/api/selected-calendars/[id]/index.ts b/pages/api/selected-calendars/[id]/index.ts index cbff13f006..e0839f1eff 100644 --- a/pages/api/selected-calendars/[id]/index.ts +++ b/pages/api/selected-calendars/[id]/index.ts @@ -6,7 +6,7 @@ import { withMiddleware } from "@lib/helpers/withMiddleware"; import authMiddleware from "./_auth-middleware"; -export default withMiddleware("HTTP_GET_DELETE_PATCH")( +export default withMiddleware()( defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { await authMiddleware(req); return defaultHandler({ diff --git a/pages/api/selected-calendars/index.ts b/pages/api/selected-calendars/index.ts index c07846423f..4c33cbe75d 100644 --- a/pages/api/selected-calendars/index.ts +++ b/pages/api/selected-calendars/index.ts @@ -2,7 +2,7 @@ import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -export default withMiddleware("HTTP_GET_OR_POST")( +export default withMiddleware()( defaultHandler({ GET: import("./_get"), POST: import("./_post"), diff --git a/pages/api/teams/[teamId]/availability/index.ts b/pages/api/teams/[teamId]/availability/index.ts index 1a27360f81..94bb68733e 100644 --- a/pages/api/teams/[teamId]/availability/index.ts +++ b/pages/api/teams/[teamId]/availability/index.ts @@ -2,7 +2,7 @@ import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -export default withMiddleware("HTTP_GET")( +export default withMiddleware()( defaultHandler({ GET: import("@api/availability/_get"), }) diff --git a/pages/api/teams/[teamId]/index.ts b/pages/api/teams/[teamId]/index.ts index 7d92ee2906..8c4a8b8cb4 100644 --- a/pages/api/teams/[teamId]/index.ts +++ b/pages/api/teams/[teamId]/index.ts @@ -6,7 +6,7 @@ import { withMiddleware } from "@lib/helpers/withMiddleware"; import authMiddleware from "./_auth-middleware"; -export default withMiddleware("HTTP_GET_DELETE_PATCH")( +export default withMiddleware()( defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { await authMiddleware(req); return defaultHandler({ diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index c07846423f..4c33cbe75d 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -2,7 +2,7 @@ import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -export default withMiddleware("HTTP_GET_OR_POST")( +export default withMiddleware()( defaultHandler({ GET: import("./_get"), POST: import("./_post"), diff --git a/pages/api/users/[userId]/availability/index.ts b/pages/api/users/[userId]/availability/index.ts index 1a27360f81..94bb68733e 100644 --- a/pages/api/users/[userId]/availability/index.ts +++ b/pages/api/users/[userId]/availability/index.ts @@ -2,7 +2,7 @@ import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -export default withMiddleware("HTTP_GET")( +export default withMiddleware()( defaultHandler({ GET: import("@api/availability/_get"), }) diff --git a/pages/api/users/[userId]/index.ts b/pages/api/users/[userId]/index.ts index 66c0e9b25c..2b0beaf345 100644 --- a/pages/api/users/[userId]/index.ts +++ b/pages/api/users/[userId]/index.ts @@ -3,7 +3,7 @@ import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; import { withValidQueryUserId } from "@lib/validations/shared/queryUserId"; -export default withMiddleware("HTTP_GET_DELETE_PATCH")( +export default withMiddleware()( withValidQueryUserId( defaultHandler({ GET: import("./_get"), diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index c07846423f..4c33cbe75d 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -2,7 +2,7 @@ import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -export default withMiddleware("HTTP_GET_OR_POST")( +export default withMiddleware()( defaultHandler({ GET: import("./_get"), POST: import("./_post"), diff --git a/pages/api/webhooks/[id]/index.ts b/pages/api/webhooks/[id]/index.ts index cbff13f006..e0839f1eff 100644 --- a/pages/api/webhooks/[id]/index.ts +++ b/pages/api/webhooks/[id]/index.ts @@ -6,7 +6,7 @@ import { withMiddleware } from "@lib/helpers/withMiddleware"; import authMiddleware from "./_auth-middleware"; -export default withMiddleware("HTTP_GET_DELETE_PATCH")( +export default withMiddleware()( defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { await authMiddleware(req); return defaultHandler({ diff --git a/pages/api/webhooks/index.ts b/pages/api/webhooks/index.ts index c07846423f..4c33cbe75d 100644 --- a/pages/api/webhooks/index.ts +++ b/pages/api/webhooks/index.ts @@ -2,7 +2,7 @@ import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -export default withMiddleware("HTTP_GET_OR_POST")( +export default withMiddleware()( defaultHandler({ GET: import("./_get"), POST: import("./_post"), From d1bbaef5c6fc51c8c7bcb8655ca2818241948e02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Fri, 21 Oct 2022 13:54:28 -0600 Subject: [PATCH 545/658] Refactor membership endpoints (#204) refs #175 Co-authored-by: Alex van Andel --- lib/validations/membership.ts | 55 +++++- lib/validations/shared/queryUserId.ts | 4 + pages/api/memberships/[id].ts | 184 ------------------ .../api/memberships/[id]/_auth-middleware.ts | 17 ++ pages/api/memberships/[id]/_delete.ts | 43 ++++ pages/api/memberships/[id]/_get.ts | 46 +++++ pages/api/memberships/[id]/_patch.ts | 71 +++++++ pages/api/memberships/[id]/index.ts | 18 ++ pages/api/memberships/_get.ts | 76 ++++++++ pages/api/memberships/_post.ts | 53 +++++ pages/api/memberships/index.ts | 75 +------ 11 files changed, 388 insertions(+), 254 deletions(-) delete mode 100644 pages/api/memberships/[id].ts create mode 100644 pages/api/memberships/[id]/_auth-middleware.ts create mode 100644 pages/api/memberships/[id]/_delete.ts create mode 100644 pages/api/memberships/[id]/_get.ts create mode 100644 pages/api/memberships/[id]/_patch.ts create mode 100644 pages/api/memberships/[id]/index.ts create mode 100644 pages/api/memberships/_get.ts create mode 100644 pages/api/memberships/_post.ts diff --git a/lib/validations/membership.ts b/lib/validations/membership.ts index d58eea2c33..27206d43b9 100644 --- a/lib/validations/membership.ts +++ b/lib/validations/membership.ts @@ -1,14 +1,65 @@ +import { stringOrNumber } from "@calcom/prisma/zod-utils"; +import { MembershipRole } from "@prisma/client"; import { z } from "zod"; -import { _MembershipModel as Membership } from "@calcom/prisma/zod"; +import { _MembershipModel as Membership, _TeamModel } from "@calcom/prisma/zod"; + +import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; +import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; export const schemaMembershipBaseBodyParams = Membership.omit({}); + const schemaMembershipRequiredParams = z.object({ teamId: z.number(), }); +export const membershipCreateBodySchema = Membership.partial({ + accepted: true, + role: true, + disableImpersonation: true, +}).transform((v) => ({ + accepted: false, + role: MembershipRole.MEMBER, + disableImpersonation: false, + ...v, +})); + +export const membershipEditBodySchema = Membership.omit({ + /** To avoid complication, let's avoid updating these, instead you can delete and create a new invite */ + teamId: true, + userId: true, +}) + .partial({ + accepted: true, + role: true, + disableImpersonation: true, + }) + .strict(); + export const schemaMembershipBodyParams = schemaMembershipBaseBodyParams.merge( schemaMembershipRequiredParams ); -export const schemaMembershipPublic = Membership.omit({}); +export const schemaMembershipPublic = Membership.merge(z.object({ team: _TeamModel }).partial()); + +/** We extract userId and teamId from compound ID string */ +export const membershipIdSchema = schemaQueryIdAsString + // So we can query additional team data in memberships + .merge(z.object({ teamId: z.union([stringOrNumber, z.array(stringOrNumber)]) }).partial()) + .transform((v, ctx) => { + const [userIdStr, teamIdStr] = v.id.split("_"); + const userIdInt = schemaQueryIdParseInt.safeParse({ id: userIdStr }); + const teamIdInt = schemaQueryIdParseInt.safeParse({ id: teamIdStr }); + if (!userIdInt.success) { + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "userId is not a number" }); + return z.NEVER; + } + if (!teamIdInt.success) { + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "teamId is not a number " }); + return z.NEVER; + } + return { + userId: userIdInt.data.id, + teamId: teamIdInt.data.id, + }; + }); diff --git a/lib/validations/shared/queryUserId.ts b/lib/validations/shared/queryUserId.ts index 94de53a214..88e2c7e8de 100644 --- a/lib/validations/shared/queryUserId.ts +++ b/lib/validations/shared/queryUserId.ts @@ -17,6 +17,10 @@ export const schemaQuerySingleOrMultipleUserIds = z.object({ userId: z.union([stringOrNumber, z.array(stringOrNumber)]), }); +export const schemaQuerySingleOrMultipleTeamIds = z.object({ + teamId: z.union([stringOrNumber, z.array(stringOrNumber)]), +}); + export const withValidQueryUserId = withValidation({ schema: schemaQueryUserId, type: "Zod", diff --git a/pages/api/memberships/[id].ts b/pages/api/memberships/[id].ts deleted file mode 100644 index b6050ebbe9..0000000000 --- a/pages/api/memberships/[id].ts +++ /dev/null @@ -1,184 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; - -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import type { MembershipResponse } from "@lib/types"; -import { schemaMembershipBodyParams, schemaMembershipPublic } from "@lib/validations/membership"; -import { schemaQueryIdAsString, withValidQueryIdString } from "@lib/validations/shared/queryIdString"; - -export async function membershipById( - { method, query, body, userId, prisma }: NextApiRequest, - res: NextApiResponse -) { - const safeQuery = schemaQueryIdAsString.safeParse(query); - if (!safeQuery.success) { - res.status(400).json({ message: "Your query was invalid" }); - return; - } - // This is how we set the userId and teamId in the query for managing compoundId. - const [paramUserId, teamId] = safeQuery.data.id.split("_"); - if (parseInt(paramUserId) !== userId) res.status(401).json({ message: "Unauthorized" }); - else { - switch (method) { - /** - * @swagger - * /memberships/{userId}_{teamId}: - * get: - * summary: Find a membership by userID and teamID - * parameters: - * - in: path - * name: userId - * schema: - * type: integer - * required: true - * description: Numeric userId of the membership to get - * - in: path - * name: teamId - * schema: - * type: integer - * required: true - * description: Numeric teamId of the membership to get - * tags: - * - memberships - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: Membership was not found - */ - case "GET": - await prisma.membership - .findUnique({ - where: { - userId_teamId: { - userId: userId, - teamId: parseInt(teamId), - }, - }, - }) - .then((data) => schemaMembershipPublic.parse(data)) - .then((membership) => res.status(200).json({ membership })) - .catch((error: Error) => - res.status(404).json({ - message: `Membership with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - - /** - * @swagger - * /memberships/{userId}_{teamId}: - * patch: - * summary: Edit an existing membership - * parameters: - * - in: path - * name: userId - * schema: - * type: integer - * required: true - * description: Numeric userId of the membership to get - * - in: path - * name: teamId - * schema: - * type: integer - * required: true - * description: Numeric teamId of the membership to get - * tags: - * - memberships - * responses: - * 201: - * description: OK, membership edited successfuly - * 400: - * description: Bad request. Membership body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - case "PATCH": - const safeBody = schemaMembershipBodyParams.safeParse(body); - if (!safeBody.success) { - { - res.status(400).json({ message: "Invalid request body" }); - return; - } - } - await prisma.membership - .update({ - where: { - userId_teamId: { - userId: userId, - teamId: parseInt(teamId), - }, - }, - data: safeBody.data, - }) - .then((data) => schemaMembershipPublic.parse(data)) - .then((membership) => res.status(200).json({ membership })) - .catch((error: Error) => - res.status(404).json({ - message: `Membership with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - - /** - * @swagger - * /memberships/{userId}_{teamId}: - * delete: - * summary: Remove an existing membership - * parameters: - * - in: path - * name: userId - * schema: - * type: integer - * required: true - * description: Numeric userId of the membership to get - * - in: path - * name: teamId - * schema: - * type: integer - * required: true - * description: Numeric teamId of the membership to get - * tags: - * - memberships - * responses: - * 201: - * description: OK, membership removed successfuly - * 400: - * description: Bad request. Membership id is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - case "DELETE": - await prisma.membership - .delete({ - where: { - userId_teamId: { - userId: userId, - teamId: parseInt(teamId), - }, - }, - }) - .then(() => - res.status(200).json({ - message: `Membership with id: ${safeQuery.data.id} deleted successfully`, - }) - ) - .catch((error: Error) => - res.status(404).json({ - message: `Membership with id: ${safeQuery.data.id} not found`, - error, - }) - ); - break; - - default: - res.status(405).json({ message: "Method not allowed" }); - break; - } - } -} - -export default withMiddleware("HTTP_GET_DELETE_PATCH")(withValidQueryIdString(membershipById)); diff --git a/pages/api/memberships/[id]/_auth-middleware.ts b/pages/api/memberships/[id]/_auth-middleware.ts new file mode 100644 index 0000000000..5da3083b4e --- /dev/null +++ b/pages/api/memberships/[id]/_auth-middleware.ts @@ -0,0 +1,17 @@ +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; + +import { membershipIdSchema } from "@lib/validations/membership"; + +async function authMiddleware(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const { teamId } = membershipIdSchema.parse(req.query); + // Admins can just skip this check + if (isAdmin) return; + // Only team members can modify a membership + const membership = await prisma.membership.findFirst({ where: { userId, teamId } }); + if (!membership) throw new HttpError({ statusCode: 403, message: "Forbidden" }); +} + +export default authMiddleware; diff --git a/pages/api/memberships/[id]/_delete.ts b/pages/api/memberships/[id]/_delete.ts new file mode 100644 index 0000000000..a21faea80f --- /dev/null +++ b/pages/api/memberships/[id]/_delete.ts @@ -0,0 +1,43 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { membershipIdSchema } from "@lib/validations/membership"; +import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; + +/** + * @swagger + * /memberships/{userId}_{teamId}: + * delete: + * summary: Remove an existing membership + * parameters: + * - in: path + * name: userId + * schema: + * type: integer + * required: true + * description: Numeric userId of the membership to get + * - in: path + * name: teamId + * schema: + * type: integer + * required: true + * description: Numeric teamId of the membership to get + * tags: + * - memberships + * responses: + * 201: + * description: OK, membership removed successfuly + * 400: + * description: Bad request. Membership id is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function deleteHandler(req: NextApiRequest) { + const { prisma, query } = req; + const userId_teamId = membershipIdSchema.parse(query); + await prisma.membership.delete({ where: { userId_teamId } }); + return { message: `Membership with id: ${query.id} deleted successfully` }; +} + +export default defaultResponder(deleteHandler); diff --git a/pages/api/memberships/[id]/_get.ts b/pages/api/memberships/[id]/_get.ts new file mode 100644 index 0000000000..626395c878 --- /dev/null +++ b/pages/api/memberships/[id]/_get.ts @@ -0,0 +1,46 @@ +import { Prisma } from "@prisma/client"; +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { membershipIdSchema, schemaMembershipPublic } from "@lib/validations/membership"; + +/** + * @swagger + * /memberships/{userId}_{teamId}: + * get: + * summary: Find a membership by userID and teamID + * parameters: + * - in: path + * name: userId + * schema: + * type: integer + * required: true + * description: Numeric userId of the membership to get + * - in: path + * name: teamId + * schema: + * type: integer + * required: true + * description: Numeric teamId of the membership to get + * tags: + * - memberships + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: Membership was not found + */ +export async function getHandler(req: NextApiRequest) { + const { prisma, query } = req; + const userId_teamId = membershipIdSchema.parse(query); + const args: Prisma.MembershipFindUniqueOrThrowArgs = { where: { userId_teamId } }; + // Just in case the user want to get more info about the team itself + if (req.query.include === "team") args.include = { team: true }; + const data = await prisma.membership.findUniqueOrThrow(args); + return { membership: schemaMembershipPublic.parse(data) }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/memberships/[id]/_patch.ts b/pages/api/memberships/[id]/_patch.ts new file mode 100644 index 0000000000..a458e1782a --- /dev/null +++ b/pages/api/memberships/[id]/_patch.ts @@ -0,0 +1,71 @@ +import type { Prisma } from "@prisma/client"; +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { + membershipEditBodySchema, + membershipIdSchema, + schemaMembershipPublic, +} from "@lib/validations/membership"; + +/** + * @swagger + * /memberships/{userId}_{teamId}: + * patch: + * summary: Edit an existing membership + * parameters: + * - in: path + * name: userId + * schema: + * type: integer + * required: true + * description: Numeric userId of the membership to get + * - in: path + * name: teamId + * schema: + * type: integer + * required: true + * description: Numeric teamId of the membership to get + * tags: + * - memberships + * responses: + * 201: + * description: OK, membership edited successfully + * 400: + * description: Bad request. Membership body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +export async function patchHandler(req: NextApiRequest) { + const { prisma, query } = req; + const userId_teamId = membershipIdSchema.parse(query); + const data = membershipEditBodySchema.parse(req.body); + const args: Prisma.MembershipUpdateArgs = { where: { userId_teamId }, data }; + + await checkPermissions(req); + + const result = await prisma.membership.update(args); + return { membership: schemaMembershipPublic.parse(result) }; +} + +async function checkPermissions(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const { userId: queryUserId, teamId } = membershipIdSchema.parse(req.query); + const data = membershipEditBodySchema.parse(req.body); + // Admins can just skip this check + if (isAdmin) return; + // Only the invited user can accept the invite + if ("accepted" in data && queryUserId !== userId) + throw new HttpError({ statusCode: 403, message: "Only the invited user can accept the invite" }); + // Only team OWNERS and ADMINS can modify `role` + if ("role" in data) { + const membership = await prisma.membership.findFirst({ + where: { userId, teamId, role: { in: ["ADMIN", "OWNER"] } }, + }); + if (!membership) throw new HttpError({ statusCode: 403, message: "Forbidden" }); + } +} + +export default defaultResponder(patchHandler); diff --git a/pages/api/memberships/[id]/index.ts b/pages/api/memberships/[id]/index.ts new file mode 100644 index 0000000000..e0839f1eff --- /dev/null +++ b/pages/api/memberships/[id]/index.ts @@ -0,0 +1,18 @@ +import type { NextApiRequest, NextApiResponse } from "next"; + +import { defaultHandler, defaultResponder } from "@calcom/lib/server"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; + +import authMiddleware from "./_auth-middleware"; + +export default withMiddleware()( + defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { + await authMiddleware(req); + return defaultHandler({ + GET: import("./_get"), + PATCH: import("./_patch"), + DELETE: import("./_delete"), + })(req, res); + }) +); diff --git a/pages/api/memberships/_get.ts b/pages/api/memberships/_get.ts new file mode 100644 index 0000000000..52c29f50e8 --- /dev/null +++ b/pages/api/memberships/_get.ts @@ -0,0 +1,76 @@ +import { Prisma } from "@prisma/client"; +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaMembershipPublic } from "@lib/validations/membership"; +import { + schemaQuerySingleOrMultipleTeamIds, + schemaQuerySingleOrMultipleUserIds, +} from "@lib/validations/shared/queryUserId"; + +/** + * @swagger + * /memberships: + * get: + * summary: Find all memberships + * tags: + * - memberships + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No memberships were found + */ +async function getHandler(req: NextApiRequest) { + const { prisma } = req; + const args: Prisma.MembershipFindManyArgs = { + where: { + /** Admins can query multiple users */ + userId: { in: getUserIds(req) }, + /** Admins can query multiple teams as well */ + teamId: { in: getTeamIds(req) }, + }, + }; + // Just in case the user want to get more info about the team itself + if (req.query.include === "team") args.include = { team: true }; + + const data = await prisma.membership.findMany(args); + return { memberships: data.map((v) => schemaMembershipPublic.parse(v)) }; +} + +/** + * Returns requested users IDs only if admin, otherwise return only current user ID + */ +function getUserIds(req: NextApiRequest) { + const { userId, isAdmin } = req; + /** Only admins can query other users */ + if (!isAdmin && req.query.userId) throw new HttpError({ statusCode: 403, message: "ADMIN required" }); + if (isAdmin && req.query.userId) { + const query = schemaQuerySingleOrMultipleUserIds.parse(req.query); + const userIds = Array.isArray(query.userId) ? query.userId : [query.userId || userId]; + return userIds; + } + // Return all memberships for ADMIN, limit to current user to non-admins + return isAdmin ? undefined : [userId]; +} + +/** + * Returns requested teams IDs only if admin + */ +function getTeamIds(req: NextApiRequest) { + const { isAdmin } = req; + /** Only admins can query other teams */ + if (!isAdmin && req.query.teamId) throw new HttpError({ statusCode: 403, message: "ADMIN required" }); + if (isAdmin && req.query.teamId) { + const query = schemaQuerySingleOrMultipleTeamIds.parse(req.query); + const teamIds = Array.isArray(query.teamId) ? query.teamId : [query.teamId]; + return teamIds; + } + return undefined; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/memberships/_post.ts b/pages/api/memberships/_post.ts new file mode 100644 index 0000000000..d76e4abf83 --- /dev/null +++ b/pages/api/memberships/_post.ts @@ -0,0 +1,53 @@ +import type { Prisma } from "@prisma/client"; +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { membershipCreateBodySchema, schemaMembershipPublic } from "@lib/validations/membership"; + +/** + * @swagger + * /memberships: + * post: + * summary: Creates a new membership + * tags: + * - memberships + * responses: + * 201: + * description: OK, membership created + * 400: + * description: Bad request. Membership body is invalid. + * 401: + * description: Authorization information is missing or invalid. + */ +async function postHandler(req: NextApiRequest) { + const { prisma } = req; + const data = membershipCreateBodySchema.parse(req.body); + const args: Prisma.MembershipCreateArgs = { data }; + + await checkPermissions(req); + + const result = await prisma.membership.create(args); + + return { + membership: schemaMembershipPublic.parse(result), + message: "Membership created successfully", + }; +} + +async function checkPermissions(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + if (isAdmin) return; + const body = membershipCreateBodySchema.parse(req.body); + // To prevent auto-accepted invites, limit it to ADMIN users + if (!isAdmin && "accepted" in body) + throw new HttpError({ statusCode: 403, message: "ADMIN needed for `accepted`" }); + // Only team OWNERS and ADMINS can add other members + const membership = await prisma.membership.findFirst({ + where: { userId, teamId: body.teamId, role: { in: ["ADMIN", "OWNER"] } }, + }); + if (!membership) throw new HttpError({ statusCode: 403, message: "You can't add members to this team" }); +} + +export default defaultResponder(postHandler); diff --git a/pages/api/memberships/index.ts b/pages/api/memberships/index.ts index 5aaa36f6db..4c33cbe75d 100644 --- a/pages/api/memberships/index.ts +++ b/pages/api/memberships/index.ts @@ -1,71 +1,10 @@ -import type { NextApiRequest, NextApiResponse } from "next"; +import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { MembershipResponse, MembershipsResponse } from "@lib/types"; -import { schemaMembershipBodyParams, schemaMembershipPublic } from "@lib/validations/membership"; -async function createOrlistAllMemberships( - { method, body, userId, prisma }: NextApiRequest, - res: NextApiResponse -) { - if (method === "GET") { - /** - * @swagger - * /memberships: - * get: - * summary: Find all memberships - * tags: - * - memberships - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No memberships were found - */ - const data = await prisma.membership.findMany({ where: { userId } }); - const memberships = data.map((membership) => schemaMembershipPublic.parse(membership)); - if (memberships) res.status(200).json({ memberships }); - else - (error: Error) => - res.status(404).json({ - message: "No Memberships were found", - error, - }); - } else if (method === "POST") { - /** - * @swagger - * /memberships: - * post: - * summary: Creates a new membership - * tags: - * - memberships - * responses: - * 201: - * description: OK, membership created - * 400: - * description: Bad request. Membership body is invalid. - * 401: - * description: Authorization information is missing or invalid. - */ - const safe = schemaMembershipBodyParams.safeParse(body); - if (!safe.success) { - res.status(400).json({ message: "Invalid request body" }); - return; - } - - const data = await prisma.membership.create({ data: { ...safe.data, userId } }); - const membership = schemaMembershipPublic.parse(data); - - if (membership) res.status(201).json({ membership, message: "Membership created successfully" }); - else - (error: Error) => - res.status(400).json({ - message: "Could not create new membership", - error, - }); - } else res.status(405).json({ message: `Method ${method} not allowed` }); -} - -export default withMiddleware("HTTP_GET_OR_POST")(createOrlistAllMemberships); +export default withMiddleware()( + defaultHandler({ + GET: import("./_get"), + POST: import("./_post"), + }) +); From e0619d383ab976f0ddf8d92b97ade894f343ccce Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 4 Nov 2022 12:14:54 -0700 Subject: [PATCH 546/658] Sync package.json --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index ebdb500e63..8a8ac1f369 100644 --- a/package.json +++ b/package.json @@ -36,11 +36,11 @@ "@calcom/features": "*", "@calcom/lib": "*", "@calcom/ui": "*", - "@sentry/nextjs": "^6.19.7", + "@sentry/nextjs": "^7.17.3", "bcryptjs": "^2.4.3", "memory-cache": "^0.2.0", "modify-response-middleware": "^1.1.0", - "next": "^12.2.5", + "next": "^12.3.1", "next-api-middleware": "^1.0.1", "next-axiom": "^0.10.0", "next-swagger-doc": "^0.3.4", From 0f5017010fd2f037aa053d04522048fa994eaf43 Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Mon, 7 Nov 2022 14:48:32 +0000 Subject: [PATCH 547/658] Fix lint error --- lib/validations/membership.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/membership.ts b/lib/validations/membership.ts index 27206d43b9..475b7d1116 100644 --- a/lib/validations/membership.ts +++ b/lib/validations/membership.ts @@ -1,8 +1,8 @@ -import { stringOrNumber } from "@calcom/prisma/zod-utils"; import { MembershipRole } from "@prisma/client"; import { z } from "zod"; import { _MembershipModel as Membership, _TeamModel } from "@calcom/prisma/zod"; +import { stringOrNumber } from "@calcom/prisma/zod-utils"; import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformParseInt"; From 51bc3d93c12ea6d220394b0aa13a8581cf27e42f Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Thu, 17 Nov 2022 18:35:06 +0000 Subject: [PATCH 548/658] user: Add email and username, remove bufferTime,startTime,endTime (#202) Co-authored-by: zomars --- lib/validations/user.ts | 30 +++++++++++++++++++++--------- pages/api/users/[userId]/_patch.ts | 2 +- pages/api/users/_post.ts | 2 +- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/lib/validations/user.ts b/lib/validations/user.ts index 2011401439..0c0448c678 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -1,6 +1,8 @@ import { z } from "zod"; +import { checkUsername } from "@calcom/lib/server/checkUsername"; import { _UserModel as User } from "@calcom/prisma/zod"; +import { iso8601 } from "@calcom/prisma/zod-utils"; import { timeZone } from "@lib/validations/shared/timeZone"; @@ -50,14 +52,26 @@ enum timeFormat { TWENTY_FOUR = 24, } +const usernameSchema = z + .string() + .transform((v) => v.toLowerCase()) + // .refine(() => {}) + .superRefine(async (val, ctx) => { + if (val) { + const result = await checkUsername(val); + if (!result.available) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "already_in_use_error" }); + if (result.premium) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "premium_username" }); + } + }); + // @note: These are the values that are editable via PATCH method on the user Model export const schemaUserBaseBodyParams = User.pick({ name: true, + email: true, + username: true, bio: true, timeZone: true, weekStart: true, - endTime: true, - bufferTime: true, theme: true, defaultScheduleId: true, locale: true, @@ -75,13 +89,12 @@ export const schemaUserBaseBodyParams = User.pick({ // Here we can both require or not (adding optional or nullish) and also rewrite validations for any value // for example making weekStart only accept weekdays as input const schemaUserEditParams = z.object({ + email: z.string().email(), + username: usernameSchema, weekStart: z.nativeEnum(weekdays).optional(), brandColor: z.string().min(4).max(9).regex(/^#/).optional(), darkBrandColor: z.string().min(4).max(9).regex(/^#/).optional(), timeZone: timeZone.optional(), - bufferTime: z.number().min(0).max(86400).optional(), - startTime: z.number().min(0).max(86400).optional(), - endTime: z.number().min(0).max(86400).optional(), theme: z.nativeEnum(theme).optional().nullable(), timeFormat: z.nativeEnum(timeFormat).optional(), defaultScheduleId: z @@ -97,13 +110,11 @@ const schemaUserEditParams = z.object({ const schemaUserCreateParams = z.object({ email: z.string().email(), + username: usernameSchema, weekStart: z.nativeEnum(weekdays).optional(), brandColor: z.string().min(4).max(9).regex(/^#/).optional(), darkBrandColor: z.string().min(4).max(9).regex(/^#/).optional(), timeZone: timeZone.optional(), - bufferTime: z.number().min(0).max(86400).optional(), - startTime: z.number().min(0).max(86400).optional(), - endTime: z.number().min(0).max(86400).optional(), theme: z.nativeEnum(theme).optional().nullable(), timeFormat: z.nativeEnum(timeFormat).optional(), defaultScheduleId: z @@ -112,7 +123,7 @@ const schemaUserCreateParams = z.object({ .optional() .nullable(), locale: z.nativeEnum(locales).optional(), - createdDate: z.string().or(z.date()).optional(), + createdDate: iso8601.optional(), }); // @note: These are the values that are editable via PATCH method on the user Model, @@ -120,6 +131,7 @@ const schemaUserCreateParams = z.object({ export const schemaUserEditBodyParams = schemaUserBaseBodyParams .merge(schemaUserEditParams) .omit({}) + .partial() .strict(); export const schemaUserCreateBodyParams = schemaUserBaseBodyParams diff --git a/pages/api/users/[userId]/_patch.ts b/pages/api/users/[userId]/_patch.ts index dd136a26ee..3f7761c539 100644 --- a/pages/api/users/[userId]/_patch.ts +++ b/pages/api/users/[userId]/_patch.ts @@ -59,7 +59,7 @@ export async function patchHandler(req: NextApiRequest) { // Here we only check for ownership of the user if the user is not admin, otherwise we let ADMIN's edit any user if (!isAdmin && query.userId !== req.userId) throw new HttpError({ statusCode: 403, message: "Forbidden" }); - const body = schemaUserEditBodyParams.parse(req.body); + const body = await schemaUserEditBodyParams.parseAsync(req.body); const userSchedules = await prisma.schedule.findMany({ where: { userId: query.userId }, }); diff --git a/pages/api/users/_post.ts b/pages/api/users/_post.ts index 268931b122..a8eff743dd 100644 --- a/pages/api/users/_post.ts +++ b/pages/api/users/_post.ts @@ -25,7 +25,7 @@ async function postHandler(req: NextApiRequest) { const { prisma, isAdmin } = req; // If user is not ADMIN, return unauthorized. if (!isAdmin) throw new HttpError({ statusCode: 401, message: "You are not authorized" }); - const data = schemaUserCreateBodyParams.parse(req.body); + const data = await schemaUserCreateBodyParams.parseAsync(req.body); const user = await prisma.user.create({ data }); req.statusCode = 201; return { user }; From e5827b035d696257609c3da413a26046e947c189 Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Fri, 18 Nov 2022 11:38:49 +0000 Subject: [PATCH 549/658] Fix type error with null being an invalid value (#213) --- pages/api/teams/[teamId]/_patch.ts | 9 ++++++++- pages/api/teams/_post.ts | 9 ++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/pages/api/teams/[teamId]/_patch.ts b/pages/api/teams/[teamId]/_patch.ts index a8782d5a4c..701464223b 100644 --- a/pages/api/teams/[teamId]/_patch.ts +++ b/pages/api/teams/[teamId]/_patch.ts @@ -38,7 +38,14 @@ export async function patchHandler(req: NextApiRequest) { where: { id: teamId, members: { some: { userId, role: { in: ["OWNER", "ADMIN"] } } } }, }); if (!_team) throw new HttpError({ statusCode: 401, message: "Unauthorized: OWNER or ADMIN required" }); - const team = await prisma.team.update({ where: { id: teamId }, data }); + // TODO: Perhaps there is a better fix for this? + const cloneData: typeof data & { + metadata: NonNullable | undefined; + } = { + ...data, + metadata: data.metadata === null ? {} : data.metadata || undefined, + }; + const team = await prisma.team.update({ where: { id: teamId }, data: cloneData }); return { team: schemaTeamReadPublic.parse(team) }; } diff --git a/pages/api/teams/_post.ts b/pages/api/teams/_post.ts index 54b8706d55..41207255ce 100644 --- a/pages/api/teams/_post.ts +++ b/pages/api/teams/_post.ts @@ -24,9 +24,16 @@ import { schemaTeamBodyParams, schemaTeamReadPublic } from "@lib/validations/tea async function postHandler(req: NextApiRequest) { const { prisma, body, userId } = req; const data = schemaTeamBodyParams.parse(body); + // TODO: Perhaps there is a better fix for this? + const cloneData: typeof data & { + metadata: NonNullable | undefined; + } = { + ...data, + metadata: data.metadata === null ? {} : data.metadata || undefined, + }; const team = await prisma.team.create({ data: { - ...data, + ...cloneData, members: { // We're also creating the relation membership of team ownership in this call. create: { userId, role: "OWNER", accepted: true }, From 4080e5bc5ed526cec82184efae8ef797b246e021 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Sat, 19 Nov 2022 00:48:07 +0530 Subject: [PATCH 550/658] Update availabilities _post swagger def (#210) - Adds more specs to the swagger definition in /availabilities for doc experimentation --- pages/api/availabilities/[id]/_delete.ts | 6 ++++ pages/api/availabilities/[id]/_get.ts | 10 +++++- pages/api/availabilities/[id]/_patch.ts | 41 ++++++++++++++++++------ pages/api/availabilities/_post.ts | 29 +++++++++++++++-- 4 files changed, 72 insertions(+), 14 deletions(-) diff --git a/pages/api/availabilities/[id]/_delete.ts b/pages/api/availabilities/[id]/_delete.ts index a298642d6f..df90d2bc55 100644 --- a/pages/api/availabilities/[id]/_delete.ts +++ b/pages/api/availabilities/[id]/_delete.ts @@ -17,6 +17,12 @@ import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformP * type: integer * required: true * description: ID of the availability to delete + * - in: query + * name: apiKey + * required: true + * schema: + * type: integer + * description: Your API key * tags: * - availabilities * externalDocs: diff --git a/pages/api/availabilities/[id]/_get.ts b/pages/api/availabilities/[id]/_get.ts index 3ea8064e05..f4fbe65f2a 100644 --- a/pages/api/availabilities/[id]/_get.ts +++ b/pages/api/availabilities/[id]/_get.ts @@ -18,6 +18,12 @@ import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformP * type: integer * required: true * description: ID of the availability to get + * - in: query + * name: apiKey + * required: true + * schema: + * type: integer + * description: Your API key * tags: * - availabilities * externalDocs: @@ -26,7 +32,9 @@ import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformP * 200: * description: OK * 401: - * description: Unauthorized + * description: Authorization information is missing or invalid + * 404: + * description: Availability not found */ export async function getHandler(req: NextApiRequest) { const { prisma, query } = req; diff --git a/pages/api/availabilities/[id]/_patch.ts b/pages/api/availabilities/[id]/_patch.ts index 9e7b0b5ebb..fdeb693799 100644 --- a/pages/api/availabilities/[id]/_patch.ts +++ b/pages/api/availabilities/[id]/_patch.ts @@ -14,6 +14,19 @@ import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformP * patch: * operationId: editAvailabilityById * summary: Edit an existing availability + * parameters: + * - in: query + * name: apiKey + * required: true + * description: Your API key + * schema: + * type: integer + * - in: path + * name: id + * required: true + * schema: + * type: integer + * description: ID of the availability to edit * requestBody: * description: Edit an existing availability related to one of your bookings * required: true @@ -24,20 +37,28 @@ import { schemaQueryIdParseInt } from "@lib/validations/shared/queryIdTransformP * properties: * days: * type: array - * example: email@example.com + * description: Array of integers depicting weekdays + * items: + * type: integer + * enum: [0, 1, 2, 3, 4, 5] + * scheduleId: + * type: integer + * description: ID of schedule this availability is associated with * startTime: * type: string - * example: 1970-01-01T17:00:00.000Z + * description: Start time of the availability * endTime: * type: string - * example: 1970-01-01T17:00:00.000Z - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the availability to edit + * description: End time of the availability + * examples: + * availability: + * summary: An example of availability + * value: + * scheduleId: 123 + * days: [1,2,3,5] + * startTime: 1970-01-01T17:00:00.000Z + * endTime: 1970-01-01T17:00:00.000Z + * * tags: * - availabilities * externalDocs: diff --git a/pages/api/availabilities/_post.ts b/pages/api/availabilities/_post.ts index aa4bac13fe..6169fbcc24 100644 --- a/pages/api/availabilities/_post.ts +++ b/pages/api/availabilities/_post.ts @@ -14,6 +14,13 @@ import { * post: * operationId: addAvailability * summary: Creates a new availability + * parameters: + * - in: query + * name: apiKey + * requiried: true + * description: Your API key + * schema: + * type: integer * requestBody: * description: Edit an existing availability related to one of your bookings * required: true @@ -28,13 +35,29 @@ import { * properties: * days: * type: array - * example: email@example.com + * description: Array of integers depicting weekdays + * items: + * type: integer + * enum: [0, 1, 2, 3, 4, 5] + * scheduleId: + * type: integer + * description: ID of schedule this availability is associated with * startTime: * type: string - * example: 1970-01-01T17:00:00.000Z + * description: Start time of the availability * endTime: * type: string - * example: 1970-01-01T17:00:00.000Z + * description: End time of the availability + * examples: + * availability: + * summary: An example of availability + * value: + * scheduleId: 123 + * days: [1,2,3,5] + * startTime: 1970-01-01T17:00:00.000Z + * endTime: 1970-01-01T17:00:00.000Z + * + * * tags: * - availabilities * externalDocs: From 3654677a202813711922da365d4933313928b033 Mon Sep 17 00:00:00 2001 From: Leo Giovanetti Date: Fri, 18 Nov 2022 16:19:33 -0300 Subject: [PATCH 551/658] Fixing unit test (#205) Fixing POST unit test for `apps/api/test/lib/bookings` --- test/lib/bookings/_post.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/lib/bookings/_post.test.ts b/test/lib/bookings/_post.test.ts index 8ba3295e79..9c2abc3afc 100644 --- a/test/lib/bookings/_post.test.ts +++ b/test/lib/bookings/_post.test.ts @@ -33,7 +33,7 @@ describe("POST /api/bookings", () => { expect(JSON.parse(res._getData())).toEqual( expect.objectContaining({ message: - "'invalid_type' in 'email': Required; 'invalid_type' in 'end': Required; 'invalid_type' in 'eventTypeId': Required; 'invalid_type' in 'location': Required; 'invalid_type' in 'name': Required; 'invalid_type' in 'start': Required; 'invalid_type' in 'timeZone': Required; 'invalid_type' in 'language': Required; 'invalid_type' in 'customInputs': Required; 'invalid_type' in 'metadata': Required", + "invalid_type in 'eventTypeId': Required; invalid_type in 'title': Required; invalid_type in 'startTime': Required; invalid_type in 'startTime': Required; invalid_type in 'endTime': Required; invalid_type in 'endTime': Required", }) ); }); From bbaa8ae5e7fd82a17bc8a5e5bf85cc6e0f536f7a Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Sat, 19 Nov 2022 00:50:15 +0530 Subject: [PATCH 552/658] Adds more definition to USER swagger (#212) Adds more definition for documentation for the USER endpoints --- pages/api/users/[userId]/_delete.ts | 10 ++++- pages/api/users/[userId]/_get.ts | 10 ++++- pages/api/users/[userId]/_patch.ts | 66 ++++++++++++++++++++++------- pages/api/users/_get.ts | 7 +++ pages/api/users/_post.ts | 59 ++++++++++++++++++++++++++ 5 files changed, 132 insertions(+), 20 deletions(-) diff --git a/pages/api/users/[userId]/_delete.ts b/pages/api/users/[userId]/_delete.ts index 46ab08e5f9..f089e64d62 100644 --- a/pages/api/users/[userId]/_delete.ts +++ b/pages/api/users/[userId]/_delete.ts @@ -7,18 +7,24 @@ import { schemaQueryUserId } from "@lib/validations/shared/queryUserId"; /** * @swagger - * /users/{id}: + * /users/{userId}: * delete: * summary: Remove an existing user * operationId: removeUserById * parameters: * - in: path - * name: id + * name: userId * example: 1 * schema: * type: integer * required: true * description: ID of the user to delete + * - in: query + * name: apiKey + * schema: + * type: string + * required: true + * description: Your API key * tags: * - users * responses: diff --git a/pages/api/users/[userId]/_get.ts b/pages/api/users/[userId]/_get.ts index 360103560b..598fe3be8e 100644 --- a/pages/api/users/[userId]/_get.ts +++ b/pages/api/users/[userId]/_get.ts @@ -8,18 +8,24 @@ import { schemaUserReadPublic } from "@lib/validations/user"; /** * @swagger - * /users/{id}: + * /users/{userId}: * get: * summary: Find a user, returns your user if regular user. * operationId: getUserById * parameters: * - in: path - * name: id + * name: userId * example: 4 * schema: * type: integer * required: true * description: ID of the user to get + * - in: query + * name: apiKey + * schema: + * type: string + * required: true + * description: Your API key * tags: * - users * responses: diff --git a/pages/api/users/[userId]/_patch.ts b/pages/api/users/[userId]/_patch.ts index 3f7761c539..4204cf7823 100644 --- a/pages/api/users/[userId]/_patch.ts +++ b/pages/api/users/[userId]/_patch.ts @@ -8,10 +8,24 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations /** * @swagger - * /users/{id}: + * /users/{userId}: * patch: * summary: Edit an existing user * operationId: editUserById + * parameters: + * - in: path + * name: userId + * example: 4 + * schema: + * type: integer + * required: true + * description: ID of the user to edit + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * requestBody: * description: Edit an existing attendee related to one of your bookings * required: true @@ -20,27 +34,47 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations * schema: * type: object * properties: - * weekStart: + * email: * type: string - * enum: [Monday, Sunday, Saturday] - * example: Monday + * format: email + * description: Email that belongs to the user being edited + * username: + * type: string + * description: Username for the user being edited * brandColor: + * description: The user's brand color * type: string - * example: "#FF000F" * darkBrandColor: + * description: The user's brand color for dark mode * type: string - * example: "#000000" - * timeZone: + * weekStart: + * description: Start of the week. Acceptable values are one of [SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY] * type: string - * example: Europe/London - * parameters: - * - in: path - * name: id - * example: 4 - * schema: - * type: integer - * required: true - * description: ID of the user to edit + * timeZone: + * description: The user's time zone + * type: string + * theme: + * description: Default theme for the user. Acceptable values are one of [DARK, LIGHT] + * type: string + * timeFormat: + * description: The user's time format. Acceptable values are one of [TWELVE, TWENTY_FOUR] + * type: string + * locale: + * description: The user's locale. Acceptable values are one of [EN, FR, IT, RU, ES, DE, PT, RO, NL, PT_BR, ES_419, KO, JA, PL, AR, IW, ZH_CH, ZH_TW, CS, SR, SV, VI] + * type: string + * examples: + * user: + * summary: An example of USER + * value: + * email: email@example.com + * username: johndoe + * weekStart: MONDAY + * brandColor: #555555 + * darkBrandColor: #111111 + * timeZone: EUROPE/PARIS + * theme: LIGHT + * timeFormat: TWELVE + * locale: FR * tags: * - users * responses: diff --git a/pages/api/users/_get.ts b/pages/api/users/_get.ts index 853eef938b..12638a0b39 100644 --- a/pages/api/users/_get.ts +++ b/pages/api/users/_get.ts @@ -13,6 +13,13 @@ import { Prisma } from ".prisma/client"; * get: * operationId: listUsers * summary: Find all users. + * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * tags: * - users * responses: diff --git a/pages/api/users/_post.ts b/pages/api/users/_post.ts index a8eff743dd..d69f7da43a 100644 --- a/pages/api/users/_post.ts +++ b/pages/api/users/_post.ts @@ -11,6 +11,65 @@ import { schemaUserCreateBodyParams } from "@lib/validations/user"; * post: * operationId: addUser * summary: Creates a new user + * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key + * requestBody: + * description: Create a new user + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - email + * - username + * properties: + * email: + * type: string + * format: email + * description: Email that belongs to the user being edited + * username: + * type: string + * description: Username for the user being created + * brandColor: + * description: The new user's brand color + * type: string + * darkBrandColor: + * description: The new user's brand color for dark mode + * type: string + * weekStart: + * description: Start of the week. Acceptable values are one of [SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY] + * type: string + * timeZone: + * description: The new user's time zone + * type: string + * theme: + * description: Default theme for the new user. Acceptable values are one of [DARK, LIGHT] + * type: string + * timeFormat: + * description: The new user's time format. Acceptable values are one of [TWELVE, TWENTY_FOUR] + * type: string + * locale: + * description: The new user's locale. Acceptable values are one of [EN, FR, IT, RU, ES, DE, PT, RO, NL, PT_BR, ES_419, KO, JA, PL, AR, IW, ZH_CH, ZH_TW, CS, SR, SV, VI] + * type: string + * examples: + * user: + * summary: An example of USER + * value: + * email: email@example.com + * username: johndoe + * weekStart: MONDAY + * brandColor: #555555 + * darkBrandColor: #111111 + * timeZone: EUROPE/PARIS + * theme: LIGHT + * timeFormat: TWELVE + * locale: FR * tags: * - users * responses: From 8e25b9244c1c1b57f4f3d2da74a0e28e28de9196 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Mon, 21 Nov 2022 10:49:55 +0530 Subject: [PATCH 553/658] Fix deployment failure due to prettier (extra spaces) (#214) Simply removes extra spaces which are causing prettier to fail deployment, introduced in the PR for USER swagger doc update --- pages/api/users/[userId]/_patch.ts | 2 +- pages/api/users/_post.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/api/users/[userId]/_patch.ts b/pages/api/users/[userId]/_patch.ts index 4204cf7823..3621d820f3 100644 --- a/pages/api/users/[userId]/_patch.ts +++ b/pages/api/users/[userId]/_patch.ts @@ -50,7 +50,7 @@ import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations * weekStart: * description: Start of the week. Acceptable values are one of [SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY] * type: string - * timeZone: + * timeZone: * description: The user's time zone * type: string * theme: diff --git a/pages/api/users/_post.ts b/pages/api/users/_post.ts index d69f7da43a..faa9a60898 100644 --- a/pages/api/users/_post.ts +++ b/pages/api/users/_post.ts @@ -45,7 +45,7 @@ import { schemaUserCreateBodyParams } from "@lib/validations/user"; * weekStart: * description: Start of the week. Acceptable values are one of [SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY] * type: string - * timeZone: + * timeZone: * description: The new user's time zone * type: string * theme: From c016a4343dbabbcb77b7a511f472fa500d8565bd Mon Sep 17 00:00:00 2001 From: alannnc Date: Tue, 22 Nov 2022 14:24:25 -0600 Subject: [PATCH 554/658] added more endpoints and validations for publish-pay teams (#209) ## What does the PR do? - Team billing via API Just like the web project, we validate that team has stripe metadata before converting requestedSlug to slug. Co-authored-by: zomars --- lib/validations/team.ts | 5 +- pages/api/attendees/_post.ts | 2 +- pages/api/event-types/_post.ts | 2 +- pages/api/teams/[teamId]/_auth-middleware.ts | 18 +++++++ pages/api/teams/[teamId]/_delete.ts | 14 +---- pages/api/teams/[teamId]/_patch.ts | 38 ++++++++++++- pages/api/teams/[teamId]/publish.ts | 57 ++++++++++++++++++++ pages/api/teams/_post.ts | 23 +++++++- 8 files changed, 142 insertions(+), 17 deletions(-) create mode 100644 pages/api/teams/[teamId]/publish.ts diff --git a/lib/validations/team.ts b/lib/validations/team.ts index 352b2ff431..e5f8e3cbfa 100644 --- a/lib/validations/team.ts +++ b/lib/validations/team.ts @@ -2,7 +2,10 @@ import { z } from "zod"; import { _TeamModel as Team } from "@calcom/prisma/zod"; -export const schemaTeamBaseBodyParams = Team.omit({ id: true }).partial({ hideBranding: true }); +export const schemaTeamBaseBodyParams = Team.omit({ id: true, createdAt: true }).partial({ + hideBranding: true, + metadata: true, +}); const schemaTeamRequiredParams = z.object({}); diff --git a/pages/api/attendees/_post.ts b/pages/api/attendees/_post.ts index 106007019d..4d74928eb9 100644 --- a/pages/api/attendees/_post.ts +++ b/pages/api/attendees/_post.ts @@ -1,6 +1,6 @@ -import { HttpError } from "@/../../packages/lib/http-error"; import type { NextApiRequest } from "next"; +import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; import { schemaAttendeeCreateBodyParams, schemaAttendeeReadPublic } from "@lib/validations/attendee"; diff --git a/pages/api/event-types/_post.ts b/pages/api/event-types/_post.ts index 75faa6d5c0..640b0b0b31 100644 --- a/pages/api/event-types/_post.ts +++ b/pages/api/event-types/_post.ts @@ -1,7 +1,7 @@ -import { HttpError } from "@/../../packages/lib/http-error"; import type { Prisma } from "@prisma/client"; import type { NextApiRequest } from "next"; +import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; import { schemaEventTypeCreateBodyParams, schemaEventTypeReadPublic } from "@lib/validations/event-type"; diff --git a/pages/api/teams/[teamId]/_auth-middleware.ts b/pages/api/teams/[teamId]/_auth-middleware.ts index 347c3e3075..13e906e5f9 100644 --- a/pages/api/teams/[teamId]/_auth-middleware.ts +++ b/pages/api/teams/[teamId]/_auth-middleware.ts @@ -1,5 +1,9 @@ +import type { Prisma } from "@prisma/client"; +import { MembershipRole } from "@prisma/client"; import type { NextApiRequest } from "next"; +import { HttpError } from "@calcom/lib/http-error"; + import { schemaQueryTeamId } from "@lib/validations/shared/queryTeamId"; async function authMiddleware(req: NextApiRequest) { @@ -13,4 +17,18 @@ async function authMiddleware(req: NextApiRequest) { }); } +export async function checkPermissions( + req: NextApiRequest, + role: Prisma.MembershipWhereInput["role"] = MembershipRole.OWNER +) { + const { userId, prisma, isAdmin } = req; + const { teamId } = schemaQueryTeamId.parse(req.query); + const args: Prisma.TeamFindFirstArgs = { where: { id: teamId } }; + /** If not ADMIN then we check if the actual user belongs to team and matches the required role */ + if (!isAdmin) args.where = { ...args.where, members: { some: { userId, role } } }; + const team = await prisma.team.findFirst(args); + if (!team) throw new HttpError({ statusCode: 401, message: `Unauthorized: ${role.toString()} required` }); + return team; +} + export default authMiddleware; diff --git a/pages/api/teams/[teamId]/_delete.ts b/pages/api/teams/[teamId]/_delete.ts index 9b8e723a9c..c9f4443809 100644 --- a/pages/api/teams/[teamId]/_delete.ts +++ b/pages/api/teams/[teamId]/_delete.ts @@ -1,10 +1,11 @@ import type { NextApiRequest } from "next"; -import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; import { schemaQueryTeamId } from "@lib/validations/shared/queryTeamId"; +import { checkPermissions } from "./_auth-middleware"; + /** * @swagger * /users/{teamId}: @@ -36,15 +37,4 @@ export async function deleteHandler(req: NextApiRequest) { return { message: `Team with id: ${teamId} deleted successfully` }; } -async function checkPermissions(req: NextApiRequest) { - const { userId, prisma, isAdmin } = req; - const { teamId } = schemaQueryTeamId.parse(req.query); - if (isAdmin) return; - /** Only OWNERS can delete teams */ - const _team = await prisma.team.findFirst({ - where: { id: teamId, members: { some: { userId, role: "OWNER" } } }, - }); - if (!_team) throw new HttpError({ statusCode: 401, message: "Unauthorized: OWNER required" }); -} - export default defaultResponder(deleteHandler); diff --git a/pages/api/teams/[teamId]/_patch.ts b/pages/api/teams/[teamId]/_patch.ts index 701464223b..0031677174 100644 --- a/pages/api/teams/[teamId]/_patch.ts +++ b/pages/api/teams/[teamId]/_patch.ts @@ -1,11 +1,17 @@ import type { NextApiRequest } from "next"; +import { purchaseTeamSubscription } from "@calcom/features/ee/teams/lib/payments"; +import { IS_TEAM_BILLING_ENABLED } from "@calcom/lib/constants"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; import { schemaQueryTeamId } from "@lib/validations/shared/queryTeamId"; import { schemaTeamReadPublic, schemaTeamUpdateBodyParams } from "@lib/validations/team"; +import { TRPCError } from "@trpc/server"; + +import { Prisma } from ".prisma/client"; + /** * @swagger * /teams/{teamId}: @@ -35,9 +41,32 @@ export async function patchHandler(req: NextApiRequest) { const { teamId } = schemaQueryTeamId.parse(req.query); /** Only OWNERS and ADMINS can edit teams */ const _team = await prisma.team.findFirst({ + include: { members: true }, where: { id: teamId, members: { some: { userId, role: { in: ["OWNER", "ADMIN"] } } } }, }); if (!_team) throw new HttpError({ statusCode: 401, message: "Unauthorized: OWNER or ADMIN required" }); + let paymentUrl; + if (_team.slug === null && data.slug) { + data.metadata = { + ...(_team.metadata as Prisma.JsonObject), + requestedSlug: data.slug, + }; + delete data.slug; + if (IS_TEAM_BILLING_ENABLED) { + const checkoutSession = await purchaseTeamSubscription({ + teamId: _team.id, + seats: _team.members.length, + userId, + }); + if (!checkoutSession.url) + throw new TRPCError({ + code: "INTERNAL_SERVER_ERROR", + message: "Failed retrieving a checkout session URL.", + }); + paymentUrl = checkoutSession.url; + } + } + // TODO: Perhaps there is a better fix for this? const cloneData: typeof data & { metadata: NonNullable | undefined; @@ -46,7 +75,14 @@ export async function patchHandler(req: NextApiRequest) { metadata: data.metadata === null ? {} : data.metadata || undefined, }; const team = await prisma.team.update({ where: { id: teamId }, data: cloneData }); - return { team: schemaTeamReadPublic.parse(team) }; + const result = { + team: schemaTeamReadPublic.parse(team), + paymentUrl, + }; + if (!paymentUrl) { + delete result.paymentUrl; + } + return result; } export default defaultResponder(patchHandler); diff --git a/pages/api/teams/[teamId]/publish.ts b/pages/api/teams/[teamId]/publish.ts new file mode 100644 index 0000000000..f99762fe52 --- /dev/null +++ b/pages/api/teams/[teamId]/publish.ts @@ -0,0 +1,57 @@ +import { MembershipRole, UserPermissionRole } from "@prisma/client"; +import { NextApiRequest, NextApiResponse } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; +import { defaultHandler, defaultResponder } from "@calcom/lib/server"; +import { createContext } from "@calcom/trpc/server/createContext"; +import { viewerRouter } from "@calcom/trpc/server/routers/viewer"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { schemaQueryTeamId } from "@lib/validations/shared/queryTeamId"; + +import { TRPCError } from "@trpc/server"; +import { getHTTPStatusCodeFromError } from "@trpc/server/http"; + +import authMiddleware, { checkPermissions } from "./_auth-middleware"; + +const patchHandler = async (req: NextApiRequest, res: NextApiResponse) => { + const { isAdmin } = req; + await checkPermissions(req, { in: [MembershipRole.OWNER, MembershipRole.ADMIN] }); + + /** We shape the session as required by tRPC rounter */ + async function sessionGetter() { + return { + user: { + id: req.userId, + username: "" /* Not used in this context */, + role: isAdmin ? UserPermissionRole.ADMIN : UserPermissionRole.USER, + }, + hasValidLicense: true, + expires: "" /* Not used in this context */, + }; + } + + /** @see https://trpc.io/docs/server-side-calls */ + const ctx = await createContext({ req, res }, sessionGetter); + const caller = viewerRouter.createCaller(ctx); + try { + const { teamId } = schemaQueryTeamId.parse(req.query); + const success_url = req.url?.replace("/publish", ""); + return await caller.teams.publish({ teamId, success_url }); + } catch (cause) { + if (cause instanceof TRPCError) { + const statusCode = getHTTPStatusCodeFromError(cause); + throw new HttpError({ statusCode, message: cause.message }); + } + throw cause; + } +}; + +export default withMiddleware()( + defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { + await authMiddleware(req); + return defaultHandler({ + PATCH: Promise.resolve({ default: defaultResponder(patchHandler) }), + })(req, res); + }) +); diff --git a/pages/api/teams/_post.ts b/pages/api/teams/_post.ts index 41207255ce..5ec2a0d032 100644 --- a/pages/api/teams/_post.ts +++ b/pages/api/teams/_post.ts @@ -1,5 +1,8 @@ +import { MembershipRole } from "@prisma/client"; import type { NextApiRequest } from "next"; +import { IS_TEAM_BILLING_ENABLED } from "@calcom/lib/constants"; +import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; import { schemaMembershipPublic } from "@lib/validations/membership"; @@ -24,6 +27,23 @@ import { schemaTeamBodyParams, schemaTeamReadPublic } from "@lib/validations/tea async function postHandler(req: NextApiRequest) { const { prisma, body, userId } = req; const data = schemaTeamBodyParams.parse(body); + + if (data.slug) { + const alreadyExist = await prisma.team.findFirst({ + where: { + slug: data.slug, + }, + }); + if (alreadyExist) throw new HttpError({ statusCode: 409, message: "Team slug already exists" }); + if (IS_TEAM_BILLING_ENABLED) { + // Setting slug in metadata, so it can be published later + data.metadata = { + requestedSlug: data.slug, + }; + delete data.slug; + } + } + // TODO: Perhaps there is a better fix for this? const cloneData: typeof data & { metadata: NonNullable | undefined; @@ -34,9 +54,10 @@ async function postHandler(req: NextApiRequest) { const team = await prisma.team.create({ data: { ...cloneData, + createdAt: new Date(), members: { // We're also creating the relation membership of team ownership in this call. - create: { userId, role: "OWNER", accepted: true }, + create: { userId, role: MembershipRole.OWNER, accepted: true }, }, }, include: { members: true }, From 3d84ce68c9baa5d4ce7c85a37a9b8678f399b7a7 Mon Sep 17 00:00:00 2001 From: zomars Date: Tue, 22 Nov 2022 19:50:00 -0700 Subject: [PATCH 555/658] Tests updates --- test/lib/bookings/_post.test.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/lib/bookings/_post.test.ts b/test/lib/bookings/_post.test.ts index 9c2abc3afc..9072f9e35b 100644 --- a/test/lib/bookings/_post.test.ts +++ b/test/lib/bookings/_post.test.ts @@ -4,7 +4,7 @@ import { createMocks } from "node-mocks-http"; import dayjs from "@calcom/dayjs"; import sendPayload from "@calcom/features/webhooks/lib/sendPayload"; -import { buildBooking, buildEventType, buildWebhook, buildUser } from "@calcom/lib/test/builder"; +import { buildBooking, buildEventType, buildWebhook } from "@calcom/lib/test/builder"; import prisma from "@calcom/prisma"; import { prismaMock } from "../../../../../tests/config/singleton"; @@ -137,7 +137,7 @@ describe("POST /api/bookings", () => { prisma, }); - prismaMock.eventType.findUniqueOrThrow.mockResolvedValue(buildEventType({ users: [] })); + prismaMock.eventType.findUniqueOrThrow.mockResolvedValue(buildEventType()); await handler(req, res); console.log({ statusCode: res._getStatusCode(), data: JSON.parse(res._getData()) }); @@ -172,7 +172,7 @@ describe("POST /api/bookings", () => { prisma, }); - prismaMock.eventType.findUniqueOrThrow.mockResolvedValue(buildEventType({ users: [buildUser()] })); + prismaMock.eventType.findUniqueOrThrow.mockResolvedValue(buildEventType()); prismaMock.booking.findMany.mockResolvedValue([]); await handler(req, res); From faa685adb60bee2cad75518ca7bfa3d6831114f1 Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 25 Nov 2022 05:47:35 -0700 Subject: [PATCH 556/658] Sync to monorepo --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8a8ac1f369..6e4c38d38d 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@calcom/features": "*", "@calcom/lib": "*", "@calcom/ui": "*", - "@sentry/nextjs": "^7.17.3", + "@sentry/nextjs": "^7.20.0", "bcryptjs": "^2.4.3", "memory-cache": "^0.2.0", "modify-response-middleware": "^1.1.0", From 94ecb1908acb4a16551018bf30108e4891b12ec9 Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 25 Nov 2022 06:03:40 -0700 Subject: [PATCH 557/658] Type fixes --- pages/api/teams/[teamId]/publish.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pages/api/teams/[teamId]/publish.ts b/pages/api/teams/[teamId]/publish.ts index f99762fe52..f35695cd71 100644 --- a/pages/api/teams/[teamId]/publish.ts +++ b/pages/api/teams/[teamId]/publish.ts @@ -36,8 +36,7 @@ const patchHandler = async (req: NextApiRequest, res: NextApiResponse) => { const caller = viewerRouter.createCaller(ctx); try { const { teamId } = schemaQueryTeamId.parse(req.query); - const success_url = req.url?.replace("/publish", ""); - return await caller.teams.publish({ teamId, success_url }); + return await caller.teams.publish({ teamId }); } catch (cause) { if (cause instanceof TRPCError) { const statusCode = getHTTPStatusCodeFromError(cause); From 055699f612169bf71538e03b86a1074cb18b6759 Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 25 Nov 2022 06:56:58 -0700 Subject: [PATCH 558/658] Various import and type fixes --- lib/helpers/extendRequest.ts | 19 ---------------- lib/helpers/verifyApiKey.ts | 2 +- lib/types.ts | 22 +++++++++---------- lib/validations/attendee.ts | 2 +- lib/validations/event-type.ts | 2 +- lib/validations/membership.ts | 4 ++-- lib/validations/user.ts | 2 +- next.config.js | 1 - package.json | 1 - pages/api/attendees/[id]/_auth-middleware.ts | 2 +- pages/api/attendees/[id]/_delete.ts | 2 +- pages/api/attendees/[id]/_get.ts | 4 ++-- pages/api/attendees/[id]/_patch.ts | 4 ++-- pages/api/attendees/[id]/index.ts | 2 +- pages/api/attendees/_get.ts | 2 +- pages/api/attendees/_post.ts | 2 +- pages/api/attendees/index.ts | 2 +- .../availabilities/[id]/_auth-middleware.ts | 2 +- pages/api/availabilities/[id]/_delete.ts | 2 +- pages/api/availabilities/[id]/_get.ts | 4 ++-- pages/api/availabilities/[id]/_patch.ts | 4 ++-- pages/api/availabilities/[id]/index.ts | 2 +- pages/api/availabilities/_post.ts | 2 +- pages/api/availabilities/index.ts | 2 +- pages/api/availability/index.ts | 2 +- .../[id]/_auth-middleware.ts | 2 +- pages/api/booking-references/[id]/_delete.ts | 2 +- pages/api/booking-references/[id]/_get.ts | 4 ++-- pages/api/booking-references/[id]/_patch.ts | 4 ++-- pages/api/booking-references/[id]/index.ts | 2 +- pages/api/booking-references/_get.ts | 2 +- pages/api/booking-references/_post.ts | 2 +- pages/api/booking-references/index.ts | 2 +- pages/api/bookings/[id]/_auth-middleware.ts | 2 +- pages/api/bookings/[id]/_delete.ts | 2 +- pages/api/bookings/[id]/_get.ts | 4 ++-- pages/api/bookings/[id]/_patch.ts | 4 ++-- pages/api/bookings/[id]/cancel.ts | 2 +- pages/api/bookings/[id]/index.ts | 2 +- pages/api/bookings/_get.ts | 4 ++-- pages/api/bookings/index.ts | 2 +- .../custom-inputs/[id]/_auth-middleware.ts | 2 +- pages/api/custom-inputs/[id]/_delete.ts | 2 +- pages/api/custom-inputs/[id]/_get.ts | 4 ++-- pages/api/custom-inputs/[id]/_patch.ts | 4 ++-- pages/api/custom-inputs/[id]/index.ts | 2 +- pages/api/custom-inputs/_get.ts | 2 +- pages/api/custom-inputs/_post.ts | 2 +- pages/api/custom-inputs/index.ts | 2 +- pages/api/destination-calendars/[id].ts | 8 +++---- pages/api/destination-calendars/index.ts | 6 ++--- pages/api/docs.ts | 3 ++- .../api/event-types/[id]/_auth-middleware.ts | 2 +- pages/api/event-types/[id]/_delete.ts | 2 +- pages/api/event-types/[id]/_get.ts | 4 ++-- pages/api/event-types/[id]/_patch.ts | 4 ++-- pages/api/event-types/[id]/index.ts | 2 +- pages/api/event-types/_get.ts | 4 ++-- pages/api/event-types/_post.ts | 2 +- pages/api/event-types/index.ts | 2 +- pages/api/me/_get.ts | 2 +- pages/api/me/index.ts | 2 +- .../api/memberships/[id]/_auth-middleware.ts | 2 +- pages/api/memberships/[id]/_delete.ts | 4 ++-- pages/api/memberships/[id]/_get.ts | 2 +- pages/api/memberships/[id]/_patch.ts | 2 +- pages/api/memberships/[id]/index.ts | 2 +- pages/api/memberships/_get.ts | 4 ++-- pages/api/memberships/_post.ts | 2 +- pages/api/memberships/index.ts | 2 +- pages/api/payments/[id].ts | 8 +++---- pages/api/payments/index.ts | 6 ++--- pages/api/schedules/[id]/_auth-middleware.ts | 2 +- pages/api/schedules/[id]/_delete.ts | 2 +- pages/api/schedules/[id]/_get.ts | 4 ++-- pages/api/schedules/[id]/_patch.ts | 4 ++-- pages/api/schedules/[id]/index.ts | 2 +- pages/api/schedules/_get.ts | 4 ++-- pages/api/schedules/_post.ts | 2 +- pages/api/schedules/index.ts | 2 +- .../[id]/_auth-middleware.ts | 2 +- pages/api/selected-calendars/[id]/_delete.ts | 2 +- pages/api/selected-calendars/[id]/_get.ts | 2 +- pages/api/selected-calendars/[id]/_patch.ts | 2 +- pages/api/selected-calendars/[id]/index.ts | 2 +- pages/api/selected-calendars/_get.ts | 4 ++-- pages/api/selected-calendars/_post.ts | 2 +- pages/api/selected-calendars/index.ts | 2 +- pages/api/teams/[teamId]/_auth-middleware.ts | 2 +- pages/api/teams/[teamId]/_delete.ts | 2 +- pages/api/teams/[teamId]/_get.ts | 4 ++-- pages/api/teams/[teamId]/_patch.ts | 7 +++--- .../api/teams/[teamId]/availability/index.ts | 4 ++-- pages/api/teams/[teamId]/index.ts | 2 +- pages/api/teams/[teamId]/publish.ts | 6 ++--- pages/api/teams/_get.ts | 2 +- pages/api/teams/_post.ts | 4 ++-- pages/api/teams/index.ts | 2 +- pages/api/users/[userId]/_delete.ts | 2 +- pages/api/users/[userId]/_get.ts | 4 ++-- pages/api/users/[userId]/_patch.ts | 4 ++-- .../api/users/[userId]/availability/index.ts | 4 ++-- pages/api/users/[userId]/index.ts | 4 ++-- pages/api/users/_get.ts | 4 ++-- pages/api/users/_post.ts | 2 +- pages/api/users/index.ts | 2 +- pages/api/webhooks/[id]/_auth-middleware.ts | 2 +- pages/api/webhooks/[id]/_delete.ts | 2 +- pages/api/webhooks/[id]/_get.ts | 4 ++-- pages/api/webhooks/[id]/_patch.ts | 4 ++-- pages/api/webhooks/[id]/index.ts | 2 +- pages/api/webhooks/_get.ts | 4 ++-- pages/api/webhooks/_post.ts | 2 +- pages/api/webhooks/index.ts | 2 +- tsconfig.json | 18 ++++----------- 115 files changed, 172 insertions(+), 203 deletions(-) diff --git a/lib/helpers/extendRequest.ts b/lib/helpers/extendRequest.ts index d01cce81e2..430504be7b 100644 --- a/lib/helpers/extendRequest.ts +++ b/lib/helpers/extendRequest.ts @@ -1,24 +1,5 @@ -import type { IncomingMessage } from "http"; import { NextMiddleware } from "next-api-middleware"; -import type { PrismaClient } from "@calcom/prisma/client"; - -/** @todo figure how to use the one from `@calcom/types` */ -/** @todo: remove once `@calcom/types` is updated with it.*/ -declare module "next" { - export interface NextApiRequest extends IncomingMessage { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - body: any; - userId: number; - method: string; - prisma: PrismaClient; - session: { user: { id: number } }; - query: Partial<{ [key: string]: string | string[] }>; - isAdmin: boolean; - isCustomPrisma: boolean; - pagination: { take: number; skip: number }; - } -} export const extendRequest: NextMiddleware = async (req, res, next) => { req.pagination = { take: 100, diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index ee252d91fd..3f8731c33c 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -3,7 +3,7 @@ import { NextMiddleware } from "next-api-middleware"; import { hashAPIKey } from "@calcom/features/ee/api-keys/lib/apiKeys"; import checkLicense from "@calcom/features/ee/common/server/checkLicense"; -import { isAdminGuard } from "@lib/utils/isAdmin"; +import { isAdminGuard } from "~/lib/utils/isAdmin"; // Used to check if the apiKey is not expired, could be extracted if reused. but not for now. export const dateNotInPast = function (date: Date) { diff --git a/lib/types.ts b/lib/types.ts index db806fa3aa..b75941c517 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -1,21 +1,21 @@ -import { AppStoreLocationType, DefaultEventLocationType } from "@calcom/app-store/locations"; +import type { EventLocationType } from "@calcom/app-store/locations"; import { - User, - Team, - Credential, - SelectedCalendar, - EventTypeCustomInput, Attendee, Availability, - BookingReference, Booking, - Webhook, + BookingReference, + Credential, DestinationCalendar, + EventType, + EventTypeCustomInput, Membership, Payment, - Schedule, ReminderMail, - EventType, + Schedule, + SelectedCalendar, + Team, + User, + Webhook, } from "@calcom/prisma/client"; // Base response, used for all responses @@ -139,7 +139,7 @@ interface EventTypeExtended extends Omit { diff --git a/pages/api/teams/_get.ts b/pages/api/teams/_get.ts index 9e9adebcdb..21fb8eb85e 100644 --- a/pages/api/teams/_get.ts +++ b/pages/api/teams/_get.ts @@ -3,7 +3,7 @@ import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; -import { schemaTeamsReadPublic } from "@lib/validations/team"; +import { schemaTeamsReadPublic } from "~/lib/validations/team"; /** * @swagger diff --git a/pages/api/teams/_post.ts b/pages/api/teams/_post.ts index 5ec2a0d032..ef0783e4df 100644 --- a/pages/api/teams/_post.ts +++ b/pages/api/teams/_post.ts @@ -5,8 +5,8 @@ import { IS_TEAM_BILLING_ENABLED } from "@calcom/lib/constants"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import { schemaMembershipPublic } from "@lib/validations/membership"; -import { schemaTeamBodyParams, schemaTeamReadPublic } from "@lib/validations/team"; +import { schemaMembershipPublic } from "~/lib/validations/membership"; +import { schemaTeamBodyParams, schemaTeamReadPublic } from "~/lib/validations/team"; /** * @swagger diff --git a/pages/api/teams/index.ts b/pages/api/teams/index.ts index 4c33cbe75d..2a15abfa5b 100644 --- a/pages/api/teams/index.ts +++ b/pages/api/teams/index.ts @@ -1,6 +1,6 @@ import { defaultHandler } from "@calcom/lib/server"; -import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { withMiddleware } from "~/lib/helpers/withMiddleware"; export default withMiddleware()( defaultHandler({ diff --git a/pages/api/users/[userId]/_delete.ts b/pages/api/users/[userId]/_delete.ts index f089e64d62..44e8f0df0f 100644 --- a/pages/api/users/[userId]/_delete.ts +++ b/pages/api/users/[userId]/_delete.ts @@ -3,7 +3,7 @@ import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import { schemaQueryUserId } from "@lib/validations/shared/queryUserId"; +import { schemaQueryUserId } from "~/lib/validations/shared/queryUserId"; /** * @swagger diff --git a/pages/api/users/[userId]/_get.ts b/pages/api/users/[userId]/_get.ts index 598fe3be8e..5be3926ae0 100644 --- a/pages/api/users/[userId]/_get.ts +++ b/pages/api/users/[userId]/_get.ts @@ -3,8 +3,8 @@ import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import { schemaQueryUserId } from "@lib/validations/shared/queryUserId"; -import { schemaUserReadPublic } from "@lib/validations/user"; +import { schemaQueryUserId } from "~/lib/validations/shared/queryUserId"; +import { schemaUserReadPublic } from "~/lib/validations/user"; /** * @swagger diff --git a/pages/api/users/[userId]/_patch.ts b/pages/api/users/[userId]/_patch.ts index 3621d820f3..1d823f067f 100644 --- a/pages/api/users/[userId]/_patch.ts +++ b/pages/api/users/[userId]/_patch.ts @@ -3,8 +3,8 @@ import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import { schemaQueryUserId } from "@lib/validations/shared/queryUserId"; -import { schemaUserEditBodyParams, schemaUserReadPublic } from "@lib/validations/user"; +import { schemaQueryUserId } from "~/lib/validations/shared/queryUserId"; +import { schemaUserEditBodyParams, schemaUserReadPublic } from "~/lib/validations/user"; /** * @swagger diff --git a/pages/api/users/[userId]/availability/index.ts b/pages/api/users/[userId]/availability/index.ts index 94bb68733e..95a9f13f9c 100644 --- a/pages/api/users/[userId]/availability/index.ts +++ b/pages/api/users/[userId]/availability/index.ts @@ -1,9 +1,9 @@ import { defaultHandler } from "@calcom/lib/server"; -import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { withMiddleware } from "~/lib/helpers/withMiddleware"; export default withMiddleware()( defaultHandler({ - GET: import("@api/availability/_get"), + GET: import("~/pages/api/availability/_get"), }) ); diff --git a/pages/api/users/[userId]/index.ts b/pages/api/users/[userId]/index.ts index 2b0beaf345..b6cb937af3 100644 --- a/pages/api/users/[userId]/index.ts +++ b/pages/api/users/[userId]/index.ts @@ -1,7 +1,7 @@ import { defaultHandler } from "@calcom/lib/server"; -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { withValidQueryUserId } from "@lib/validations/shared/queryUserId"; +import { withMiddleware } from "~/lib/helpers/withMiddleware"; +import { withValidQueryUserId } from "~/lib/validations/shared/queryUserId"; export default withMiddleware()( withValidQueryUserId( diff --git a/pages/api/users/_get.ts b/pages/api/users/_get.ts index 12638a0b39..6c6e140e7a 100644 --- a/pages/api/users/_get.ts +++ b/pages/api/users/_get.ts @@ -2,8 +2,8 @@ import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; -import { withMiddleware } from "@lib/helpers/withMiddleware"; -import { schemaUsersReadPublic } from "@lib/validations/user"; +import { withMiddleware } from "~/lib/helpers/withMiddleware"; +import { schemaUsersReadPublic } from "~/lib/validations/user"; import { Prisma } from ".prisma/client"; diff --git a/pages/api/users/_post.ts b/pages/api/users/_post.ts index faa9a60898..2346e35876 100644 --- a/pages/api/users/_post.ts +++ b/pages/api/users/_post.ts @@ -3,7 +3,7 @@ import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import { schemaUserCreateBodyParams } from "@lib/validations/user"; +import { schemaUserCreateBodyParams } from "~/lib/validations/user"; /** * @swagger diff --git a/pages/api/users/index.ts b/pages/api/users/index.ts index 4c33cbe75d..2a15abfa5b 100644 --- a/pages/api/users/index.ts +++ b/pages/api/users/index.ts @@ -1,6 +1,6 @@ import { defaultHandler } from "@calcom/lib/server"; -import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { withMiddleware } from "~/lib/helpers/withMiddleware"; export default withMiddleware()( defaultHandler({ diff --git a/pages/api/webhooks/[id]/_auth-middleware.ts b/pages/api/webhooks/[id]/_auth-middleware.ts index ef45e638ed..6f2eb04db5 100644 --- a/pages/api/webhooks/[id]/_auth-middleware.ts +++ b/pages/api/webhooks/[id]/_auth-middleware.ts @@ -2,7 +2,7 @@ import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; -import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; +import { schemaQueryIdAsString } from "~/lib/validations/shared/queryIdString"; async function authMiddleware(req: NextApiRequest) { const { userId, isAdmin, prisma } = req; diff --git a/pages/api/webhooks/[id]/_delete.ts b/pages/api/webhooks/[id]/_delete.ts index cb0998bd94..e0e2979ab0 100644 --- a/pages/api/webhooks/[id]/_delete.ts +++ b/pages/api/webhooks/[id]/_delete.ts @@ -2,7 +2,7 @@ import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; -import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; +import { schemaQueryIdAsString } from "~/lib/validations/shared/queryIdString"; /** * @swagger diff --git a/pages/api/webhooks/[id]/_get.ts b/pages/api/webhooks/[id]/_get.ts index 3b9639c2c6..216684cc90 100644 --- a/pages/api/webhooks/[id]/_get.ts +++ b/pages/api/webhooks/[id]/_get.ts @@ -2,8 +2,8 @@ import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; -import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; -import { schemaWebhookReadPublic } from "@lib/validations/webhook"; +import { schemaQueryIdAsString } from "~/lib/validations/shared/queryIdString"; +import { schemaWebhookReadPublic } from "~/lib/validations/webhook"; /** * @swagger diff --git a/pages/api/webhooks/[id]/_patch.ts b/pages/api/webhooks/[id]/_patch.ts index cb645e4363..baa53d257a 100644 --- a/pages/api/webhooks/[id]/_patch.ts +++ b/pages/api/webhooks/[id]/_patch.ts @@ -4,8 +4,8 @@ import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; -import { schemaWebhookEditBodyParams, schemaWebhookReadPublic } from "@lib/validations/webhook"; +import { schemaQueryIdAsString } from "~/lib/validations/shared/queryIdString"; +import { schemaWebhookEditBodyParams, schemaWebhookReadPublic } from "~/lib/validations/webhook"; /** * @swagger diff --git a/pages/api/webhooks/[id]/index.ts b/pages/api/webhooks/[id]/index.ts index e0839f1eff..727ad02843 100644 --- a/pages/api/webhooks/[id]/index.ts +++ b/pages/api/webhooks/[id]/index.ts @@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from "next"; import { defaultHandler, defaultResponder } from "@calcom/lib/server"; -import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { withMiddleware } from "~/lib/helpers/withMiddleware"; import authMiddleware from "./_auth-middleware"; diff --git a/pages/api/webhooks/_get.ts b/pages/api/webhooks/_get.ts index fbf4665561..6b00b00e47 100644 --- a/pages/api/webhooks/_get.ts +++ b/pages/api/webhooks/_get.ts @@ -4,8 +4,8 @@ import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import { schemaQuerySingleOrMultipleUserIds } from "@lib/validations/shared/queryUserId"; -import { schemaWebhookReadPublic } from "@lib/validations/webhook"; +import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/queryUserId"; +import { schemaWebhookReadPublic } from "~/lib/validations/webhook"; /** * @swagger diff --git a/pages/api/webhooks/_post.ts b/pages/api/webhooks/_post.ts index f87b8ffe57..ab8cc028e3 100644 --- a/pages/api/webhooks/_post.ts +++ b/pages/api/webhooks/_post.ts @@ -5,7 +5,7 @@ import { v4 as uuidv4 } from "uuid"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import { schemaWebhookCreateBodyParams, schemaWebhookReadPublic } from "@lib/validations/webhook"; +import { schemaWebhookCreateBodyParams, schemaWebhookReadPublic } from "~/lib/validations/webhook"; /** * @swagger diff --git a/pages/api/webhooks/index.ts b/pages/api/webhooks/index.ts index 4c33cbe75d..2a15abfa5b 100644 --- a/pages/api/webhooks/index.ts +++ b/pages/api/webhooks/index.ts @@ -1,6 +1,6 @@ import { defaultHandler } from "@calcom/lib/server"; -import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { withMiddleware } from "~/lib/helpers/withMiddleware"; export default withMiddleware()( defaultHandler({ diff --git a/tsconfig.json b/tsconfig.json index 3e4341ce5e..c6b3666313 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,26 +5,16 @@ "jsx": "preserve", "baseUrl": ".", "paths": { - "@api/*": [ - "pages/api/*" - ], - "@lib/*": [ - "lib/*" - ], - "@/*": [ - "*" - ] + "~/*": ["*"], + "@prisma/client/*": ["@calcom/prisma/client/*"] } }, "include": [ "next-env.d.ts", "**/*.ts", "**/*.tsx", + "../../packages/types/*.d.ts", "../../packages/types/next-auth.d.ts" ], - "exclude": [ - "node_modules", - "templates", - "auth" - ] + "exclude": ["node_modules", "templates", "auth"] } From 48b637164c66344171c33ef74faa3384c2b1596d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Sun, 27 Nov 2022 15:36:36 -0700 Subject: [PATCH 559/658] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index dd278617f0..fe7e8da7f2 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,8 @@ To remove this limitation, we need to ensure that on local endpoints are request ## Hosted api through cal.com +> _❗ WARNING: This is still experimental and not fully implemented yet❗_ + Go to console.cal.com Add a deployment or go to an existing one. Activate API or Admin addon From 26ea743af23f84c1186e1f4235fa22cdb905a4c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Tue, 29 Nov 2022 09:07:53 -0700 Subject: [PATCH 560/658] Update README.md --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fe7e8da7f2..c31304595b 100644 --- a/README.md +++ b/README.md @@ -210,14 +210,20 @@ We recommend deploying API in vercel. There's some settings that you'll need to setup. -Under Vercel > Your API Deployment > Settings +Under Vercel > Your API Project > Settings In General > Build & Development Settings BUILD COMMAND: `yarn turbo run build --scope=@calcom/api --include-dependencies --no-deps` OUTPUT DIRECTORY: `apps/api/.next` +In Git > Ignored Build Step + +Add this command: `./scripts/vercel-deploy.sh` + See `scripts/vercel-deploy.sh` for more info on how the deployment is done. +> _❗ IMORTANT: If you're forking the API repo you will need to update the URLs in both the main repo [`.gitmodules`](https://github.com/calcom/cal.com/blob/main/.gitmodules#L7) and this repo [`./scripts/vercel-deploy.sh`](https://github.com/calcom/api/blob/main/scripts/vercel-deploy.sh#L3) ❗_ + ## Environment variables Lastly API requires an env var for `DATABASE_URL` and `CALCOM_LICENSE_KEY` From d35f27014e3d47b2692b91a6c4194324ad9e4a0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Tue, 29 Nov 2022 15:06:23 -0700 Subject: [PATCH 561/658] Implements API key endpoint (#211) This allow us to manage our API keys directly from the API itself. User can: - Create own API keys - Edit own API keys (only the note field for now) - Delete own API keys - Get own API keys Admin can: - CRUD for any user - Get all API keys --- lib/validations/api-key.ts | 29 ++++++++++++++ pages/api/api-keys/[id]/_auth-middleware.ts | 17 ++++++++ pages/api/api-keys/[id]/_delete.ts | 14 +++++++ pages/api/api-keys/[id]/_get.ts | 15 +++++++ pages/api/api-keys/[id]/_patch.ts | 16 ++++++++ pages/api/api-keys/[id]/index.ts | 18 +++++++++ pages/api/api-keys/_get.ts | 40 +++++++++++++++++++ pages/api/api-keys/_post.ts | 44 +++++++++++++++++++++ pages/api/api-keys/index.ts | 10 +++++ 9 files changed, 203 insertions(+) create mode 100644 lib/validations/api-key.ts create mode 100644 pages/api/api-keys/[id]/_auth-middleware.ts create mode 100644 pages/api/api-keys/[id]/_delete.ts create mode 100644 pages/api/api-keys/[id]/_get.ts create mode 100644 pages/api/api-keys/[id]/_patch.ts create mode 100644 pages/api/api-keys/[id]/index.ts create mode 100644 pages/api/api-keys/_get.ts create mode 100644 pages/api/api-keys/_post.ts create mode 100644 pages/api/api-keys/index.ts diff --git a/lib/validations/api-key.ts b/lib/validations/api-key.ts new file mode 100644 index 0000000000..c0afb8eb16 --- /dev/null +++ b/lib/validations/api-key.ts @@ -0,0 +1,29 @@ +import { z } from "zod"; + +import { _ApiKeyModel as ApiKey } from "@calcom/prisma/zod"; + +export const apiKeyCreateBodySchema = ApiKey.pick({ + note: true, + expiresAt: true, + userId: true, +}) + .partial({ userId: true }) + .merge(z.object({ neverExpires: z.boolean().optional() })) + .strict(); + +export const apiKeyEditBodySchema = ApiKey.pick({ + note: true, +}) + .partial() + .strict(); + +export const apiKeyPublicSchema = ApiKey.pick({ + id: true, + userId: true, + note: true, + createdAt: true, + expiresAt: true, + lastUsedAt: true, + /** We might never want to expose these. Leaving this a as reminder. */ + // hashedKey: true, +}); diff --git a/pages/api/api-keys/[id]/_auth-middleware.ts b/pages/api/api-keys/[id]/_auth-middleware.ts new file mode 100644 index 0000000000..3137ccad25 --- /dev/null +++ b/pages/api/api-keys/[id]/_auth-middleware.ts @@ -0,0 +1,17 @@ +import type { NextApiRequest } from "next"; + +import { HttpError } from "@calcom/lib/http-error"; + +import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; + +export async function authMiddleware(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const { id } = schemaQueryIdAsString.parse(req.query); + // Admin can check any api key + if (isAdmin) return; + // Check if user can access the api key + const apiKey = await prisma.apiKey.findFirst({ + where: { id, userId }, + }); + if (!apiKey) throw new HttpError({ statusCode: 404, message: "API key not found" }); +} diff --git a/pages/api/api-keys/[id]/_delete.ts b/pages/api/api-keys/[id]/_delete.ts new file mode 100644 index 0000000000..8f298e4401 --- /dev/null +++ b/pages/api/api-keys/[id]/_delete.ts @@ -0,0 +1,14 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; + +async function deleteHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdAsString.parse(query); + await prisma.apiKey.delete({ where: { id } }); + return { message: `ApiKey with id: ${id} deleted` }; +} + +export default defaultResponder(deleteHandler); diff --git a/pages/api/api-keys/[id]/_get.ts b/pages/api/api-keys/[id]/_get.ts new file mode 100644 index 0000000000..36bf06d309 --- /dev/null +++ b/pages/api/api-keys/[id]/_get.ts @@ -0,0 +1,15 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { apiKeyPublicSchema } from "@lib/validations/api-key"; +import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; + +async function getHandler(req: NextApiRequest) { + const { prisma, query } = req; + const { id } = schemaQueryIdAsString.parse(query); + const api_key = await prisma.apiKey.findUniqueOrThrow({ where: { id } }); + return { api_key: apiKeyPublicSchema.parse(api_key) }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/api-keys/[id]/_patch.ts b/pages/api/api-keys/[id]/_patch.ts new file mode 100644 index 0000000000..8603fe69b8 --- /dev/null +++ b/pages/api/api-keys/[id]/_patch.ts @@ -0,0 +1,16 @@ +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { apiKeyEditBodySchema, apiKeyPublicSchema } from "@lib/validations/api-key"; +import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; + +async function patchHandler(req: NextApiRequest) { + const { prisma, body } = req; + const { id } = schemaQueryIdAsString.parse(req.query); + const data = apiKeyEditBodySchema.parse(body); + const api_key = await prisma.apiKey.update({ where: { id }, data }); + return { api_key: apiKeyPublicSchema.parse(api_key) }; +} + +export default defaultResponder(patchHandler); diff --git a/pages/api/api-keys/[id]/index.ts b/pages/api/api-keys/[id]/index.ts new file mode 100644 index 0000000000..a69e97191f --- /dev/null +++ b/pages/api/api-keys/[id]/index.ts @@ -0,0 +1,18 @@ +import { NextApiRequest, NextApiResponse } from "next"; + +import { defaultHandler, defaultResponder } from "@calcom/lib/server"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; + +import { authMiddleware } from "./_auth-middleware"; + +export default withMiddleware()( + defaultResponder(async (req: NextApiRequest, res: NextApiResponse) => { + await authMiddleware(req); + return defaultHandler({ + GET: import("./_get"), + PATCH: import("./_patch"), + DELETE: import("./_delete"), + })(req, res); + }) +); diff --git a/pages/api/api-keys/_get.ts b/pages/api/api-keys/_get.ts new file mode 100644 index 0000000000..930dac9234 --- /dev/null +++ b/pages/api/api-keys/_get.ts @@ -0,0 +1,40 @@ +import type { Prisma } from "@prisma/client"; +import type { NextApiRequest } from "next"; + +import { defaultResponder } from "@calcom/lib/server"; +import { Ensure } from "@calcom/types/utils"; + +import { apiKeyPublicSchema } from "@lib/validations/api-key"; +import { schemaQuerySingleOrMultipleUserIds } from "@lib/validations/shared/queryUserId"; + +type CustomNextApiRequest = NextApiRequest & { + args?: Prisma.ApiKeyFindManyArgs; +}; + +/** Admins can query other users' API keys */ +function handleAdminRequests(req: CustomNextApiRequest) { + // To match type safety with runtime + if (!hasReqArgs(req)) throw Error("Missing req.args"); + const { userId, isAdmin } = req; + if (isAdmin && req.query.userId) { + const query = schemaQuerySingleOrMultipleUserIds.parse(req.query); + const userIds = Array.isArray(query.userId) ? query.userId : [query.userId || userId]; + req.args.where = { userId: { in: userIds } }; + if (Array.isArray(query.userId)) req.args.orderBy = { userId: "asc" }; + } +} + +function hasReqArgs(req: CustomNextApiRequest): req is Ensure { + return "args" in req; +} + +async function getHandler(req: CustomNextApiRequest) { + const { userId, isAdmin, prisma } = req; + req.args = isAdmin ? {} : { where: { userId } }; + // Proof of concept: allowing mutation in exchange of composability + handleAdminRequests(req); + const data = await prisma.apiKey.findMany(req.args); + return { api_keys: data.map((v) => apiKeyPublicSchema.parse(v)) }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/api-keys/_post.ts b/pages/api/api-keys/_post.ts new file mode 100644 index 0000000000..61dd7ce9a9 --- /dev/null +++ b/pages/api/api-keys/_post.ts @@ -0,0 +1,44 @@ +import type { Prisma } from "@prisma/client"; +import type { NextApiRequest } from "next"; +import { v4 } from "uuid"; + +import { generateUniqueAPIKey } from "@calcom/features/ee/api-keys/lib/apiKeys"; +import { HttpError } from "@calcom/lib/http-error"; +import { defaultResponder } from "@calcom/lib/server"; + +import { apiKeyCreateBodySchema, apiKeyPublicSchema } from "@lib/validations/api-key"; + +async function postHandler(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + const { neverExpires, userId: bodyUserId, ...input } = apiKeyCreateBodySchema.parse(req.body); + const [hashedKey, apiKey] = generateUniqueAPIKey(); + const args: Prisma.ApiKeyCreateArgs = { + data: { + id: v4(), + userId, + ...input, + // And here we pass a null to expiresAt if never expires is true. otherwise just pass expiresAt from input + expiresAt: neverExpires ? null : input.expiresAt, + hashedKey, + }, + }; + + if (!isAdmin && bodyUserId) throw new HttpError({ statusCode: 403, message: `ADMIN required for userId` }); + + if (isAdmin && bodyUserId) { + const where: Prisma.UserWhereInput = { id: bodyUserId }; + await prisma.user.findFirstOrThrow({ where }); + args.data.userId = bodyUserId; + } + + const result = await prisma.apiKey.create(args); + return { + api_key: { + ...apiKeyPublicSchema.parse(result), + key: `${process.env.API_KEY_PREFIX ?? "cal_"}${apiKey}`, + }, + message: "API key created successfully. Save the `key` value as it won't be displayed again.", + }; +} + +export default defaultResponder(postHandler); diff --git a/pages/api/api-keys/index.ts b/pages/api/api-keys/index.ts new file mode 100644 index 0000000000..c07846423f --- /dev/null +++ b/pages/api/api-keys/index.ts @@ -0,0 +1,10 @@ +import { defaultHandler } from "@calcom/lib/server"; + +import { withMiddleware } from "@lib/helpers/withMiddleware"; + +export default withMiddleware("HTTP_GET_OR_POST")( + defaultHandler({ + GET: import("./_get"), + POST: import("./_post"), + }) +); From e15f6abc9b173fcfe0800bae3b9b904172cfff2a Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 2 Dec 2022 15:22:56 -0700 Subject: [PATCH 562/658] Fixes --- lib/helpers/customPrisma.ts | 7 +++---- pages/api/users/_get.ts | 3 +-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/helpers/customPrisma.ts b/lib/helpers/customPrisma.ts index f374048499..255ddc509a 100644 --- a/lib/helpers/customPrisma.ts +++ b/lib/helpers/customPrisma.ts @@ -2,10 +2,11 @@ import { hash } from "bcryptjs"; import cache from "memory-cache"; import { NextMiddleware } from "next-api-middleware"; -import { PRISMA_CLIENT_CACHING_TIME } from "@calcom/api/lib/constants"; import { CONSOLE_URL } from "@calcom/lib/constants"; import { prisma, customPrisma } from "@calcom/prisma"; +import { PRISMA_CLIENT_CACHING_TIME } from "../../lib/constants"; + // This replaces the prisma client for the cusotm one if the key is valid export const customPrismaClient: NextMiddleware = async (req, res, next) => { const { @@ -18,9 +19,7 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { return; } // If we have a key, we check if the deployment matching the key, has a databaseUrl value set. - const databaseUrl = await fetch( - `${process.env.NEXT_PUBLIC_CONSOLE_URL || CONSOLE_URL}/api/deployments/database?key=${key}` - ) + const databaseUrl = await fetch(`${CONSOLE_URL}/api/deployments/database?key=${key}`) .then((res) => res.json()) .then((res) => res.databaseUrl); diff --git a/pages/api/users/_get.ts b/pages/api/users/_get.ts index 6c6e140e7a..6e9b9c1c2b 100644 --- a/pages/api/users/_get.ts +++ b/pages/api/users/_get.ts @@ -1,3 +1,4 @@ +import { Prisma } from "@prisma/client"; import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; @@ -5,8 +6,6 @@ import { defaultResponder } from "@calcom/lib/server"; import { withMiddleware } from "~/lib/helpers/withMiddleware"; import { schemaUsersReadPublic } from "~/lib/validations/user"; -import { Prisma } from ".prisma/client"; - /** * @swagger * /users: From b3443cd22dfb7a041bf173f371ef54a09f6007d9 Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 2 Dec 2022 18:39:30 -0700 Subject: [PATCH 563/658] Revert fix --- lib/helpers/customPrisma.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/helpers/customPrisma.ts b/lib/helpers/customPrisma.ts index 255ddc509a..075875aaf0 100644 --- a/lib/helpers/customPrisma.ts +++ b/lib/helpers/customPrisma.ts @@ -18,8 +18,11 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { await next(); return; } + // If we have a key, we check if the deployment matching the key, has a databaseUrl value set. - const databaseUrl = await fetch(`${CONSOLE_URL}/api/deployments/database?key=${key}`) + const databaseUrl = await fetch( + `${process.env.NEXT_PUBLIC_CONSOLE_URL || CONSOLE_URL}/api/deployments/database?key=${key}` + ) .then((res) => res.json()) .then((res) => res.databaseUrl); From ae7c3e2d6ac80e5883e5354283ab0d3dbb5cc434 Mon Sep 17 00:00:00 2001 From: zomars Date: Mon, 5 Dec 2022 14:16:58 -0700 Subject: [PATCH 564/658] Removes unused cache --- lib/helpers/customPrisma.ts | 24 ++++-------------------- 1 file changed, 4 insertions(+), 20 deletions(-) diff --git a/lib/helpers/customPrisma.ts b/lib/helpers/customPrisma.ts index 075875aaf0..a09eda7a40 100644 --- a/lib/helpers/customPrisma.ts +++ b/lib/helpers/customPrisma.ts @@ -1,13 +1,11 @@ -import { hash } from "bcryptjs"; -import cache from "memory-cache"; import { NextMiddleware } from "next-api-middleware"; import { CONSOLE_URL } from "@calcom/lib/constants"; -import { prisma, customPrisma } from "@calcom/prisma"; +import { customPrisma, prisma } from "@calcom/prisma"; -import { PRISMA_CLIENT_CACHING_TIME } from "../../lib/constants"; +const LOCAL_CONSOLE_URL = process.env.NEXT_PUBLIC_CONSOLE_URL || CONSOLE_URL; -// This replaces the prisma client for the cusotm one if the key is valid +// This replaces the prisma client for the custom one if the key is valid export const customPrismaClient: NextMiddleware = async (req, res, next) => { const { query: { key }, @@ -20,9 +18,7 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { } // If we have a key, we check if the deployment matching the key, has a databaseUrl value set. - const databaseUrl = await fetch( - `${process.env.NEXT_PUBLIC_CONSOLE_URL || CONSOLE_URL}/api/deployments/database?key=${key}` - ) + const databaseUrl = await fetch(`${LOCAL_CONSOLE_URL}/api/deployments/database?key=${key}`) .then((res) => res.json()) .then((res) => res.databaseUrl); @@ -30,18 +26,6 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { res.status(400).json({ error: "no databaseUrl set up at your instance yet" }); return; } - // FIXME: Add some checks for the databaseUrl to make sure it is valid. (e.g. not a localhost) - const hashedUrl = await hash(databaseUrl, 12); - - const cachedPrisma = cache.get(hashedUrl); - /* We cache each cusotm prisma client for 24h to avoid too many requests to the database. */ - if (!cachedPrisma) { - cache.put( - hashedUrl, - customPrisma({ datasources: { db: { url: databaseUrl } } }), - PRISMA_CLIENT_CACHING_TIME // Cache the prisma client for 24 hours - ); - } req.prisma = customPrisma({ datasources: { db: { url: databaseUrl } } }); /* @note: In order to skip verifyApiKey for customPrisma requests, From 41d22c8ccb64f30a8f2a4e5ed106828e0c075027 Mon Sep 17 00:00:00 2001 From: zomars Date: Mon, 5 Dec 2022 16:09:19 -0700 Subject: [PATCH 565/658] Fixes for console --- lib/validations/shared/baseApiParams.ts | 16 +++++++--------- lib/validations/shared/queryUserId.ts | 8 +++----- pages/api/users/[userId]/index.ts | 13 +++++-------- 3 files changed, 15 insertions(+), 22 deletions(-) diff --git a/lib/validations/shared/baseApiParams.ts b/lib/validations/shared/baseApiParams.ts index b670be62d3..d0482d0d27 100644 --- a/lib/validations/shared/baseApiParams.ts +++ b/lib/validations/shared/baseApiParams.ts @@ -2,12 +2,10 @@ import { z } from "zod"; // Extracted out as utility function so can be reused // at different endpoints that require this validation. -export const baseApiParams = z - .object({ - // since we added apiKey as query param this is required by next-validations helper - // for query params to work properly and not fail. - apiKey: z.string().optional(), - // version required for supporting /v1/ redirect to query in api as *?version=1 - version: z.string().optional(), - }) - .strict(); +export const baseApiParams = z.object({ + // since we added apiKey as query param this is required by next-validations helper + // for query params to work properly and not fail. + apiKey: z.string().optional(), + // version required for supporting /v1/ redirect to query in api as *?version=1 + version: z.string().optional(), +}); diff --git a/lib/validations/shared/queryUserId.ts b/lib/validations/shared/queryUserId.ts index 88e2c7e8de..f187d0f134 100644 --- a/lib/validations/shared/queryUserId.ts +++ b/lib/validations/shared/queryUserId.ts @@ -7,11 +7,9 @@ import { baseApiParams } from "./baseApiParams"; // Extracted out as utility function so can be reused // at different endpoints that require this validation. -export const schemaQueryUserId = baseApiParams - .extend({ - userId: stringOrNumber, - }) - .strict(); +export const schemaQueryUserId = baseApiParams.extend({ + userId: stringOrNumber, +}); export const schemaQuerySingleOrMultipleUserIds = z.object({ userId: z.union([stringOrNumber, z.array(stringOrNumber)]), diff --git a/pages/api/users/[userId]/index.ts b/pages/api/users/[userId]/index.ts index b6cb937af3..ef0f429b1e 100644 --- a/pages/api/users/[userId]/index.ts +++ b/pages/api/users/[userId]/index.ts @@ -1,14 +1,11 @@ import { defaultHandler } from "@calcom/lib/server"; import { withMiddleware } from "~/lib/helpers/withMiddleware"; -import { withValidQueryUserId } from "~/lib/validations/shared/queryUserId"; export default withMiddleware()( - withValidQueryUserId( - defaultHandler({ - GET: import("./_get"), - PATCH: import("./_patch"), - DELETE: import("./_delete"), - }) - ) + defaultHandler({ + GET: import("./_get"), + PATCH: import("./_patch"), + DELETE: import("./_delete"), + }) ); From 8b74f463f454cf84e0f39bf78ff7d0f245014caa Mon Sep 17 00:00:00 2001 From: zomars Date: Thu, 8 Dec 2022 15:00:06 -0700 Subject: [PATCH 566/658] Needed for console --- lib/validations/user.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/validations/user.ts b/lib/validations/user.ts index 8e0689ff3d..25810f27c6 100644 --- a/lib/validations/user.ts +++ b/lib/validations/user.ts @@ -80,6 +80,7 @@ export const schemaUserBaseBodyParams = User.pick({ darkBrandColor: true, allowDynamicBooking: true, away: true, + role: true, // @note: disallowing avatar changes via API for now. We can add it later if needed. User should upload image via UI. // avatar: true, }).partial(); From f3c5f9bc0c1b68a3dcd24d1428abd3f4cbfd7efe Mon Sep 17 00:00:00 2001 From: zomars Date: Thu, 8 Dec 2022 16:28:28 -0700 Subject: [PATCH 567/658] Import fixes --- pages/api/api-keys/[id]/_auth-middleware.ts | 2 +- pages/api/api-keys/[id]/_delete.ts | 2 +- pages/api/api-keys/[id]/_get.ts | 4 ++-- pages/api/api-keys/[id]/_patch.ts | 4 ++-- pages/api/api-keys/[id]/index.ts | 2 +- pages/api/api-keys/_get.ts | 4 ++-- pages/api/api-keys/_post.ts | 2 +- pages/api/api-keys/index.ts | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/pages/api/api-keys/[id]/_auth-middleware.ts b/pages/api/api-keys/[id]/_auth-middleware.ts index 3137ccad25..fb1c917485 100644 --- a/pages/api/api-keys/[id]/_auth-middleware.ts +++ b/pages/api/api-keys/[id]/_auth-middleware.ts @@ -2,7 +2,7 @@ import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; -import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; +import { schemaQueryIdAsString } from "~/lib/validations/shared/queryIdString"; export async function authMiddleware(req: NextApiRequest) { const { userId, isAdmin, prisma } = req; diff --git a/pages/api/api-keys/[id]/_delete.ts b/pages/api/api-keys/[id]/_delete.ts index 8f298e4401..099c6ba7b1 100644 --- a/pages/api/api-keys/[id]/_delete.ts +++ b/pages/api/api-keys/[id]/_delete.ts @@ -2,7 +2,7 @@ import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; -import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; +import { schemaQueryIdAsString } from "~/lib/validations/shared/queryIdString"; async function deleteHandler(req: NextApiRequest) { const { prisma, query } = req; diff --git a/pages/api/api-keys/[id]/_get.ts b/pages/api/api-keys/[id]/_get.ts index 36bf06d309..99b1188507 100644 --- a/pages/api/api-keys/[id]/_get.ts +++ b/pages/api/api-keys/[id]/_get.ts @@ -2,8 +2,8 @@ import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; -import { apiKeyPublicSchema } from "@lib/validations/api-key"; -import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; +import { apiKeyPublicSchema } from "~/lib/validations/api-key"; +import { schemaQueryIdAsString } from "~/lib/validations/shared/queryIdString"; async function getHandler(req: NextApiRequest) { const { prisma, query } = req; diff --git a/pages/api/api-keys/[id]/_patch.ts b/pages/api/api-keys/[id]/_patch.ts index 8603fe69b8..673a081f54 100644 --- a/pages/api/api-keys/[id]/_patch.ts +++ b/pages/api/api-keys/[id]/_patch.ts @@ -2,8 +2,8 @@ import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; -import { apiKeyEditBodySchema, apiKeyPublicSchema } from "@lib/validations/api-key"; -import { schemaQueryIdAsString } from "@lib/validations/shared/queryIdString"; +import { apiKeyEditBodySchema, apiKeyPublicSchema } from "~/lib/validations/api-key"; +import { schemaQueryIdAsString } from "~/lib/validations/shared/queryIdString"; async function patchHandler(req: NextApiRequest) { const { prisma, body } = req; diff --git a/pages/api/api-keys/[id]/index.ts b/pages/api/api-keys/[id]/index.ts index a69e97191f..4b27553002 100644 --- a/pages/api/api-keys/[id]/index.ts +++ b/pages/api/api-keys/[id]/index.ts @@ -2,7 +2,7 @@ import { NextApiRequest, NextApiResponse } from "next"; import { defaultHandler, defaultResponder } from "@calcom/lib/server"; -import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { withMiddleware } from "~/lib/helpers/withMiddleware"; import { authMiddleware } from "./_auth-middleware"; diff --git a/pages/api/api-keys/_get.ts b/pages/api/api-keys/_get.ts index 930dac9234..3d374b51ec 100644 --- a/pages/api/api-keys/_get.ts +++ b/pages/api/api-keys/_get.ts @@ -4,8 +4,8 @@ import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; import { Ensure } from "@calcom/types/utils"; -import { apiKeyPublicSchema } from "@lib/validations/api-key"; -import { schemaQuerySingleOrMultipleUserIds } from "@lib/validations/shared/queryUserId"; +import { apiKeyPublicSchema } from "~/lib/validations/api-key"; +import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/queryUserId"; type CustomNextApiRequest = NextApiRequest & { args?: Prisma.ApiKeyFindManyArgs; diff --git a/pages/api/api-keys/_post.ts b/pages/api/api-keys/_post.ts index 61dd7ce9a9..8329ac0df5 100644 --- a/pages/api/api-keys/_post.ts +++ b/pages/api/api-keys/_post.ts @@ -6,7 +6,7 @@ import { generateUniqueAPIKey } from "@calcom/features/ee/api-keys/lib/apiKeys"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import { apiKeyCreateBodySchema, apiKeyPublicSchema } from "@lib/validations/api-key"; +import { apiKeyCreateBodySchema, apiKeyPublicSchema } from "~/lib/validations/api-key"; async function postHandler(req: NextApiRequest) { const { userId, isAdmin, prisma } = req; diff --git a/pages/api/api-keys/index.ts b/pages/api/api-keys/index.ts index c07846423f..0737e056fb 100644 --- a/pages/api/api-keys/index.ts +++ b/pages/api/api-keys/index.ts @@ -1,6 +1,6 @@ import { defaultHandler } from "@calcom/lib/server"; -import { withMiddleware } from "@lib/helpers/withMiddleware"; +import { withMiddleware } from "~/lib/helpers/withMiddleware"; export default withMiddleware("HTTP_GET_OR_POST")( defaultHandler({ From c129586336b287d7b93c516435d905337951d2d2 Mon Sep 17 00:00:00 2001 From: zomars Date: Thu, 8 Dec 2022 16:34:09 -0700 Subject: [PATCH 568/658] Linting --- pages/api/memberships/[id]/_delete.ts | 1 - pages/api/selected-calendars/[id]/_patch.ts | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/pages/api/memberships/[id]/_delete.ts b/pages/api/memberships/[id]/_delete.ts index cac08b6edb..160db80653 100644 --- a/pages/api/memberships/[id]/_delete.ts +++ b/pages/api/memberships/[id]/_delete.ts @@ -3,7 +3,6 @@ import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; import { membershipIdSchema } from "~/lib/validations/membership"; -import { schemaQueryIdAsString } from "~/lib/validations/shared/queryIdString"; /** * @swagger diff --git a/pages/api/selected-calendars/[id]/_patch.ts b/pages/api/selected-calendars/[id]/_patch.ts index 6d77d92875..81b09a95df 100644 --- a/pages/api/selected-calendars/[id]/_patch.ts +++ b/pages/api/selected-calendars/[id]/_patch.ts @@ -46,7 +46,7 @@ import { * description: Authorization information is missing or invalid. */ export async function patchHandler(req: NextApiRequest) { - const { prisma, query, userId, isAdmin } = req; + const { prisma, query, isAdmin } = req; const userId_integration_externalId = selectedCalendarIdSchema.parse(query); const { userId: bodyUserId, ...data } = schemaSelectedCalendarUpdateBodyParams.parse(req.body); const args: Prisma.SelectedCalendarUpdateArgs = { where: { userId_integration_externalId }, data }; From 5d892df019b808758fa723f9a014fb6e78ea9d51 Mon Sep 17 00:00:00 2001 From: Joe Au-Yeung <65426560+joeauyeung@users.noreply.github.com> Date: Thu, 15 Dec 2022 17:36:09 -0500 Subject: [PATCH 569/658] Allow seatsPerTimeSlot and seatsShowAttendees in event type calls (#216) This PR allows `seatsPerTimeSlot` and `seatsShowAttendees` in event type POST and PATCH calls --- lib/validations/event-type.ts | 6 ++++++ pages/api/event-types/_post.ts | 1 + 2 files changed, 7 insertions(+) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index a2177df111..5836945abb 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -56,6 +56,8 @@ const schemaEventTypeCreateParams = z length: z.number().int(), metadata: z.any().optional(), recurringEvent: recurringEventInputSchema.optional(), + seatsPerTimeSlot: z.number().optional(), + seatsShowAttendees: z.boolean().optional(), }) .strict(); @@ -68,6 +70,8 @@ const schemaEventTypeEditParams = z title: z.string().optional(), slug: z.string().optional(), length: z.number().int().optional(), + seatsPerTimeSlot: z.number().optional(), + seatsShowAttendees: z.boolean().optional(), }) .strict(); @@ -103,6 +107,8 @@ export const schemaEventTypeReadPublic = EventType.pick({ description: true, locations: true, metadata: true, + seatsPerTimeSlot: true, + seatsShowAttendees: true, }).merge( z.object({ locations: z diff --git a/pages/api/event-types/_post.ts b/pages/api/event-types/_post.ts index a0bc450c11..11ce826e6e 100644 --- a/pages/api/event-types/_post.ts +++ b/pages/api/event-types/_post.ts @@ -37,6 +37,7 @@ import { schemaEventTypeCreateBodyParams, schemaEventTypeReadPublic } from "~/li * slug: * type: string * example: my-event + * * tags: * - event-types * externalDocs: From 12f19ff7c03a5284d2740e01d5291b713f120a21 Mon Sep 17 00:00:00 2001 From: zomars Date: Thu, 15 Dec 2022 15:11:54 -0700 Subject: [PATCH 570/658] Upgrades zod --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 68527e67ab..e6e00b8e63 100644 --- a/package.json +++ b/package.json @@ -25,16 +25,16 @@ "node-mocks-http": "^1.11.0" }, "dependencies": { - "@calcom/prisma": "*", - "@calcom/trpc": "*", - "@calcom/embed-core": "*", "@calcom/app-store": "*", "@calcom/core": "*", "@calcom/dayjs": "*", "@calcom/emails": "*", + "@calcom/embed-core": "*", "@calcom/embed-snippet": "*", "@calcom/features": "*", "@calcom/lib": "*", + "@calcom/prisma": "*", + "@calcom/trpc": "*", "@sentry/nextjs": "^7.20.0", "bcryptjs": "^2.4.3", "memory-cache": "^0.2.0", @@ -48,6 +48,6 @@ "typescript": "^4.7.4", "tzdata": "^1.0.30", "uuid": "^8.3.2", - "zod": "^3.19.1" + "zod": "^3.20.2" } } From 161ebacfefaca22d9de14933291db1231633375e Mon Sep 17 00:00:00 2001 From: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com> Date: Tue, 20 Dec 2022 18:45:24 +0100 Subject: [PATCH 571/658] Don't allow team admins to give owner permissions (#221) Throw an error if a user of a team with ADMIN permission tries to change permission to OWNER (Bug#3) Co-authored-by: CarinaWolli --- pages/api/memberships/[id]/_patch.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pages/api/memberships/[id]/_patch.ts b/pages/api/memberships/[id]/_patch.ts index 00670a4ee0..4b8996c11c 100644 --- a/pages/api/memberships/[id]/_patch.ts +++ b/pages/api/memberships/[id]/_patch.ts @@ -58,13 +58,20 @@ async function checkPermissions(req: NextApiRequest) { if (isAdmin) return; // Only the invited user can accept the invite if ("accepted" in data && queryUserId !== userId) - throw new HttpError({ statusCode: 403, message: "Only the invited user can accept the invite" }); + throw new HttpError({ + statusCode: 403, + message: "Only the invited user can accept the invite", + }); // Only team OWNERS and ADMINS can modify `role` if ("role" in data) { const membership = await prisma.membership.findFirst({ where: { userId, teamId, role: { in: ["ADMIN", "OWNER"] } }, }); - if (!membership) throw new HttpError({ statusCode: 403, message: "Forbidden" }); + if ( + !membership || + (membership.role !== "OWNER" && req.body.role === "OWNER") + ) + throw new HttpError({ statusCode: 403, message: "Forbidden" }); } } From c3e08525418d29ec2a0650e75fb56297335f9de0 Mon Sep 17 00:00:00 2001 From: Carina Wollendorfer <30310907+CarinaWolli@users.noreply.github.com> Date: Tue, 20 Dec 2022 18:50:46 +0100 Subject: [PATCH 572/658] Only allow team admin and owner to create team event types (#220) Currently, anybody can create an event type for any team. With this PR we only allow team ADMIN and OWNER to create event types for the team. Co-authored-by: CarinaWolli --- pages/api/event-types/_post.ts | 40 +++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/pages/api/event-types/_post.ts b/pages/api/event-types/_post.ts index 11ce826e6e..417bbfdf7f 100644 --- a/pages/api/event-types/_post.ts +++ b/pages/api/event-types/_post.ts @@ -4,7 +4,10 @@ import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import { schemaEventTypeCreateBodyParams, schemaEventTypeReadPublic } from "~/lib/validations/event-type"; +import { + schemaEventTypeCreateBodyParams, + schemaEventTypeReadPublic, +} from "~/lib/validations/event-type"; /** * @swagger @@ -53,11 +56,34 @@ import { schemaEventTypeCreateBodyParams, schemaEventTypeReadPublic } from "~/li async function postHandler(req: NextApiRequest) { const { userId, isAdmin, prisma } = req; const body = schemaEventTypeCreateBodyParams.parse(req.body); - let args: Prisma.EventTypeCreateArgs = { data: { ...body, userId, users: { connect: { id: userId } } } }; + let args: Prisma.EventTypeCreateArgs = { + data: { ...body, userId, users: { connect: { id: userId } } }, + }; await checkPermissions(req); - if (isAdmin && body.userId) args = { data: { ...body, users: { connect: { id: body.userId } } } }; + if (isAdmin && body.userId) + args = { data: { ...body, users: { connect: { id: body.userId } } } }; + + if (body.teamId) { + const hasMembership = await prisma.membership.findFirst({ + where: { + userId, + teamId: body.teamId, + accepted: true, + }, + }); + + if ( + !hasMembership?.role || + !["ADMIN", "OWNER"].includes(hasMembership.role) + ) { + throw new HttpError({ + statusCode: 401, + message: "No permission to create an event-type for this team`", + }); + } + } const data = await prisma.eventType.create(args); @@ -72,9 +98,13 @@ async function checkPermissions(req: NextApiRequest) { const body = schemaEventTypeCreateBodyParams.parse(req.body); /* Non-admin users can only create event types for themselves */ if (!isAdmin && body.userId) - throw new HttpError({ statusCode: 401, message: "ADMIN required for `userId`" }); + throw new HttpError({ + statusCode: 401, + message: "ADMIN required for `userId`", + }); /* Admin users are required to pass in a userId */ - if (isAdmin && !body.userId) throw new HttpError({ statusCode: 400, message: "`userId` required" }); + if (isAdmin && !body.userId) + throw new HttpError({ statusCode: 400, message: "`userId` required" }); } export default defaultResponder(postHandler); From 604d937661ed8f8fd50cc645bf7d129b635333e8 Mon Sep 17 00:00:00 2001 From: zomars Date: Tue, 20 Dec 2022 11:58:30 -0700 Subject: [PATCH 573/658] Linting --- pages/api/event-types/_post.ts | 16 ++++------------ pages/api/memberships/[id]/_patch.ts | 5 +---- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/pages/api/event-types/_post.ts b/pages/api/event-types/_post.ts index 417bbfdf7f..1868a35529 100644 --- a/pages/api/event-types/_post.ts +++ b/pages/api/event-types/_post.ts @@ -4,10 +4,7 @@ import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import { - schemaEventTypeCreateBodyParams, - schemaEventTypeReadPublic, -} from "~/lib/validations/event-type"; +import { schemaEventTypeCreateBodyParams, schemaEventTypeReadPublic } from "~/lib/validations/event-type"; /** * @swagger @@ -62,8 +59,7 @@ async function postHandler(req: NextApiRequest) { await checkPermissions(req); - if (isAdmin && body.userId) - args = { data: { ...body, users: { connect: { id: body.userId } } } }; + if (isAdmin && body.userId) args = { data: { ...body, users: { connect: { id: body.userId } } } }; if (body.teamId) { const hasMembership = await prisma.membership.findFirst({ @@ -74,10 +70,7 @@ async function postHandler(req: NextApiRequest) { }, }); - if ( - !hasMembership?.role || - !["ADMIN", "OWNER"].includes(hasMembership.role) - ) { + if (!hasMembership?.role || !["ADMIN", "OWNER"].includes(hasMembership.role)) { throw new HttpError({ statusCode: 401, message: "No permission to create an event-type for this team`", @@ -103,8 +96,7 @@ async function checkPermissions(req: NextApiRequest) { message: "ADMIN required for `userId`", }); /* Admin users are required to pass in a userId */ - if (isAdmin && !body.userId) - throw new HttpError({ statusCode: 400, message: "`userId` required" }); + if (isAdmin && !body.userId) throw new HttpError({ statusCode: 400, message: "`userId` required" }); } export default defaultResponder(postHandler); diff --git a/pages/api/memberships/[id]/_patch.ts b/pages/api/memberships/[id]/_patch.ts index 4b8996c11c..98115eff39 100644 --- a/pages/api/memberships/[id]/_patch.ts +++ b/pages/api/memberships/[id]/_patch.ts @@ -67,10 +67,7 @@ async function checkPermissions(req: NextApiRequest) { const membership = await prisma.membership.findFirst({ where: { userId, teamId, role: { in: ["ADMIN", "OWNER"] } }, }); - if ( - !membership || - (membership.role !== "OWNER" && req.body.role === "OWNER") - ) + if (!membership || (membership.role !== "OWNER" && req.body.role === "OWNER")) throw new HttpError({ statusCode: 403, message: "Forbidden" }); } } From 9c23a8e5ab8ceb1af82beaa850609ed7fdc6a86e Mon Sep 17 00:00:00 2001 From: Hariom Balhara Date: Thu, 5 Jan 2023 03:47:47 +0530 Subject: [PATCH 574/658] Security Fixes (#224) Fixes - 2,3,4 security vulnerabilities reported in this message. https://calendso.slack.com/archives/C03127U5S5Q/p1671922033089329 More Fixes - Dont't allow a user to add a random attendee to a booking not owned by him - Don't allow a user to add a random cal user as an organizer of the booking. - Membership deletion should be as per the Privileges of Owner,Admin,Member --- pages/api/attendees/[id]/_patch.ts | 15 +++++ pages/api/bookings/[id]/_patch.ts | 14 +++++ pages/api/event-types/[id]/_patch.ts | 14 ++++- pages/api/event-types/_post.ts | 19 +----- .../_utils/checkTeamEventEditPermission.ts | 29 +++++++++ pages/api/memberships/[id]/_delete.ts | 60 +++++++++++++++++++ pages/api/schedules/[id]/_patch.ts | 12 ++++ 7 files changed, 144 insertions(+), 19 deletions(-) create mode 100644 pages/api/event-types/_utils/checkTeamEventEditPermission.ts diff --git a/pages/api/attendees/[id]/_patch.ts b/pages/api/attendees/[id]/_patch.ts index 46db6f285f..73ef195ff8 100644 --- a/pages/api/attendees/[id]/_patch.ts +++ b/pages/api/attendees/[id]/_patch.ts @@ -1,5 +1,7 @@ import type { NextApiRequest } from "next"; +import { z } from "zod"; +import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; import { schemaAttendeeEditBodyParams, schemaAttendeeReadPublic } from "~/lib/validations/attendee"; @@ -50,8 +52,21 @@ export async function patchHandler(req: NextApiRequest) { const { prisma, query, body } = req; const { id } = schemaQueryIdParseInt.parse(query); const data = schemaAttendeeEditBodyParams.parse(body); + await checkPermissions(req, data); const attendee = await prisma.attendee.update({ where: { id }, data }); return { attendee: schemaAttendeeReadPublic.parse(attendee) }; } +async function checkPermissions(req: NextApiRequest, body: z.infer) { + const { isAdmin, prisma } = req; + if (isAdmin) return; + const { userId } = req; + const { bookingId } = body; + if (bookingId) { + // Ensure that the booking the attendee is being added to belongs to the user + const booking = await prisma.booking.findFirst({ where: { id: bookingId, userId } }); + if (!booking) throw new HttpError({ statusCode: 403, message: "You don't have access to the booking" }); + } +} + export default defaultResponder(patchHandler); diff --git a/pages/api/bookings/[id]/_patch.ts b/pages/api/bookings/[id]/_patch.ts index a1378e16b4..fc20c14709 100644 --- a/pages/api/bookings/[id]/_patch.ts +++ b/pages/api/bookings/[id]/_patch.ts @@ -1,5 +1,7 @@ import type { NextApiRequest } from "next"; +import { z } from "zod"; +import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; import { schemaBookingEditBodyParams, schemaBookingReadPublic } from "~/lib/validations/booking"; @@ -49,8 +51,20 @@ export async function patchHandler(req: NextApiRequest) { const { prisma, query, body } = req; const { id } = schemaQueryIdParseInt.parse(query); const data = schemaBookingEditBodyParams.parse(body); + await checkPermissions(req, data); const booking = await prisma.booking.update({ where: { id }, data }); return { booking: schemaBookingReadPublic.parse(booking) }; } +async function checkPermissions(req: NextApiRequest, body: z.infer) { + const { isAdmin } = req; + if (body.userId && !isAdmin) { + // Organizer has to be a cal user and we can't allow a booking to be transfered to some other cal user's name + throw new HttpError({ + statusCode: 403, + message: "Only admin can change the organizer of a booking", + }); + } +} + export default defaultResponder(patchHandler); diff --git a/pages/api/event-types/[id]/_patch.ts b/pages/api/event-types/[id]/_patch.ts index 2ce0886029..a1c0bef77e 100644 --- a/pages/api/event-types/[id]/_patch.ts +++ b/pages/api/event-types/[id]/_patch.ts @@ -1,11 +1,18 @@ import type { NextApiRequest } from "next"; +import { z } from "zod"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import { schemaEventTypeEditBodyParams, schemaEventTypeReadPublic } from "~/lib/validations/event-type"; +import { + schemaEventTypeEditBodyParams, + schemaEventTypeBaseBodyParams, + schemaEventTypeReadPublic, +} from "~/lib/validations/event-type"; import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt"; +import checkTeamEventEditPermission from "../_utils/checkTeamEventEditPermission"; + /** * @swagger * /event-types/{id}: @@ -37,18 +44,19 @@ export async function patchHandler(req: NextApiRequest) { const { prisma, query, body } = req; const { id } = schemaQueryIdParseInt.parse(query); const data = schemaEventTypeEditBodyParams.parse(body); - await checkPermissions(req); + await checkPermissions(req, body); const event_type = await prisma.eventType.update({ where: { id }, data }); return { event_type: schemaEventTypeReadPublic.parse(event_type) }; } -async function checkPermissions(req: NextApiRequest) { +async function checkPermissions(req: NextApiRequest, body: z.infer) { const { userId, prisma, isAdmin } = req; const { id } = schemaQueryIdParseInt.parse(req.query); if (isAdmin) return; /** Only event type owners can modify it */ const eventType = await prisma.eventType.findFirst({ where: { id, userId } }); if (!eventType) throw new HttpError({ statusCode: 403, message: "Forbidden" }); + await checkTeamEventEditPermission(req, body); } export default defaultResponder(patchHandler); diff --git a/pages/api/event-types/_post.ts b/pages/api/event-types/_post.ts index 1868a35529..faefb4cc74 100644 --- a/pages/api/event-types/_post.ts +++ b/pages/api/event-types/_post.ts @@ -6,6 +6,8 @@ import { defaultResponder } from "@calcom/lib/server"; import { schemaEventTypeCreateBodyParams, schemaEventTypeReadPublic } from "~/lib/validations/event-type"; +import checkTeamEventEditPermission from "./_utils/checkTeamEventEditPermission"; + /** * @swagger * /event-types: @@ -61,22 +63,7 @@ async function postHandler(req: NextApiRequest) { if (isAdmin && body.userId) args = { data: { ...body, users: { connect: { id: body.userId } } } }; - if (body.teamId) { - const hasMembership = await prisma.membership.findFirst({ - where: { - userId, - teamId: body.teamId, - accepted: true, - }, - }); - - if (!hasMembership?.role || !["ADMIN", "OWNER"].includes(hasMembership.role)) { - throw new HttpError({ - statusCode: 401, - message: "No permission to create an event-type for this team`", - }); - } - } + await checkTeamEventEditPermission(req, body); const data = await prisma.eventType.create(args); diff --git a/pages/api/event-types/_utils/checkTeamEventEditPermission.ts b/pages/api/event-types/_utils/checkTeamEventEditPermission.ts new file mode 100644 index 0000000000..b2392ba7b4 --- /dev/null +++ b/pages/api/event-types/_utils/checkTeamEventEditPermission.ts @@ -0,0 +1,29 @@ +import type { NextApiRequest } from "next"; +import { z } from "zod"; + +import { HttpError } from "@calcom/lib/http-error"; + +import { schemaEventTypeBaseBodyParams } from "~/lib/validations/event-type"; + +export default async function checkTeamEventEditPermission( + req: NextApiRequest, + body: Pick, "teamId"> +) { + const { prisma, userId } = req; + if (body.teamId) { + const membership = await prisma.membership.findFirst({ + where: { + userId, + teamId: body.teamId, + accepted: true, + }, + }); + + if (!membership?.role || !["ADMIN", "OWNER"].includes(membership.role)) { + throw new HttpError({ + statusCode: 401, + message: "No permission to operate on event-type for this team", + }); + } + } +} diff --git a/pages/api/memberships/[id]/_delete.ts b/pages/api/memberships/[id]/_delete.ts index 160db80653..06acefb3bb 100644 --- a/pages/api/memberships/[id]/_delete.ts +++ b/pages/api/memberships/[id]/_delete.ts @@ -1,5 +1,6 @@ import type { NextApiRequest } from "next"; +import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; import { membershipIdSchema } from "~/lib/validations/membership"; @@ -35,8 +36,67 @@ import { membershipIdSchema } from "~/lib/validations/membership"; export async function deleteHandler(req: NextApiRequest) { const { prisma, query } = req; const userId_teamId = membershipIdSchema.parse(query); + await checkPermissions(req); await prisma.membership.delete({ where: { userId_teamId } }); return { message: `Membership with id: ${query.id} deleted successfully` }; } +async function checkPermissions(req: NextApiRequest) { + const { prisma, isAdmin, userId, query } = req; + const userId_teamId = membershipIdSchema.parse(query); + // Admin User can do anything including deletion of Admin Team Member in any team + if (isAdmin) { + return; + } + + // Owner can delete Admin and Member + // Admin Team Member can delete Member + // Member can't delete anyone + const PRIVILEGE_ORDER = ["OWNER", "ADMIN", "MEMBER"]; + + const memberShipToBeDeleted = await prisma.membership.findUnique({ + where: { userId_teamId }, + }); + + if (!memberShipToBeDeleted) { + throw new HttpError({ statusCode: 404, message: "Membership not found" }); + } + + // If a user is deleting their own membership, then they can do it + if (userId === memberShipToBeDeleted.userId) { + return; + } + + const currentUserMembership = await prisma.membership.findUnique({ + where: { + userId_teamId: { + userId, + teamId: memberShipToBeDeleted.teamId, + }, + }, + }); + + if (!currentUserMembership) { + // Current User isn't a member of the team + throw new HttpError({ statusCode: 403, message: "You are not a member of the team" }); + } + + if ( + PRIVILEGE_ORDER.indexOf(memberShipToBeDeleted.role) === -1 || + PRIVILEGE_ORDER.indexOf(currentUserMembership.role) === -1 + ) { + throw new HttpError({ statusCode: 400, message: "Invalid role" }); + } + + // If Role that is being deleted comes before the current User's Role, or it's the same ROLE, throw error + if ( + PRIVILEGE_ORDER.indexOf(memberShipToBeDeleted.role) <= PRIVILEGE_ORDER.indexOf(currentUserMembership.role) + ) { + throw new HttpError({ + statusCode: 403, + message: "You don't have the appropriate role to delete this membership", + }); + } +} + export default defaultResponder(deleteHandler); diff --git a/pages/api/schedules/[id]/_patch.ts b/pages/api/schedules/[id]/_patch.ts index 4846bd173f..e8a27ee105 100644 --- a/pages/api/schedules/[id]/_patch.ts +++ b/pages/api/schedules/[id]/_patch.ts @@ -1,5 +1,7 @@ import type { NextApiRequest } from "next"; +import { z } from "zod"; +import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; import { schemaSchedulePublic, schemaSingleScheduleBodyParams } from "~/lib/validations/schedule"; @@ -32,8 +34,18 @@ export async function patchHandler(req: NextApiRequest) { const { prisma, query } = req; const { id } = schemaQueryIdParseInt.parse(query); const data = schemaSingleScheduleBodyParams.parse(req.body); + await checkPermissions(req, data); const result = await prisma.schedule.update({ where: { id }, data, include: { availability: true } }); return { schedule: schemaSchedulePublic.parse(result) }; } +async function checkPermissions(req: NextApiRequest, body: z.infer) { + const { isAdmin } = req; + if (isAdmin) return; + if (body.userId) { + throw new HttpError({ statusCode: 403, message: "Non admin cannot change the owner of a schedule" }); + } + //_auth-middleware takes care of verifying the ownership of schedule. +} + export default defaultResponder(patchHandler); From 2808b798dfa64436eebd83b3705c7cafe4596446 Mon Sep 17 00:00:00 2001 From: zomars Date: Thu, 5 Jan 2023 18:02:06 -0700 Subject: [PATCH 575/658] Upgrades next --- package.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index e6e00b8e63..c534b11389 100644 --- a/package.json +++ b/package.json @@ -39,11 +39,11 @@ "bcryptjs": "^2.4.3", "memory-cache": "^0.2.0", "modify-response-middleware": "^1.1.0", - "next": "^12.3.1", + "next": "^13.1.1", "next-api-middleware": "^1.0.1", - "next-axiom": "^0.10.0", + "next-axiom": "^0.16.0", "next-swagger-doc": "^0.3.4", - "next-transpile-modules": "^9.0.0", + "next-transpile-modules": "^10.0.0", "next-validations": "^0.2.0", "typescript": "^4.7.4", "tzdata": "^1.0.30", From 7aebdb8c966f472383cf55e8da31e9655102e775 Mon Sep 17 00:00:00 2001 From: Udit Takkar <53316345+Udit-takkar@users.noreply.github.com> Date: Sat, 7 Jan 2023 21:26:13 +0530 Subject: [PATCH 576/658] fix: use schema from zod-utils (#225) fixes:- https://secure.helpscout.net/conversation/2117165409/2395 How to test? Create an event type with custom inputs GET Request on /event-types end point After:- Screenshot 2023-01-07 at 4 57 39 PM Signed-off-by: Udit Takkar --- lib/validations/event-type.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 5836945abb..579793a446 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -1,6 +1,7 @@ import { z } from "zod"; -import { _EventTypeCustomInputModel, _EventTypeModel as EventType } from "@calcom/prisma/zod"; +import { _EventTypeModel as EventType } from "@calcom/prisma/zod"; +import { customInputSchema } from "@calcom/prisma/zod-utils"; import { Frequency } from "~/lib/types"; @@ -122,6 +123,6 @@ export const schemaEventTypeReadPublic = EventType.pick({ ) .nullable(), metadata: jsonSchema.nullable(), - customInputs: _EventTypeCustomInputModel.array().optional(), + customInputs: customInputSchema.array().optional(), }) ); From 6cec8620cb8f6a8a797088566da7ec0e3e0001be Mon Sep 17 00:00:00 2001 From: Leo Giovanetti Date: Wed, 18 Jan 2023 16:49:31 -0300 Subject: [PATCH 577/658] Pagination issue fixed, total added (#227) Fixes #217. --- lib/helpers/withPagination.ts | 2 +- pages/api/users/_get.ts | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/helpers/withPagination.ts b/lib/helpers/withPagination.ts index 32ff4a7289..8a78b03c2b 100644 --- a/lib/helpers/withPagination.ts +++ b/lib/helpers/withPagination.ts @@ -16,7 +16,7 @@ const withPage = z.object({ export const withPagination: NextMiddleware = async (req, _, next) => { const { page, take } = withPage.parse(req.query); - const skip = page * take || 0; + const skip = (page - 1) * take; req.pagination = { take, skip, diff --git a/pages/api/users/_get.ts b/pages/api/users/_get.ts index 6e9b9c1c2b..3ccfdb6ca0 100644 --- a/pages/api/users/_get.ts +++ b/pages/api/users/_get.ts @@ -39,9 +39,12 @@ async function getHandler(req: NextApiRequest) { const where: Prisma.UserWhereInput = {}; // If user is not ADMIN, return only his data. if (!isAdmin) where.id = userId; - const data = await prisma.user.findMany({ where, take, skip }); + const [total, data] = await prisma.$transaction([ + prisma.user.count(), + prisma.user.findMany({ where, take, skip }), + ]); const users = schemaUsersReadPublic.parse(data); - return { users }; + return { users, total }; } export default withMiddleware("pagination")(defaultResponder(getHandler)); From a4a666042152c2de6c980ab199cc84971444cd84 Mon Sep 17 00:00:00 2001 From: zomars Date: Mon, 23 Jan 2023 17:24:47 -0700 Subject: [PATCH 578/658] Fix deploy script --- scripts/vercel-deploy.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/vercel-deploy.sh b/scripts/vercel-deploy.sh index 0de5b672b4..e9ef0538b3 100755 --- a/scripts/vercel-deploy.sh +++ b/scripts/vercel-deploy.sh @@ -35,6 +35,9 @@ git clone $BRANCH_TO_CLONE https://$GITHUB_ACCESS_TOKEN@github.com/calcom/cal.co echo "Cloned" +# Ensure the submodule directory exists +mkdir -p $SUBMODULE_PATH + # set up an empty temporary work directory rm -rf tmp || true # remove the tmp folder if exists mkdir tmp # create the tmp folder From 9af022b663a3934be502c64a80eeacb1a094d7cd Mon Sep 17 00:00:00 2001 From: zomars Date: Wed, 25 Jan 2023 14:14:43 -0700 Subject: [PATCH 579/658] Fix for multi-tenant users --- lib/helpers/customPrisma.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/helpers/customPrisma.ts b/lib/helpers/customPrisma.ts index a09eda7a40..466d6ee8c0 100644 --- a/lib/helpers/customPrisma.ts +++ b/lib/helpers/customPrisma.ts @@ -34,6 +34,7 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { */ req.isAdmin = true; req.isCustomPrisma = true; - + // We don't need the key from here and on. Prevents unrecognized key errors. + delete req.query.key; await next(); }; From 944a50bd29b417e4653e70fa75f7fdd416356b46 Mon Sep 17 00:00:00 2001 From: zomars Date: Wed, 25 Jan 2023 18:37:51 -0700 Subject: [PATCH 580/658] Upgrades typescript --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c534b11389..6c1d3c9eb6 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "next-swagger-doc": "^0.3.4", "next-transpile-modules": "^10.0.0", "next-validations": "^0.2.0", - "typescript": "^4.7.4", + "typescript": "^4.9.4", "tzdata": "^1.0.30", "uuid": "^8.3.2", "zod": "^3.20.2" From 0af9e113606e9f32069820547c9bc365fbaf8811 Mon Sep 17 00:00:00 2001 From: zomars Date: Thu, 26 Jan 2023 14:28:41 -0700 Subject: [PATCH 581/658] Revert "Upgrades typescript" This reverts commit 944a50bd29b417e4653e70fa75f7fdd416356b46. --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6c1d3c9eb6..c534b11389 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "next-swagger-doc": "^0.3.4", "next-transpile-modules": "^10.0.0", "next-validations": "^0.2.0", - "typescript": "^4.9.4", + "typescript": "^4.7.4", "tzdata": "^1.0.30", "uuid": "^8.3.2", "zod": "^3.20.2" From 3517ef6adce1f3540856a30b4694a4c84d9a1cd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Thu, 26 Jan 2023 18:51:06 -0700 Subject: [PATCH 582/658] Upgrades typescript to 4.9.4 (#230) https://github.com/calcom/cal.com/pull/6747 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index c534b11389..6c1d3c9eb6 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "next-swagger-doc": "^0.3.4", "next-transpile-modules": "^10.0.0", "next-validations": "^0.2.0", - "typescript": "^4.7.4", + "typescript": "^4.9.4", "tzdata": "^1.0.30", "uuid": "^8.3.2", "zod": "^3.20.2" From 279c3da21f32ef84566e06a09e4fe8bdb0d528dc Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Tue, 7 Feb 2023 21:11:08 +0530 Subject: [PATCH 583/658] Improves Booking docs in swagger (#219) Adds definition to booking swagger definition, and fixes user _post definition example --- pages/api/bookings/[id]/_delete.ts | 37 +++++++++++-- pages/api/bookings/[id]/_get.ts | 6 +++ pages/api/bookings/[id]/_patch.ts | 45 ++++++++++++++-- pages/api/bookings/_get.ts | 21 ++++++++ pages/api/bookings/_post.ts | 87 ++++++++++++++++++++++++------ pages/api/users/_post.ts | 20 +++---- 6 files changed, 183 insertions(+), 33 deletions(-) diff --git a/pages/api/bookings/[id]/_delete.ts b/pages/api/bookings/[id]/_delete.ts index a48e53b9ae..c2bc3cf5d9 100644 --- a/pages/api/bookings/[id]/_delete.ts +++ b/pages/api/bookings/[id]/_delete.ts @@ -29,6 +29,19 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * type: integer * required: true * description: ID of the booking to cancel + * parameters: + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the booking to get + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * tags: * - bookings * responses: @@ -36,11 +49,25 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * description: OK, booking cancelled successfuly * 400: * description: | - * Message | Cause - * :--|:-- - * Booking not found| The provided id didn't correspond to any existing booking. - * Cannot cancel past events| The provided id matched an existing booking with a past startDate. - * User not found| The userId did not matched an existing user. + * Bad request + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
MessageCause
Booking not foundThe provided id didn't correspond to any existing booking.
Cannot cancel past eventsThe provided id matched an existing booking with a past startDate.
User not foundThe userId did not matched an existing user.
* 404: * description: User not found */ diff --git a/pages/api/bookings/[id]/_get.ts b/pages/api/bookings/[id]/_get.ts index a15f993077..2d6ae07a64 100644 --- a/pages/api/bookings/[id]/_get.ts +++ b/pages/api/bookings/[id]/_get.ts @@ -18,6 +18,12 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * type: integer * required: true * description: ID of the booking to get + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * tags: * - bookings * responses: diff --git a/pages/api/bookings/[id]/_patch.ts b/pages/api/bookings/[id]/_patch.ts index fc20c14709..55b20bc9c1 100644 --- a/pages/api/bookings/[id]/_patch.ts +++ b/pages/api/bookings/[id]/_patch.ts @@ -23,14 +23,53 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * properties: * title: * type: string - * example: 15min + * description: 'Booking event title' * startTime: * type: string - * example: 1970-01-01T17:00:00.000Z + * format: date-time + * description: 'Start time of the Event' * endTime: * type: string - * example: 1970-01-01T17:00:00.000Z + * format: date-time + * description: 'End time of the Event' + * recurringEventId: + * type: integer + * description: 'Recurring event ID if the event is recurring' + * description: + * type: string + * description: 'Event description' + * status: + * type: string + * description: 'Acceptable values one of ["ACCEPTED", "PENDING", "CANCELLED", "REJECTED"]' + * location: + * type: string + * description: 'Meeting location' + * smsReminderNumber: + * type: number + * description: 'SMS reminder number' + * attendees: + * type: array + * description: 'List of attendees of the booking' + * items: + * type: object + * properties: + * name: + * type: string + * email: + * type: string + * format: email + * timeZone: + * type: string + * locale: + * type: string + * * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * - in: path * name: id * schema: diff --git a/pages/api/bookings/_get.ts b/pages/api/bookings/_get.ts index cdb9f1627f..9476d07e09 100644 --- a/pages/api/bookings/_get.ts +++ b/pages/api/bookings/_get.ts @@ -12,7 +12,28 @@ import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/que * /bookings: * get: * summary: Find all bookings + * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * operationId: listBookings + * requestBody: + * description: Find all bookings + * content: + * application/json: + * schema: + * type: object + * properties: + * userId: + * description: 'The user(s) to get the booking for, if the request is by an Admin' + * oneOf: + * - type: integer + * - type: array + * items: + * type: integer * tags: * - bookings * responses: diff --git a/pages/api/bookings/_post.ts b/pages/api/bookings/_post.ts index af3099dd85..ff3ac36e02 100644 --- a/pages/api/bookings/_post.ts +++ b/pages/api/bookings/_post.ts @@ -8,42 +8,99 @@ import { defaultResponder } from "@calcom/lib/server"; * /bookings: * post: * summary: Creates a new booking + * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * operationId: addBooking * requestBody: - * description: Edit an existing booking related to one of your event-types + * description: Create a new booking related to one of your event-types * required: true * content: * application/json: * schema: * type: object + * required: + * - startTime + * - endTime * properties: * title: * type: string - * example: 15min + * description: 'Booking event title' * startTime: * type: string - * example: 1970-01-01T17:00:00.000Z + * format: date-time + * description: 'Start time of the Event' * endTime: * type: string - * example: 1970-01-01T17:00:00.000Z - * recurringCount: + * format: date-time + * description: 'End time of the Event' + * recurringEventId: + * type: integer + * description: 'Recurring event ID if the event is recurring' + * description: + * type: string + * description: 'Event description' + * status: + * type: string + * description: 'Acceptable values one of ["ACCEPTED", "PENDING", "CANCELLED", "REJECTED"]' + * location: + * type: string + * description: 'Meeting location' + * smsReminderNumber: * type: number - * example: 8 + * description: 'SMS reminder number' + * attendees: + * type: array + * description: 'List of attendees of the booking' + * items: + * type: object + * properties: + * name: + * type: string + * email: + * type: string + * format: email + * timeZone: + * type: string + * locale: + * type: string + * * tags: - * - bookings + * - bookings * responses: * 201: * description: Booking(s) created successfully. * 400: - * description: | - * Message | Cause - * :--|:-- - * Booking body is invalid| Missing property on booking entity. - * Invalid eventTypeId| The provided eventTypeId does not exist. - * Missing recurringCount| The eventType is recurring, and no recurringCount was passed. - * Invalid recurringCount| The provided recurringCount is greater than the eventType recurring config + * description: | + * Bad request + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
MessageCause
Booking body is invalidMissing property on booking entity.
Invalid eventTypeIdThe provided eventTypeId does not exist.
Missing recurringCountThe eventType is recurring, and no recurringCount was passed.
Invalid recurringCountThe provided recurringCount is greater than the eventType recurring config
* 401: - * description: Authorization information is missing or invalid. + * description: Authorization information is missing or invalid. */ async function handler(req: NextApiRequest) { const { userId, isAdmin } = req; diff --git a/pages/api/users/_post.ts b/pages/api/users/_post.ts index 2346e35876..3ee8c222d5 100644 --- a/pages/api/users/_post.ts +++ b/pages/api/users/_post.ts @@ -46,7 +46,7 @@ import { schemaUserCreateBodyParams } from "~/lib/validations/user"; * description: Start of the week. Acceptable values are one of [SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY] * type: string * timeZone: - * description: The new user's time zone + * description: The new user's time zone. Eg: 'EUROPE/PARIS' * type: string * theme: * description: Default theme for the new user. Acceptable values are one of [DARK, LIGHT] @@ -61,15 +61,15 @@ import { schemaUserCreateBodyParams } from "~/lib/validations/user"; * user: * summary: An example of USER * value: - * email: email@example.com - * username: johndoe - * weekStart: MONDAY - * brandColor: #555555 - * darkBrandColor: #111111 - * timeZone: EUROPE/PARIS - * theme: LIGHT - * timeFormat: TWELVE - * locale: FR + * email: 'email@example.com' + * username: 'johndoe' + * weekStart: 'MONDAY' + * brandColor: '#555555' + * darkBrandColor: '#111111' + * timeZone: 'EUROPE/PARIS' + * theme: 'LIGHT' + * timeFormat: 'TWELVE' + * locale: 'FR' * tags: * - users * responses: From 992bdc0b543d2b305b293a8ae9dcc2f0ae8d132c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Tue, 7 Feb 2023 17:20:21 -0700 Subject: [PATCH 584/658] Fixes paginated endpoints (#234) - Passing an invalid number or 0 was causing trouble --- lib/helpers/withPagination.ts | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/helpers/withPagination.ts b/lib/helpers/withPagination.ts index 8a78b03c2b..1f1bd397be 100644 --- a/lib/helpers/withPagination.ts +++ b/lib/helpers/withPagination.ts @@ -2,16 +2,8 @@ import { NextMiddleware } from "next-api-middleware"; import z from "zod"; const withPage = z.object({ - page: z - .string() - .optional() - .default("1") - .transform((n) => parseInt(n)), - take: z - .string() - .optional() - .default("10") - .transform((n) => parseInt(n)), + page: z.coerce.number().min(1).optional().default(1), + take: z.coerce.number().min(1).optional().default(10), }); export const withPagination: NextMiddleware = async (req, _, next) => { From 3ebab100cedab0620f87be0bddba29a3efd890dc Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed, 8 Feb 2023 20:22:08 +0530 Subject: [PATCH 585/658] Fixes invalid availability schema (#236) Hotfix attempt to fix fix invalid availability _post schema in swagger --- pages/api/availabilities/_post.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pages/api/availabilities/_post.ts b/pages/api/availabilities/_post.ts index be48924d61..19c76f26cb 100644 --- a/pages/api/availabilities/_post.ts +++ b/pages/api/availabilities/_post.ts @@ -15,12 +15,12 @@ import { * operationId: addAvailability * summary: Creates a new availability * parameters: - * - in: query - * name: apiKey - * requiried: true - * description: Your API key - * schema: - * type: integer + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * requestBody: * description: Edit an existing availability related to one of your bookings * required: true From 0b2724124acdf91f76ef1d7c3b55ac5868e6dd44 Mon Sep 17 00:00:00 2001 From: zomars Date: Wed, 8 Feb 2023 10:55:46 -0700 Subject: [PATCH 586/658] Updated checkLicense --- lib/helpers/verifyApiKey.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 3f8731c33c..2420dc4358 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -15,10 +15,10 @@ export const dateNotInPast = function (date: Date) { // This verifies the apiKey and sets the user if it is valid. export const verifyApiKey: NextMiddleware = async (req, res, next) => { - const hasValidLicense = await checkLicense(process.env.CALCOM_LICENSE_KEY || ""); + const { prisma, isCustomPrisma, isAdmin } = req; + const hasValidLicense = await checkLicense(prisma); if (!hasValidLicense) return res.status(401).json({ error: "Invalid or missing CALCOM_LICENSE_KEY environment variable" }); - const { prisma, isCustomPrisma, isAdmin } = req; // If the user is an admin and using a license key (from customPrisma), skip the apiKey check. if (isCustomPrisma && isAdmin) { await next(); From dc0a6eaa32374213cc352216fc87a95642238397 Mon Sep 17 00:00:00 2001 From: zomars Date: Wed, 8 Feb 2023 10:55:57 -0700 Subject: [PATCH 587/658] Export for typecheck --- pages/api/users/_get.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/users/_get.ts b/pages/api/users/_get.ts index 3ccfdb6ca0..da4f985931 100644 --- a/pages/api/users/_get.ts +++ b/pages/api/users/_get.ts @@ -29,7 +29,7 @@ import { schemaUsersReadPublic } from "~/lib/validations/user"; * 404: * description: No users were found */ -async function getHandler(req: NextApiRequest) { +export async function getHandler(req: NextApiRequest) { const { userId, prisma, From f170f17f2c1137bfbf4be803c74b854ec1a69f3d Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 9 Feb 2023 03:08:04 +0530 Subject: [PATCH 588/658] Improves custom inputs docs in swagger (#233) Adds swagger definition to `custom-inputs` endpoint --- pages/api/custom-inputs/[id]/_delete.ts | 6 +++ pages/api/custom-inputs/[id]/_get.ts | 6 +++ pages/api/custom-inputs/[id]/_patch.ts | 45 ++++++++++++++++++ pages/api/custom-inputs/_get.ts | 7 +++ pages/api/custom-inputs/_post.ts | 61 +++++++++++++++++++++++++ 5 files changed, 125 insertions(+) diff --git a/pages/api/custom-inputs/[id]/_delete.ts b/pages/api/custom-inputs/[id]/_delete.ts index 86e3fdaf86..747e1954ff 100644 --- a/pages/api/custom-inputs/[id]/_delete.ts +++ b/pages/api/custom-inputs/[id]/_delete.ts @@ -16,6 +16,12 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * type: integer * required: true * description: ID of the eventTypeCustomInput to delete + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * tags: * - custom-inputs * responses: diff --git a/pages/api/custom-inputs/[id]/_get.ts b/pages/api/custom-inputs/[id]/_get.ts index e79ad00c4e..96cb8133dc 100644 --- a/pages/api/custom-inputs/[id]/_get.ts +++ b/pages/api/custom-inputs/[id]/_get.ts @@ -17,6 +17,12 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * type: integer * required: true * description: ID of the eventTypeCustomInput to get + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * tags: * - custom-inputs * responses: diff --git a/pages/api/custom-inputs/[id]/_patch.ts b/pages/api/custom-inputs/[id]/_patch.ts index 860c347284..9ecdd822de 100644 --- a/pages/api/custom-inputs/[id]/_patch.ts +++ b/pages/api/custom-inputs/[id]/_patch.ts @@ -13,6 +13,44 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * /custom-inputs/{id}: * patch: * summary: Edit an existing eventTypeCustomInput + * requestBody: + * description: Edit an existing eventTypeCustomInput for an event type + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * eventTypeId: + * type: integer + * description: 'ID of the event type to which the custom input is being added' + * label: + * type: string + * description: 'Label of the custom input' + * type: + * type: string + * description: 'Type of the custom input. The value is ENUM; one of [TEXT, TEXTLONG, NUMBER, BOOL, RADIO, PHONE]' + * options: + * type: object + * properties: + * label: + * type: string + * type: + * type: string + * description: 'Options for the custom input' + * required: + * type: boolean + * description: 'If the custom input is required before booking' + * placeholder: + * type: string + * description: 'Placeholder text for the custom input' + * + * examples: + * custom-inputs: + * summary: Example of patching an existing Custom Input + * value: + * required: true + * * parameters: * - in: path * name: id @@ -20,6 +58,13 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * type: integer * required: true * description: ID of the eventTypeCustomInput to edit + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key + * * tags: * - custom-inputs * responses: diff --git a/pages/api/custom-inputs/_get.ts b/pages/api/custom-inputs/_get.ts index c08f9239c6..db63434ddf 100644 --- a/pages/api/custom-inputs/_get.ts +++ b/pages/api/custom-inputs/_get.ts @@ -10,6 +10,13 @@ import { schemaEventTypeCustomInputPublic } from "~/lib/validations/event-type-c * /custom-inputs: * get: * summary: Find all eventTypeCustomInputs + * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * tags: * - custom-inputs * responses: diff --git a/pages/api/custom-inputs/_post.ts b/pages/api/custom-inputs/_post.ts index 815ceff04c..56d15816a4 100644 --- a/pages/api/custom-inputs/_post.ts +++ b/pages/api/custom-inputs/_post.ts @@ -8,11 +8,72 @@ import { schemaEventTypeCustomInputPublic, } from "~/lib/validations/event-type-custom-input"; +// id: z.number().int(), +// eventTypeId: z.number().int(), +// label: z.string(), +// type: z.nativeEnum(EventTypeCustomInputType), +// required: z.boolean(), +// placeholder: z.string(), /** * @swagger * /custom-inputs: * post: * summary: Creates a new eventTypeCustomInput + * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key + * requestBody: + * description: Create a new custom input for an event type + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - eventTypeId + * - label + * - type + * - required + * - placeholder + * properties: + * eventTypeId: + * type: integer + * description: 'ID of the event type to which the custom input is being added' + * label: + * type: string + * description: 'Label of the custom input' + * type: + * type: string + * description: 'Type of the custom input. The value is ENUM; one of [TEXT, TEXTLONG, NUMBER, BOOL, RADIO, PHONE]' + * options: + * type: object + * properties: + * label: + * type: string + * type: + * type: string + * description: 'Options for the custom input' + * required: + * type: boolean + * description: 'If the custom input is required before booking' + * placeholder: + * type: string + * description: 'Placeholder text for the custom input' + * + * examples: + * custom-inputs: + * summary: An example of custom-inputs + * value: + * eventTypeID: 1 + * label: "Phone Number" + * type: "PHONE" + * required: true + * placeholder: "100 101 1234" + * * tags: * - custom-inputs * responses: From 2248d7069f2aa2bc35f8e55b006cbde102f76177 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 9 Feb 2023 05:46:32 +0530 Subject: [PATCH 589/658] Improves Destination Calendar docs in swagger (#235) Adds swagger definition to `destination-calendar` endpoint --- pages/api/destination-calendars/[id].ts | 60 ++++++++++++++++++++++-- pages/api/destination-calendars/index.ts | 41 +++++++++++++++- 2 files changed, 94 insertions(+), 7 deletions(-) diff --git a/pages/api/destination-calendars/[id].ts b/pages/api/destination-calendars/[id].ts index 61daae15c8..1f521c40d7 100644 --- a/pages/api/destination-calendars/[id].ts +++ b/pages/api/destination-calendars/[id].ts @@ -40,8 +40,14 @@ export async function destionationCalendarById( * type: integer * required: true * description: ID of the destination calendar to get + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * tags: - * - destination-calendars + * - destination-calendars * responses: * 200: * description: OK @@ -58,8 +64,34 @@ export async function destionationCalendarById( * type: integer * required: true * description: ID of the destination calendar to edit + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key + * requestBody: + * description: Create a new booking related to one of your event-types + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * integration: + * type: string + * description: 'The integration' + * externalId: + * type: string + * description: 'The external ID of the integration' + * eventTypeId: + * type: integer + * description: 'The ID of the eventType it is associated with' + * bookingId: + * type: integer + * description: 'The booking ID it is associated with' * tags: - * - destination-calendars + * - destination-calendars * responses: * 201: * description: OK, destinationCalendar edited successfuly @@ -76,8 +108,14 @@ export async function destionationCalendarById( * type: integer * required: true * description: ID of the destination calendar to delete + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * tags: - * - destination-calendars + * - destination-calendars * responses: * 201: * description: OK, destinationCalendar removed successfuly @@ -110,8 +148,14 @@ export async function destionationCalendarById( * type: integer * required: true * description: ID of the destination calendar to edit + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * tags: - * - destination-calendars + * - destination-calendars * responses: * 201: * description: OK, destinationCalendar edited successfuly @@ -150,8 +194,14 @@ export async function destionationCalendarById( * type: integer * required: true * description: ID of the destination calendar to delete + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * tags: - * - destination-calendars + * - destination-calendars * responses: * 201: * description: OK, destinationCalendar removed successfuly diff --git a/pages/api/destination-calendars/index.ts b/pages/api/destination-calendars/index.ts index 3690dfa359..2143ba0d0a 100644 --- a/pages/api/destination-calendars/index.ts +++ b/pages/api/destination-calendars/index.ts @@ -16,9 +16,16 @@ async function createOrlistAllDestinationCalendars( * @swagger * /destination-calendars: * get: + * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * summary: Find all destination calendars * tags: - * - destination-calendars + * - destination-calendars * responses: * 200: * description: OK @@ -43,9 +50,39 @@ async function createOrlistAllDestinationCalendars( * @swagger * /destination-calendars: * post: + * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * summary: Creates a new destination calendar + * requestBody: + * description: Create a new destination calendar for your events + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - integration + * - externalId + * properties: + * integration: + * type: string + * description: 'The integration' + * externalId: + * type: string + * description: 'The external ID of the integration' + * eventTypeId: + * type: integer + * description: 'The ID of the eventType it is associated with' + * bookingId: + * type: integer + * description: 'The booking ID it is associated with' * tags: - * - destination-calendars + * - destination-calendars * responses: * 201: * description: OK, destination calendar created From 0389ebfed5aa80fea02d37a78ebe277568537536 Mon Sep 17 00:00:00 2001 From: zomars Date: Wed, 8 Feb 2023 19:29:58 -0700 Subject: [PATCH 590/658] Testing disconnect --- lib/helpers/customPrisma.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/helpers/customPrisma.ts b/lib/helpers/customPrisma.ts index 466d6ee8c0..147bc21185 100644 --- a/lib/helpers/customPrisma.ts +++ b/lib/helpers/customPrisma.ts @@ -37,4 +37,5 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { // We don't need the key from here and on. Prevents unrecognized key errors. delete req.query.key; await next(); + await req.prisma.$disconnect(); }; From 317e05511bfddcda575794a5fa242d4343545a18 Mon Sep 17 00:00:00 2001 From: zomars Date: Wed, 8 Feb 2023 19:33:23 -0700 Subject: [PATCH 591/658] Shared insntances test fix --- lib/helpers/customPrisma.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/helpers/customPrisma.ts b/lib/helpers/customPrisma.ts index 147bc21185..c9967dd06e 100644 --- a/lib/helpers/customPrisma.ts +++ b/lib/helpers/customPrisma.ts @@ -26,6 +26,12 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { res.status(400).json({ error: "no databaseUrl set up at your instance yet" }); return; } + try { + /** Attempt to prevent shared connection pools for custom prisma instances */ + await prisma.$disconnect(); + } catch (error) { + console.error("Couldn't not prisma.$disconnect()"); + } req.prisma = customPrisma({ datasources: { db: { url: databaseUrl } } }); /* @note: In order to skip verifyApiKey for customPrisma requests, From fdb45e3745444f9861bc3fce288e5c195722fe65 Mon Sep 17 00:00:00 2001 From: zomars Date: Wed, 8 Feb 2023 19:56:41 -0700 Subject: [PATCH 592/658] More tests --- lib/helpers/customPrisma.ts | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/helpers/customPrisma.ts b/lib/helpers/customPrisma.ts index c9967dd06e..9955568e97 100644 --- a/lib/helpers/customPrisma.ts +++ b/lib/helpers/customPrisma.ts @@ -1,7 +1,7 @@ +import { PrismaClient } from "@prisma/client"; import { NextMiddleware } from "next-api-middleware"; import { CONSOLE_URL } from "@calcom/lib/constants"; -import { customPrisma, prisma } from "@calcom/prisma"; const LOCAL_CONSOLE_URL = process.env.NEXT_PUBLIC_CONSOLE_URL || CONSOLE_URL; @@ -12,7 +12,7 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { }: { query: { key?: string } } = req; // If no custom api Id is provided, attach to request the regular cal.com prisma client. if (!key) { - req.prisma = prisma; + req.prisma = new PrismaClient(); await next(); return; } @@ -26,13 +26,7 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { res.status(400).json({ error: "no databaseUrl set up at your instance yet" }); return; } - try { - /** Attempt to prevent shared connection pools for custom prisma instances */ - await prisma.$disconnect(); - } catch (error) { - console.error("Couldn't not prisma.$disconnect()"); - } - req.prisma = customPrisma({ datasources: { db: { url: databaseUrl } } }); + req.prisma = new PrismaClient({ datasources: { db: { url: databaseUrl } } }); /* @note: In order to skip verifyApiKey for customPrisma requests, we pass isAdmin true, and userId 0, if we detect them later, @@ -44,4 +38,6 @@ export const customPrismaClient: NextMiddleware = async (req, res, next) => { delete req.query.key; await next(); await req.prisma.$disconnect(); + // @ts-expect-error testing + delete req.prisma; }; From f02cfc99906c93767e1f6edd4a0f33fc51a4cc98 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Mon, 13 Feb 2023 18:22:11 +0530 Subject: [PATCH 593/658] Swagger definition general fixes (#237) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR addresses definition errors currently residing within our swagger doc. ~DISCLAIMER: There is still an error for our DELETE booking call, as open API standard doesn't expect the DELETE call to contain a request body, but we are requiring it in the way it currently works. Perhaps we should move those to Query Parameters instead. Thoughts @zomars @emrysal ?~ It was taken care of by @leog and the docs are now updated as per the endpoint image image --------- Co-authored-by: Leo Giovanetti Co-authored-by: Omar López --- .../shared/queryIdTransformParseInt.ts | 11 +--- pages/api/booking-references/[id]/_delete.ts | 8 ++- pages/api/booking-references/[id]/_get.ts | 8 ++- pages/api/booking-references/[id]/_patch.ts | 27 ++++++--- pages/api/booking-references/_get.ts | 9 ++- pages/api/booking-references/_post.ts | 37 ++++++++----- pages/api/bookings/[id]/_delete.ts | 55 +++++++++---------- pages/api/bookings/_get.ts | 23 +++----- pages/api/users/_post.ts | 2 +- 9 files changed, 101 insertions(+), 79 deletions(-) diff --git a/lib/validations/shared/queryIdTransformParseInt.ts b/lib/validations/shared/queryIdTransformParseInt.ts index b97d126d43..b9ec495f47 100644 --- a/lib/validations/shared/queryIdTransformParseInt.ts +++ b/lib/validations/shared/queryIdTransformParseInt.ts @@ -5,14 +5,9 @@ import { baseApiParams } from "./baseApiParams"; // Extracted out as utility function so can be reused // at different endpoints that require this validation. -export const schemaQueryIdParseInt = baseApiParams - .extend({ - id: z - .string() - .regex(/^\d+$/) - .transform((id) => parseInt(id)), - }) - .strict(); +export const schemaQueryIdParseInt = baseApiParams.extend({ + id: z.coerce.number(), +}); export const withValidQueryIdTransformParseInt = withValidation({ schema: schemaQueryIdParseInt, diff --git a/pages/api/booking-references/[id]/_delete.ts b/pages/api/booking-references/[id]/_delete.ts index 54160b0124..23a83ce311 100644 --- a/pages/api/booking-references/[id]/_delete.ts +++ b/pages/api/booking-references/[id]/_delete.ts @@ -17,8 +17,14 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * type: integer * required: true * description: ID of the booking reference to delete + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * tags: - * - booking-references + * - booking-references * responses: * 201: * description: OK, bookingReference removed successfully diff --git a/pages/api/booking-references/[id]/_get.ts b/pages/api/booking-references/[id]/_get.ts index 2ea3bd68c5..6baf71a550 100644 --- a/pages/api/booking-references/[id]/_get.ts +++ b/pages/api/booking-references/[id]/_get.ts @@ -18,8 +18,14 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * type: integer * required: true * description: ID of the booking reference to get + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * tags: - * - booking-references + * - booking-references * responses: * 200: * description: OK diff --git a/pages/api/booking-references/[id]/_patch.ts b/pages/api/booking-references/[id]/_patch.ts index c235370255..37e17e2e00 100644 --- a/pages/api/booking-references/[id]/_patch.ts +++ b/pages/api/booking-references/[id]/_patch.ts @@ -23,16 +23,25 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * schema: * type: object * properties: - * days: - * type: array - * example: email@example.com - * startTime: + * type: * type: string - * example: 1970-01-01T17:00:00.000Z - * endTime: + * meetingId: * type: string - * example: 1970-01-01T17:00:00.000Z + * meetingPassword: + * type: string + * externalCalendarId: + * type: string + * deleted: + * type: boolean + * credentialId: + * type: integer * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * - in: path * name: id * schema: @@ -40,10 +49,10 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * required: true * description: ID of the booking reference to edit * tags: - * - booking-references + * - booking-references * responses: * 201: - * description: OK, safeBody.data edited successfully + * description: OK, BookingReference edited successfully * 400: * description: Bad request. BookingReference body is invalid. * 401: diff --git a/pages/api/booking-references/_get.ts b/pages/api/booking-references/_get.ts index 5934d4ef03..c3b81a4622 100644 --- a/pages/api/booking-references/_get.ts +++ b/pages/api/booking-references/_get.ts @@ -9,10 +9,17 @@ import { schemaBookingReferenceReadPublic } from "~/lib/validations/booking-refe * @swagger * /booking-references: * get: + * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * operationId: listBookingReferences * summary: Find all booking references * tags: - * - booking-references + * - booking-references * responses: * 200: * description: OK diff --git a/pages/api/booking-references/_post.ts b/pages/api/booking-references/_post.ts index ff9f0109aa..b3b8b713cf 100644 --- a/pages/api/booking-references/_post.ts +++ b/pages/api/booking-references/_post.ts @@ -12,6 +12,13 @@ import { * @swagger * /booking-references: * post: + * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * operationId: addBookingReference * summary: Creates a new booking reference * requestBody: @@ -24,27 +31,27 @@ import { * required: * - type * - uid - * - meetingId - * - bookingId - * - deleted * properties: - * deleted: - * type: boolean - * example: false - * uid: - * type: string - * example: '123456789' * type: * type: string - * example: email@example.com - * bookingId: - * type: number - * example: 1 + * uid: + * type: string * meetingId: * type: string - * example: 'meeting-id' + * meetingPassword: + * type: string + * meetingUrl: + * type: string + * bookingId: + * type: boolean + * externalCalendarId: + * type: string + * deleted: + * type: boolean + * credentialId: + * type: integer * tags: - * - booking-references + * - booking-references * responses: * 201: * description: OK, booking reference created diff --git a/pages/api/bookings/[id]/_delete.ts b/pages/api/bookings/[id]/_delete.ts index c2bc3cf5d9..a1cdbc9c3e 100644 --- a/pages/api/bookings/[id]/_delete.ts +++ b/pages/api/bookings/[id]/_delete.ts @@ -12,16 +12,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * delete: * summary: Booking cancellation * operationId: cancelBookingById - * requestBody: - * content: - * application/json: - * schema: - * type: object - * properties: - * allRemainingBookings: - * type: boolean - * reason: - * type: string + * * parameters: * - in: path * name: id @@ -29,24 +20,29 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * type: integer * required: true * description: ID of the booking to cancel - * parameters: - * - in: path - * name: id - * schema: - * type: integer - * required: true - * description: ID of the booking to get - * - in: query - * name: apiKey - * required: true - * schema: - * type: string - * description: Your API key + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key + * - in: query + * name: allRemainingBookings + * required: false + * schema: + * type: boolean + * description: Delete all remaining bookings + * - in: query + * name: reason + * required: false + * schema: + * type: string + * description: The reason for cancellation of the booking * tags: * - bookings * responses: * 200: - * description: OK, booking cancelled successfuly + * description: OK, booking cancelled successfully * 400: * description: | * Bad request @@ -72,11 +68,12 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * description: User not found */ async function handler(req: NextApiRequest) { - const { id } = schemaQueryIdParseInt.parse(req.query); - const { allRemainingBookings, cancellationReason } = schemaBookingCancelParams.parse({ - ...req.body, - cancellationReason: req.body.reason, - }); + const { id, allRemainingBookings, cancellationReason } = schemaQueryIdParseInt + .merge(schemaBookingCancelParams.pick({ allRemainingBookings: true, cancellationReason: true })) + .parse({ + ...req.query, + allRemainingBookings: req.query.allRemainingBookings === "true", + }); // Normalizing for universal handler req.body = { id, allRemainingBookings, cancellationReason }; return await handleCancelBooking(req); diff --git a/pages/api/bookings/_get.ts b/pages/api/bookings/_get.ts index 9476d07e09..a9158c22b3 100644 --- a/pages/api/bookings/_get.ts +++ b/pages/api/bookings/_get.ts @@ -19,21 +19,16 @@ import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/que * schema: * type: string * description: Your API key + * - in: query + * name: userId + * required: false + * schema: + * oneOf: + * - type: integer + * - type: array + * items: + * type: integer * operationId: listBookings - * requestBody: - * description: Find all bookings - * content: - * application/json: - * schema: - * type: object - * properties: - * userId: - * description: 'The user(s) to get the booking for, if the request is by an Admin' - * oneOf: - * - type: integer - * - type: array - * items: - * type: integer * tags: * - bookings * responses: diff --git a/pages/api/users/_post.ts b/pages/api/users/_post.ts index 3ee8c222d5..7c945399d0 100644 --- a/pages/api/users/_post.ts +++ b/pages/api/users/_post.ts @@ -46,7 +46,7 @@ import { schemaUserCreateBodyParams } from "~/lib/validations/user"; * description: Start of the week. Acceptable values are one of [SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY] * type: string * timeZone: - * description: The new user's time zone. Eg: 'EUROPE/PARIS' + * description: The new user's time zone. Eg- 'EUROPE/PARIS' * type: string * theme: * description: Default theme for the new user. Acceptable values are one of [DARK, LIGHT] From 42eb7041d41994d3ee0bfb3c419f948709e0310d Mon Sep 17 00:00:00 2001 From: zomars Date: Thu, 16 Feb 2023 14:01:40 -0700 Subject: [PATCH 594/658] New linting rules --- lib/helpers/addRequestid.ts | 2 +- lib/helpers/captureErrors.ts | 2 +- lib/helpers/customPrisma.ts | 2 +- lib/helpers/extendRequest.ts | 2 +- lib/helpers/httpMethods.ts | 2 +- lib/helpers/verifyApiKey.ts | 2 +- lib/helpers/withPagination.ts | 2 +- lib/types.ts | 2 +- pages/api/api-keys/[id]/index.ts | 2 +- pages/api/api-keys/_get.ts | 2 +- pages/api/attendees/[id]/_patch.ts | 2 +- pages/api/attendees/[id]/index.ts | 2 +- pages/api/availabilities/[id]/index.ts | 2 +- pages/api/booking-references/[id]/index.ts | 2 +- pages/api/bookings/[id]/_patch.ts | 2 +- pages/api/bookings/[id]/cancel.ts | 2 +- pages/api/bookings/[id]/index.ts | 2 +- pages/api/bookings/_get.ts | 2 +- pages/api/custom-inputs/[id]/index.ts | 2 +- pages/api/destination-calendars/index.ts | 2 +- pages/api/docs.ts | 2 +- pages/api/event-types/[id]/_patch.ts | 9 +++------ pages/api/event-types/[id]/index.ts | 2 +- .../event-types/_utils/checkTeamEventEditPermission.ts | 4 ++-- pages/api/memberships/[id]/_get.ts | 2 +- pages/api/memberships/_get.ts | 2 +- pages/api/payments/index.ts | 2 +- pages/api/schedules/[id]/_patch.ts | 2 +- pages/api/teams/[teamId]/_patch.ts | 2 +- pages/api/teams/[teamId]/index.ts | 2 +- pages/api/teams/[teamId]/publish.ts | 2 +- pages/api/teams/_get.ts | 2 +- pages/api/users/_get.ts | 2 +- test/lib/bookings/_post.test.ts | 4 ++-- 34 files changed, 38 insertions(+), 41 deletions(-) diff --git a/lib/helpers/addRequestid.ts b/lib/helpers/addRequestid.ts index 6bdf1e546a..92d2d6919a 100644 --- a/lib/helpers/addRequestid.ts +++ b/lib/helpers/addRequestid.ts @@ -1,5 +1,5 @@ import { nanoid } from "nanoid"; -import { NextMiddleware } from "next-api-middleware"; +import type { NextMiddleware } from "next-api-middleware"; export const addRequestId: NextMiddleware = async (_req, res, next) => { // Apply header with unique ID to every request diff --git a/lib/helpers/captureErrors.ts b/lib/helpers/captureErrors.ts index ff35ee3c89..0d850b052b 100644 --- a/lib/helpers/captureErrors.ts +++ b/lib/helpers/captureErrors.ts @@ -1,5 +1,5 @@ import * as Sentry from "@sentry/nextjs"; -import { NextMiddleware } from "next-api-middleware"; +import type { NextMiddleware } from "next-api-middleware"; export const captureErrors: NextMiddleware = async (_req, res, next) => { try { diff --git a/lib/helpers/customPrisma.ts b/lib/helpers/customPrisma.ts index 9955568e97..54bb8e76e4 100644 --- a/lib/helpers/customPrisma.ts +++ b/lib/helpers/customPrisma.ts @@ -1,5 +1,5 @@ import { PrismaClient } from "@prisma/client"; -import { NextMiddleware } from "next-api-middleware"; +import type { NextMiddleware } from "next-api-middleware"; import { CONSOLE_URL } from "@calcom/lib/constants"; diff --git a/lib/helpers/extendRequest.ts b/lib/helpers/extendRequest.ts index 430504be7b..d6fff1cbd0 100644 --- a/lib/helpers/extendRequest.ts +++ b/lib/helpers/extendRequest.ts @@ -1,4 +1,4 @@ -import { NextMiddleware } from "next-api-middleware"; +import type { NextMiddleware } from "next-api-middleware"; export const extendRequest: NextMiddleware = async (req, res, next) => { req.pagination = { diff --git a/lib/helpers/httpMethods.ts b/lib/helpers/httpMethods.ts index 0bf6243e0f..8003a71984 100644 --- a/lib/helpers/httpMethods.ts +++ b/lib/helpers/httpMethods.ts @@ -1,4 +1,4 @@ -import { NextMiddleware } from "next-api-middleware"; +import type { NextMiddleware } from "next-api-middleware"; export const httpMethod = (allowedHttpMethod: "GET" | "POST" | "PATCH" | "DELETE"): NextMiddleware => { return async function (req, res, next) { diff --git a/lib/helpers/verifyApiKey.ts b/lib/helpers/verifyApiKey.ts index 2420dc4358..45df30e5ef 100644 --- a/lib/helpers/verifyApiKey.ts +++ b/lib/helpers/verifyApiKey.ts @@ -1,4 +1,4 @@ -import { NextMiddleware } from "next-api-middleware"; +import type { NextMiddleware } from "next-api-middleware"; import { hashAPIKey } from "@calcom/features/ee/api-keys/lib/apiKeys"; import checkLicense from "@calcom/features/ee/common/server/checkLicense"; diff --git a/lib/helpers/withPagination.ts b/lib/helpers/withPagination.ts index 1f1bd397be..f29c08829b 100644 --- a/lib/helpers/withPagination.ts +++ b/lib/helpers/withPagination.ts @@ -1,4 +1,4 @@ -import { NextMiddleware } from "next-api-middleware"; +import type { NextMiddleware } from "next-api-middleware"; import z from "zod"; const withPage = z.object({ diff --git a/lib/types.ts b/lib/types.ts index b75941c517..3022c8c0c8 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -1,5 +1,5 @@ import type { EventLocationType } from "@calcom/app-store/locations"; -import { +import type { Attendee, Availability, Booking, diff --git a/pages/api/api-keys/[id]/index.ts b/pages/api/api-keys/[id]/index.ts index 4b27553002..2e0c358153 100644 --- a/pages/api/api-keys/[id]/index.ts +++ b/pages/api/api-keys/[id]/index.ts @@ -1,4 +1,4 @@ -import { NextApiRequest, NextApiResponse } from "next"; +import type { NextApiRequest, NextApiResponse } from "next"; import { defaultHandler, defaultResponder } from "@calcom/lib/server"; diff --git a/pages/api/api-keys/_get.ts b/pages/api/api-keys/_get.ts index 3d374b51ec..8c23c6fe9e 100644 --- a/pages/api/api-keys/_get.ts +++ b/pages/api/api-keys/_get.ts @@ -2,7 +2,7 @@ import type { Prisma } from "@prisma/client"; import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; -import { Ensure } from "@calcom/types/utils"; +import type { Ensure } from "@calcom/types/utils"; import { apiKeyPublicSchema } from "~/lib/validations/api-key"; import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/queryUserId"; diff --git a/pages/api/attendees/[id]/_patch.ts b/pages/api/attendees/[id]/_patch.ts index 73ef195ff8..30e1a3d164 100644 --- a/pages/api/attendees/[id]/_patch.ts +++ b/pages/api/attendees/[id]/_patch.ts @@ -1,5 +1,5 @@ import type { NextApiRequest } from "next"; -import { z } from "zod"; +import type { z } from "zod"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; diff --git a/pages/api/attendees/[id]/index.ts b/pages/api/attendees/[id]/index.ts index 02fa97c2f8..727ad02843 100644 --- a/pages/api/attendees/[id]/index.ts +++ b/pages/api/attendees/[id]/index.ts @@ -1,4 +1,4 @@ -import { NextApiRequest, NextApiResponse } from "next"; +import type { NextApiRequest, NextApiResponse } from "next"; import { defaultHandler, defaultResponder } from "@calcom/lib/server"; diff --git a/pages/api/availabilities/[id]/index.ts b/pages/api/availabilities/[id]/index.ts index 02fa97c2f8..727ad02843 100644 --- a/pages/api/availabilities/[id]/index.ts +++ b/pages/api/availabilities/[id]/index.ts @@ -1,4 +1,4 @@ -import { NextApiRequest, NextApiResponse } from "next"; +import type { NextApiRequest, NextApiResponse } from "next"; import { defaultHandler, defaultResponder } from "@calcom/lib/server"; diff --git a/pages/api/booking-references/[id]/index.ts b/pages/api/booking-references/[id]/index.ts index 02fa97c2f8..727ad02843 100644 --- a/pages/api/booking-references/[id]/index.ts +++ b/pages/api/booking-references/[id]/index.ts @@ -1,4 +1,4 @@ -import { NextApiRequest, NextApiResponse } from "next"; +import type { NextApiRequest, NextApiResponse } from "next"; import { defaultHandler, defaultResponder } from "@calcom/lib/server"; diff --git a/pages/api/bookings/[id]/_patch.ts b/pages/api/bookings/[id]/_patch.ts index 55b20bc9c1..ebf392c822 100644 --- a/pages/api/bookings/[id]/_patch.ts +++ b/pages/api/bookings/[id]/_patch.ts @@ -1,5 +1,5 @@ import type { NextApiRequest } from "next"; -import { z } from "zod"; +import type { z } from "zod"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; diff --git a/pages/api/bookings/[id]/cancel.ts b/pages/api/bookings/[id]/cancel.ts index d85eac4d0c..8dd20bef17 100644 --- a/pages/api/bookings/[id]/cancel.ts +++ b/pages/api/bookings/[id]/cancel.ts @@ -1,4 +1,4 @@ -import { NextApiRequest, NextApiResponse } from "next"; +import type { NextApiRequest, NextApiResponse } from "next"; import { defaultHandler } from "@calcom/lib/server"; diff --git a/pages/api/bookings/[id]/index.ts b/pages/api/bookings/[id]/index.ts index 02fa97c2f8..727ad02843 100644 --- a/pages/api/bookings/[id]/index.ts +++ b/pages/api/bookings/[id]/index.ts @@ -1,4 +1,4 @@ -import { NextApiRequest, NextApiResponse } from "next"; +import type { NextApiRequest, NextApiResponse } from "next"; import { defaultHandler, defaultResponder } from "@calcom/lib/server"; diff --git a/pages/api/bookings/_get.ts b/pages/api/bookings/_get.ts index a9158c22b3..e610f42103 100644 --- a/pages/api/bookings/_get.ts +++ b/pages/api/bookings/_get.ts @@ -1,4 +1,4 @@ -import { Prisma } from "@prisma/client"; +import type { Prisma } from "@prisma/client"; import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; diff --git a/pages/api/custom-inputs/[id]/index.ts b/pages/api/custom-inputs/[id]/index.ts index 02fa97c2f8..727ad02843 100644 --- a/pages/api/custom-inputs/[id]/index.ts +++ b/pages/api/custom-inputs/[id]/index.ts @@ -1,4 +1,4 @@ -import { NextApiRequest, NextApiResponse } from "next"; +import type { NextApiRequest, NextApiResponse } from "next"; import { defaultHandler, defaultResponder } from "@calcom/lib/server"; diff --git a/pages/api/destination-calendars/index.ts b/pages/api/destination-calendars/index.ts index 2143ba0d0a..c1330d49fa 100644 --- a/pages/api/destination-calendars/index.ts +++ b/pages/api/destination-calendars/index.ts @@ -1,7 +1,7 @@ import type { NextApiRequest, NextApiResponse } from "next"; import { withMiddleware } from "~/lib/helpers/withMiddleware"; -import { DestinationCalendarResponse, DestinationCalendarsResponse } from "~/lib/types"; +import type { DestinationCalendarResponse, DestinationCalendarsResponse } from "~/lib/types"; import { schemaDestinationCalendarCreateBodyParams, schemaDestinationCalendarReadPublic, diff --git a/pages/api/docs.ts b/pages/api/docs.ts index bdbb3cd462..27a09c650c 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -1,7 +1,7 @@ import modifyRes from "modify-response-middleware"; import { use } from "next-api-middleware"; import { withSwagger } from "next-swagger-doc"; -import { NextApiRequest, NextApiResponse } from "next/types"; +import type { NextApiRequest, NextApiResponse } from "next/types"; import pjson from "~/package.json"; diff --git a/pages/api/event-types/[id]/_patch.ts b/pages/api/event-types/[id]/_patch.ts index a1c0bef77e..e712bc8f14 100644 --- a/pages/api/event-types/[id]/_patch.ts +++ b/pages/api/event-types/[id]/_patch.ts @@ -1,14 +1,11 @@ import type { NextApiRequest } from "next"; -import { z } from "zod"; +import type { z } from "zod"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; -import { - schemaEventTypeEditBodyParams, - schemaEventTypeBaseBodyParams, - schemaEventTypeReadPublic, -} from "~/lib/validations/event-type"; +import type { schemaEventTypeBaseBodyParams } from "~/lib/validations/event-type"; +import { schemaEventTypeEditBodyParams, schemaEventTypeReadPublic } from "~/lib/validations/event-type"; import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt"; import checkTeamEventEditPermission from "../_utils/checkTeamEventEditPermission"; diff --git a/pages/api/event-types/[id]/index.ts b/pages/api/event-types/[id]/index.ts index 02fa97c2f8..727ad02843 100644 --- a/pages/api/event-types/[id]/index.ts +++ b/pages/api/event-types/[id]/index.ts @@ -1,4 +1,4 @@ -import { NextApiRequest, NextApiResponse } from "next"; +import type { NextApiRequest, NextApiResponse } from "next"; import { defaultHandler, defaultResponder } from "@calcom/lib/server"; diff --git a/pages/api/event-types/_utils/checkTeamEventEditPermission.ts b/pages/api/event-types/_utils/checkTeamEventEditPermission.ts index b2392ba7b4..abcfc055f2 100644 --- a/pages/api/event-types/_utils/checkTeamEventEditPermission.ts +++ b/pages/api/event-types/_utils/checkTeamEventEditPermission.ts @@ -1,9 +1,9 @@ import type { NextApiRequest } from "next"; -import { z } from "zod"; +import type { z } from "zod"; import { HttpError } from "@calcom/lib/http-error"; -import { schemaEventTypeBaseBodyParams } from "~/lib/validations/event-type"; +import type { schemaEventTypeBaseBodyParams } from "~/lib/validations/event-type"; export default async function checkTeamEventEditPermission( req: NextApiRequest, diff --git a/pages/api/memberships/[id]/_get.ts b/pages/api/memberships/[id]/_get.ts index a9395bcebe..cf44094bfa 100644 --- a/pages/api/memberships/[id]/_get.ts +++ b/pages/api/memberships/[id]/_get.ts @@ -1,4 +1,4 @@ -import { Prisma } from "@prisma/client"; +import type { Prisma } from "@prisma/client"; import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; diff --git a/pages/api/memberships/_get.ts b/pages/api/memberships/_get.ts index dc7bc41c1a..da6e936df3 100644 --- a/pages/api/memberships/_get.ts +++ b/pages/api/memberships/_get.ts @@ -1,4 +1,4 @@ -import { Prisma } from "@prisma/client"; +import type { Prisma } from "@prisma/client"; import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; diff --git a/pages/api/payments/index.ts b/pages/api/payments/index.ts index d6721e2417..c6f8c79fec 100644 --- a/pages/api/payments/index.ts +++ b/pages/api/payments/index.ts @@ -1,7 +1,7 @@ import type { NextApiRequest, NextApiResponse } from "next"; import { withMiddleware } from "~/lib/helpers/withMiddleware"; -import { PaymentsResponse } from "~/lib/types"; +import type { PaymentsResponse } from "~/lib/types"; import { schemaPaymentPublic } from "~/lib/validations/payment"; /** diff --git a/pages/api/schedules/[id]/_patch.ts b/pages/api/schedules/[id]/_patch.ts index e8a27ee105..e121eafa75 100644 --- a/pages/api/schedules/[id]/_patch.ts +++ b/pages/api/schedules/[id]/_patch.ts @@ -1,5 +1,5 @@ import type { NextApiRequest } from "next"; -import { z } from "zod"; +import type { z } from "zod"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; diff --git a/pages/api/teams/[teamId]/_patch.ts b/pages/api/teams/[teamId]/_patch.ts index 964a73e4dd..ddf83e5883 100644 --- a/pages/api/teams/[teamId]/_patch.ts +++ b/pages/api/teams/[teamId]/_patch.ts @@ -1,4 +1,4 @@ -import { Prisma } from "@prisma/client"; +import type { Prisma } from "@prisma/client"; import type { NextApiRequest } from "next"; import { purchaseTeamSubscription } from "@calcom/features/ee/teams/lib/payments"; diff --git a/pages/api/teams/[teamId]/index.ts b/pages/api/teams/[teamId]/index.ts index 02fa97c2f8..727ad02843 100644 --- a/pages/api/teams/[teamId]/index.ts +++ b/pages/api/teams/[teamId]/index.ts @@ -1,4 +1,4 @@ -import { NextApiRequest, NextApiResponse } from "next"; +import type { NextApiRequest, NextApiResponse } from "next"; import { defaultHandler, defaultResponder } from "@calcom/lib/server"; diff --git a/pages/api/teams/[teamId]/publish.ts b/pages/api/teams/[teamId]/publish.ts index f85f6431a9..edb36be796 100644 --- a/pages/api/teams/[teamId]/publish.ts +++ b/pages/api/teams/[teamId]/publish.ts @@ -1,5 +1,5 @@ import { MembershipRole, UserPermissionRole } from "@prisma/client"; -import { NextApiRequest, NextApiResponse } from "next"; +import type { NextApiRequest, NextApiResponse } from "next"; import { HttpError } from "@calcom/lib/http-error"; import { defaultHandler, defaultResponder } from "@calcom/lib/server"; diff --git a/pages/api/teams/_get.ts b/pages/api/teams/_get.ts index 21fb8eb85e..ca038fdc18 100644 --- a/pages/api/teams/_get.ts +++ b/pages/api/teams/_get.ts @@ -1,4 +1,4 @@ -import { Prisma } from "@prisma/client"; +import type { Prisma } from "@prisma/client"; import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; diff --git a/pages/api/users/_get.ts b/pages/api/users/_get.ts index da4f985931..59e09bdeb5 100644 --- a/pages/api/users/_get.ts +++ b/pages/api/users/_get.ts @@ -1,4 +1,4 @@ -import { Prisma } from "@prisma/client"; +import type { Prisma } from "@prisma/client"; import type { NextApiRequest } from "next"; import { defaultResponder } from "@calcom/lib/server"; diff --git a/test/lib/bookings/_post.test.ts b/test/lib/bookings/_post.test.ts index 9072f9e35b..95bf7a73d5 100644 --- a/test/lib/bookings/_post.test.ts +++ b/test/lib/bookings/_post.test.ts @@ -1,5 +1,5 @@ -import { Request, Response } from "express"; -import { NextApiRequest, NextApiResponse } from "next"; +import type { Request, Response } from "express"; +import type { NextApiRequest, NextApiResponse } from "next"; import { createMocks } from "node-mocks-http"; import dayjs from "@calcom/dayjs"; From a4f82fa6fa505f2bf82fdf13ccd585c3b6f4a7bb Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 23 Feb 2023 18:24:10 +0530 Subject: [PATCH 595/658] Adds swagger definition to Event Types (#242) This PR adds swagger definition to Event Types endpoint with request body examples for POST and PATCH requests --- pages/api/bookings/_post.ts | 6 ++ pages/api/event-types/[id]/_delete.ts | 10 +- pages/api/event-types/[id]/_get.ts | 24 +++-- pages/api/event-types/[id]/_patch.ts | 122 ++++++++++++++++++++++- pages/api/event-types/_get.ts | 9 +- pages/api/event-types/_post.ts | 137 ++++++++++++++++++++++++-- 6 files changed, 284 insertions(+), 24 deletions(-) diff --git a/pages/api/bookings/_post.ts b/pages/api/bookings/_post.ts index ff3ac36e02..51ee9333d2 100644 --- a/pages/api/bookings/_post.ts +++ b/pages/api/bookings/_post.ts @@ -50,6 +50,12 @@ import { defaultResponder } from "@calcom/lib/server"; * location: * type: string * description: 'Meeting location' + * seatsPerTimeSlot: + * type: integer + * description: 'The number of seats for each time slot' + * seatsShowAttendees: + * type: boolean + * description: 'Share Attendee information in seats' * smsReminderNumber: * type: number * description: 'SMS reminder number' diff --git a/pages/api/event-types/[id]/_delete.ts b/pages/api/event-types/[id]/_delete.ts index 20a5dc4d65..2e598afc54 100644 --- a/pages/api/event-types/[id]/_delete.ts +++ b/pages/api/event-types/[id]/_delete.ts @@ -12,18 +12,22 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * operationId: removeEventTypeById * summary: Remove an existing eventType * parameters: + * - in: query + * name: apiKey + * schema: + * type: string + * required: true + * description: Your API Key * - in: path * name: id * schema: * type: integer * required: true * description: ID of the eventType to delete - * security: - * - ApiKeyAuth: [] * tags: * - event-types * externalDocs: - * url: https://docs.cal.com/event-types + * url: https://docs.cal.com/core-features/event-types * responses: * 201: * description: OK, eventType removed successfully diff --git a/pages/api/event-types/[id]/_get.ts b/pages/api/event-types/[id]/_get.ts index 747a91513a..58046dedcd 100644 --- a/pages/api/event-types/[id]/_get.ts +++ b/pages/api/event-types/[id]/_get.ts @@ -12,19 +12,23 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * operationId: getEventTypeById * summary: Find a eventType * parameters: - * - in: path - * name: id - * example: 4 - * schema: - * type: integer - * required: true - * description: ID of the eventType to get - * security: - * - ApiKeyAuth: [] + * - in: query + * name: apiKey + * schema: + * type: string + * required: true + * description: Your API Key + * - in: path + * name: id + * example: 4 + * schema: + * type: integer + * required: true + * description: ID of the eventType to get * tags: * - event-types * externalDocs: - * url: https://docs.cal.com/event-types + * url: https://docs.cal.com/core-features/event-types * responses: * 200: * description: OK diff --git a/pages/api/event-types/[id]/_patch.ts b/pages/api/event-types/[id]/_patch.ts index e712bc8f14..57662a623e 100644 --- a/pages/api/event-types/[id]/_patch.ts +++ b/pages/api/event-types/[id]/_patch.ts @@ -17,18 +17,134 @@ import checkTeamEventEditPermission from "../_utils/checkTeamEventEditPermission * operationId: editEventTypeById * summary: Edit an existing eventType * parameters: + * - in: query + * name: apiKey + * schema: + * type: string + * required: true + * description: Your API Key * - in: path * name: id * schema: * type: integer * required: true * description: ID of the eventType to edit - * security: - * - ApiKeyAuth: [] + * requestBody: + * description: Create a new event-type related to your user or team + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * length: + * type: integer + * description: Duration of the event type in minutes + * metadata: + * type: object + * description: Metadata relating to event type. Pass {} if empty + * title: + * type: string + * description: Title of the event type + * slug: + * type: string + * description: Unique slug for the event type + * hidden: + * type: boolean + * description: If the event type should be hidden from your public booking page + * position: + * type: integer + * description: The position of the event type on the public booking page + * teamId: + * type: integer + * description: Team ID if the event type should belong to a team + * periodType: + * type: string + * enum: [UNLIMITED, ROLLING, RANGE] + * description: To decide how far into the future an invitee can book an event with you + * periodStartDate: + * type: string + * format: date-time + * description: Start date of bookable period (Required if periodType is 'range') + * periodEndDate: + * type: string + * format: date-time + * description: End date of bookable period (Required if periodType is 'range') + * periodDays: + * type: integer + * description: Number of bookable days (Required if periodType is rolling) + * periodCountCalendarDays: + * type: boolean + * description: If calendar days should be counted for period days + * requiresConfirmation: + * type: boolean + * description: If the event type should require your confirmation before completing the booking + * recurringEvent: + * type: object + * description: If the event should recur every week/month/year with the selected frequency + * properties: + * interval: + * type: integer + * count: + * type: integer + * freq: + * type: integer + * disableGuests: + * type: boolean + * description: If the event type should disable adding guests to the booking + * hideCalendarNotes: + * type: boolean + * description: If the calendar notes should be hidden from the booking + * minimumBookingNotice: + * type: integer + * description: Minimum time in minutes before the event is bookable + * beforeEventBuffer: + * type: integer + * description: Number of minutes of buffer time before a Cal Event + * afterEventBuffer: + * type: integer + * description: Number of minutes of buffer time after a Cal Event + * schedulingType: + * type: string + * description: The type of scheduling if a Team event. Required for team events only + * enum: [ROUND_ROBIN, COLLECTIVE] + * price: + * type: integer + * description: Price of the event type booking + * currency: + * type: string + * description: Currency acronym. Eg- usd, eur, gbp, etc. + * slotInterval: + * type: integer + * description: The intervals of available bookable slots in minutes + * successRedirectUrl: + * type: string + * format: url + * description: A valid URL where the booker will redirect to, once the booking is completed successfully + * description: + * type: string + * description: Description of the event type + * seatsPerTimeSlot: + * type: integer + * description: 'The number of seats for each time slot' + * seatsShowAttendees: + * type: boolean + * description: 'Share Attendee information in seats' + * locations: + * type: array + * description: A list of all available locations for the event type + * items: + * type: object + * example: + * event-type: + * summary: An example of event type PATCH request + * value: + * length: 60 + * requiresConfirmation: true * tags: * - event-types * externalDocs: - * url: https://docs.cal.com/event-types + * url: https://docs.cal.com/core-features/event-types * responses: * 201: * description: OK, eventType edited successfully diff --git a/pages/api/event-types/_get.ts b/pages/api/event-types/_get.ts index bd87e5546e..0f5810a774 100644 --- a/pages/api/event-types/_get.ts +++ b/pages/api/event-types/_get.ts @@ -13,10 +13,17 @@ import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/que * get: * summary: Find all event types * operationId: listEventTypes + * parameters: + * - in: query + * name: apiKey + * schema: + * type: string + * required: true + * description: Your API Key * tags: * - event-types * externalDocs: - * url: https://docs.cal.com/event-types + * url: https://docs.cal.com/core-features/event-types * responses: * 200: * description: OK diff --git a/pages/api/event-types/_post.ts b/pages/api/event-types/_post.ts index faefb4cc74..28be45e2f5 100644 --- a/pages/api/event-types/_post.ts +++ b/pages/api/event-types/_post.ts @@ -14,6 +14,13 @@ import checkTeamEventEditPermission from "./_utils/checkTeamEventEditPermission" * post: * summary: Creates a new event type * operationId: addEventType + * parameters: + * - in: query + * name: apiKey + * schema: + * type: string + * required: true + * description: Your API Key * requestBody: * description: Create a new event-type related to your user or team * required: true @@ -28,22 +35,138 @@ import checkTeamEventEditPermission from "./_utils/checkTeamEventEditPermission" * - metadata * properties: * length: - * type: number - * example: 30 + * type: integer + * description: Duration of the event type in minutes * metadata: * type: object - * example: {"smartContractAddress": "0x1234567890123456789012345678901234567890"} + * description: Metadata relating to event type. Pass {} if empty * title: * type: string - * example: My Event + * description: Title of the event type * slug: * type: string - * example: my-event - * + * description: Unique slug for the event type + * hidden: + * type: boolean + * description: If the event type should be hidden from your public booking page + * position: + * type: integer + * description: The position of the event type on the public booking page + * teamId: + * type: integer + * description: Team ID if the event type should belong to a team + * periodType: + * type: string + * enum: [UNLIMITED, ROLLING, RANGE] + * description: To decide how far into the future an invitee can book an event with you + * periodStartDate: + * type: string + * format: date-time + * description: Start date of bookable period (Required if periodType is 'range') + * periodEndDate: + * type: string + * format: date-time + * description: End date of bookable period (Required if periodType is 'range') + * periodDays: + * type: integer + * description: Number of bookable days (Required if periodType is rolling) + * periodCountCalendarDays: + * type: boolean + * description: If calendar days should be counted for period days + * requiresConfirmation: + * type: boolean + * description: If the event type should require your confirmation before completing the booking + * recurringEvent: + * type: object + * description: If the event should recur every week/month/year with the selected frequency + * properties: + * interval: + * type: integer + * count: + * type: integer + * freq: + * type: integer + * disableGuests: + * type: boolean + * description: If the event type should disable adding guests to the booking + * hideCalendarNotes: + * type: boolean + * description: If the calendar notes should be hidden from the booking + * minimumBookingNotice: + * type: integer + * description: Minimum time in minutes before the event is bookable + * beforeEventBuffer: + * type: integer + * description: Number of minutes of buffer time before a Cal Event + * afterEventBuffer: + * type: integer + * description: Number of minutes of buffer time after a Cal Event + * schedulingType: + * type: string + * description: The type of scheduling if a Team event. Required for team events only + * enum: [ROUND_ROBIN, COLLECTIVE] + * price: + * type: integer + * description: Price of the event type booking + * currency: + * type: string + * description: Currency acronym. Eg- usd, eur, gbp, etc. + * slotInterval: + * type: integer + * description: The intervals of available bookable slots in minutes + * successRedirectUrl: + * type: string + * format: url + * description: A valid URL where the booker will redirect to, once the booking is completed successfully + * description: + * type: string + * description: Description of the event type + * locations: + * type: array + * description: A list of all available locations for the event type + * items: + * type: object + * example: + * event-type: + * summary: An example of event type POST request + * value: + * title: Hello World + * slug: hello-world + * length: 30 + * hidden: false + * position: 0 + * eventName: null + * timeZone: null + * periodType: UNLIMITED + * periodStartDate: 2023-02-15T08:46:16.000Z + * periodEndDate: 2023-0-15T08:46:16.000Z + * periodDays: null + * periodCountCalendarDays: false + * requiresConfirmation: false + * recurringEvent: null + * disableGuests: false + * hideCalendarNotes: false + * minimumBookingNotice: 120 + * beforeEventBuffer: 0 + * afterEventBuffer: 0 + * price: 0 + * currency: usd + * slotInterval: null + * successRedirectUrl: null + * description: A test event type + * metadata: { + * apps: { + * stripe: { + * price: 0, + * enabled: false, + * currency: usd + * } + * } + * } * tags: * - event-types * externalDocs: - * url: https://docs.cal.com/event-types + * url: https://docs.cal.com/core-features/event-types * responses: * 201: * description: OK, event type created From d47fa578b756f04c57e5bb1bf044806e2f3c17e2 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 23 Feb 2023 20:46:55 +0530 Subject: [PATCH 596/658] Fixes _patch swagger paramters --- pages/api/bookings/[id]/_patch.ts | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/pages/api/bookings/[id]/_patch.ts b/pages/api/bookings/[id]/_patch.ts index ebf392c822..ecee252e79 100644 --- a/pages/api/bookings/[id]/_patch.ts +++ b/pages/api/bookings/[id]/_patch.ts @@ -32,36 +32,9 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * type: string * format: date-time * description: 'End time of the Event' - * recurringEventId: - * type: integer - * description: 'Recurring event ID if the event is recurring' - * description: - * type: string - * description: 'Event description' * status: * type: string * description: 'Acceptable values one of ["ACCEPTED", "PENDING", "CANCELLED", "REJECTED"]' - * location: - * type: string - * description: 'Meeting location' - * smsReminderNumber: - * type: number - * description: 'SMS reminder number' - * attendees: - * type: array - * description: 'List of attendees of the booking' - * items: - * type: object - * properties: - * name: - * type: string - * email: - * type: string - * format: email - * timeZone: - * type: string - * locale: - * type: string * * parameters: * - in: query From 2a5688f2a6893e46e2cc8bda152d383738024da3 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 24 Feb 2023 03:34:48 +0530 Subject: [PATCH 597/658] Adds the ability to confirm a booking using API (#243) Simply adds the ability to update the status of a booking (meant for confirming a booking) using the API Fixes: https://github.com/calcom/cal.com/issues/7121 --- lib/validations/booking.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index b6e3832140..c295cf97bd 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -22,6 +22,7 @@ const schemaBookingEditParams = z title: z.string().optional(), startTime: iso8601.optional(), endTime: iso8601.optional(), + status: z.string().optional(), }) .strict(); From d8d875cc0192694cd05fc446027030f63b67f67f Mon Sep 17 00:00:00 2001 From: zomars Date: Tue, 28 Feb 2023 15:01:11 -0700 Subject: [PATCH 598/658] Upgrades next --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6c1d3c9eb6..9effa1de70 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "bcryptjs": "^2.4.3", "memory-cache": "^0.2.0", "modify-response-middleware": "^1.1.0", - "next": "^13.1.1", + "next": "^13.2.1", "next-api-middleware": "^1.0.1", "next-axiom": "^0.16.0", "next-swagger-doc": "^0.3.4", From d65d08a3a1595a4a2d2eb48823489edf66639341 Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 3 Mar 2023 13:20:27 -0700 Subject: [PATCH 599/658] Type fix --- lib/validations/booking.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index c295cf97bd..b43c2c8ac9 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -13,6 +13,7 @@ const schemaBookingBaseBodyParams = Booking.pick({ description: true, startTime: true, endTime: true, + status: true, }).partial(); export const schemaBookingCreateBodyParams = extendedBookingCreateBody.merge(schemaQueryUserId.partial()); @@ -22,7 +23,6 @@ const schemaBookingEditParams = z title: z.string().optional(), startTime: iso8601.optional(), endTime: iso8601.optional(), - status: z.string().optional(), }) .strict(); From 59c25d41fd3cda82fc3d52ee6aa3a8ccdce2755c Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Mon, 6 Mar 2023 12:45:04 +0000 Subject: [PATCH 600/658] Removed next-transpile-modules --- next.config.js | 90 ++++++++++++++++++++++++-------------------------- package.json | 1 - 2 files changed, 43 insertions(+), 48 deletions(-) diff --git a/next.config.js b/next.config.js index 568fe06270..0c9da3ba5b 100644 --- a/next.config.js +++ b/next.config.js @@ -1,49 +1,45 @@ -// https://www.npmjs.com/package/next-transpile-modules -// This makes our @calcom/prisma package from the monorepo to be transpiled and usable by API -const withTM = require("next-transpile-modules")([ - "@calcom/app-store", - "@calcom/core", - "@calcom/dayjs", - "@calcom/emails", - "@calcom/embed-core", - "@calcom/embed-snippet", - "@calcom/features", - "@calcom/lib", - "@calcom/prisma", - "@calcom/trpc", -]); const { withAxiom } = require("next-axiom"); -module.exports = withAxiom( - withTM({ - async rewrites() { - return { - afterFiles: [ - // This redirects requests recieved at / the root to the /api/ folder. - { - source: "/v:version/:rest*", - destination: "/api/v:version/:rest*", - }, - // This redirects requests to api/v*/ to /api/ passing version as a query parameter. - { - source: "/api/v:version/:rest*", - destination: "/api/:rest*?version=:version", - }, - // Keeps backwards compatibility with old webhook URLs - { - source: "/api/hooks/:rest*", - destination: "/api/webhooks/:rest*", - }, - ], - fallback: [ - // These rewrites are checked after both pages/public files - // and dynamic routes are checked - { - source: "/:path*", - destination: `/api/:path*`, - }, - ], - }; - }, - }) -); +module.exports = withAxiom({ + transpilePackages: [ + "@calcom/app-store", + "@calcom/core", + "@calcom/dayjs", + "@calcom/emails", + "@calcom/embed-core", + "@calcom/embed-snippet", + "@calcom/features", + "@calcom/lib", + "@calcom/prisma", + "@calcom/trpc", + ], + async rewrites() { + return { + afterFiles: [ + // This redirects requests recieved at / the root to the /api/ folder. + { + source: "/v:version/:rest*", + destination: "/api/v:version/:rest*", + }, + // This redirects requests to api/v*/ to /api/ passing version as a query parameter. + { + source: "/api/v:version/:rest*", + destination: "/api/:rest*?version=:version", + }, + // Keeps backwards compatibility with old webhook URLs + { + source: "/api/hooks/:rest*", + destination: "/api/webhooks/:rest*", + }, + ], + fallback: [ + // These rewrites are checked after both pages/public files + // and dynamic routes are checked + { + source: "/:path*", + destination: `/api/:path*`, + }, + ], + }; + }, +}); diff --git a/package.json b/package.json index 9effa1de70..d25af3f814 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,6 @@ "next-api-middleware": "^1.0.1", "next-axiom": "^0.16.0", "next-swagger-doc": "^0.3.4", - "next-transpile-modules": "^10.0.0", "next-validations": "^0.2.0", "typescript": "^4.9.4", "tzdata": "^1.0.30", From e54e1aa72e49d682d9fcddef6a9600d92b909f0c Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 10 Mar 2023 19:29:24 +0530 Subject: [PATCH 601/658] Updates Availability and Attendees swagger docs, hotfixes Booking API doc (#241) - Adds swagger definition and swagger fixes to /availability and /attendees - Also fixes Booking API endpoint definition (startTime -> start, endTime -> end) --- pages/api/attendees/[id]/_delete.ts | 8 ++++- pages/api/attendees/[id]/_get.ts | 7 +++- pages/api/attendees/[id]/_patch.ts | 28 ++++++++------- pages/api/attendees/_get.ts | 7 ++++ pages/api/attendees/_post.ts | 12 ++++--- pages/api/availability/_get.ts | 56 +++++++++++++++++++++++++++++ pages/api/bookings/[id]/_patch.ts | 4 +-- pages/api/bookings/_post.ts | 8 ++--- 8 files changed, 106 insertions(+), 24 deletions(-) diff --git a/pages/api/attendees/[id]/_delete.ts b/pages/api/attendees/[id]/_delete.ts index 1001aed900..4d0475b864 100644 --- a/pages/api/attendees/[id]/_delete.ts +++ b/pages/api/attendees/[id]/_delete.ts @@ -11,6 +11,12 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * operationId: removeAttendeeById * summary: Remove an existing attendee * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * - in: path * name: id * schema: @@ -21,7 +27,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * - attendees * responses: * 201: - * description: OK, attendee removed successfuly + * description: OK, attendee removed successfully * 400: * description: Bad request. Attendee id is invalid. * 401: diff --git a/pages/api/attendees/[id]/_get.ts b/pages/api/attendees/[id]/_get.ts index a47a457ff5..bf1680de29 100644 --- a/pages/api/attendees/[id]/_get.ts +++ b/pages/api/attendees/[id]/_get.ts @@ -12,13 +12,18 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * operationId: getAttendeeById * summary: Find an attendee * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * - in: path * name: id * schema: * type: integer * required: true * description: ID of the attendee to get - * example: 3 * tags: * - attendees * responses: diff --git a/pages/api/attendees/[id]/_patch.ts b/pages/api/attendees/[id]/_patch.ts index 30e1a3d164..67269c7197 100644 --- a/pages/api/attendees/[id]/_patch.ts +++ b/pages/api/attendees/[id]/_patch.ts @@ -11,8 +11,8 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * @swagger * /attendees/{id}: * patch: - * summary: Edit an existing attendee * operationId: editAttendeeById + * summary: Edit an existing attendee * requestBody: * description: Edit an existing attendee related to one of your bookings * required: true @@ -23,31 +23,35 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * properties: * email: * type: string - * example: email@example.com + * format: email * name: * type: string - * example: John Doe * timeZone: * type: string - * example: Europe/London * parameters: - * - in: path - * name: id - * schema: - * type: integer - * example: 3 - * required: true - * description: ID of the attendee to edit + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key + * - in: path + * name: id + * schema: + * type: integer + * required: true + * description: ID of the attendee to get * tags: * - attendees * responses: * 201: - * description: OK, attendee edited successfuly + * description: OK, attendee edited successfully * 400: * description: Bad request. Attendee body is invalid. * 401: * description: Authorization information is missing or invalid. */ + export async function patchHandler(req: NextApiRequest) { const { prisma, query, body } = req; const { id } = schemaQueryIdParseInt.parse(query); diff --git a/pages/api/attendees/_get.ts b/pages/api/attendees/_get.ts index d4d1e28c55..d6662d897c 100644 --- a/pages/api/attendees/_get.ts +++ b/pages/api/attendees/_get.ts @@ -12,6 +12,13 @@ import { schemaAttendeeReadPublic } from "~/lib/validations/attendee"; * get: * operationId: listAttendees * summary: Find all attendees + * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * tags: * - attendees * responses: diff --git a/pages/api/attendees/_post.ts b/pages/api/attendees/_post.ts index 9f6b29c97d..8570376c55 100644 --- a/pages/api/attendees/_post.ts +++ b/pages/api/attendees/_post.ts @@ -11,6 +11,13 @@ import { schemaAttendeeCreateBodyParams, schemaAttendeeReadPublic } from "~/lib/ * post: * operationId: addAttendee * summary: Creates a new attendee + * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * requestBody: * description: Create a new attendee related to one of your bookings * required: true @@ -26,16 +33,13 @@ import { schemaAttendeeCreateBodyParams, schemaAttendeeReadPublic } from "~/lib/ * properties: * bookingId: * type: number - * example: 1 * email: * type: string - * example: email@example.com + * format: email * name: * type: string - * example: John Doe * timeZone: * type: string - * example: Europe/London * tags: * - attendees * responses: diff --git a/pages/api/availability/_get.ts b/pages/api/availability/_get.ts index 7dee66c194..f601251609 100644 --- a/pages/api/availability/_get.ts +++ b/pages/api/availability/_get.ts @@ -7,6 +7,62 @@ import { defaultResponder } from "@calcom/lib/server"; import { availabilityUserSelect } from "@calcom/prisma"; import { stringOrNumber } from "@calcom/prisma/zod-utils"; +/** + * @swagger + * /availability: + * get: + * summary: Find user or team availability + * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key + * - in: query + * name: userId + * schema: + * type: integer + * description: ID of the user to fetch the availability for + * - in: query + * name: teamId + * schema: + * type: integer + * description: ID of the team to fetch the availability for + * - in: query + * name: username + * schema: + * type: string + * description: username of the user to fetch the availability for + * - in: query + * name: dateFrom + * schema: + * type: string + * format: date + * description: Start Date of the availability query + * - in: query + * name: dateTo + * schema: + * type: string + * format: date + * description: End Date of the availability query + * - in: query + * name: eventTypeId + * schema: + * type: integer + * description: Event Type ID of the event type to fetch the availability for + * operationId: availability + * tags: + * - availability + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: User not found | Team not found | Team has no members + */ + const availabilitySchema = z .object({ userId: stringOrNumber.optional(), diff --git a/pages/api/bookings/[id]/_patch.ts b/pages/api/bookings/[id]/_patch.ts index ecee252e79..8c1638e2a4 100644 --- a/pages/api/bookings/[id]/_patch.ts +++ b/pages/api/bookings/[id]/_patch.ts @@ -24,11 +24,11 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * title: * type: string * description: 'Booking event title' - * startTime: + * start: * type: string * format: date-time * description: 'Start time of the Event' - * endTime: + * end: * type: string * format: date-time * description: 'End time of the Event' diff --git a/pages/api/bookings/_post.ts b/pages/api/bookings/_post.ts index 51ee9333d2..23175b1264 100644 --- a/pages/api/bookings/_post.ts +++ b/pages/api/bookings/_post.ts @@ -24,17 +24,17 @@ import { defaultResponder } from "@calcom/lib/server"; * schema: * type: object * required: - * - startTime - * - endTime + * - start + * - end * properties: * title: * type: string * description: 'Booking event title' - * startTime: + * start: * type: string * format: date-time * description: 'Start time of the Event' - * endTime: + * end: * type: string * format: date-time * description: 'End time of the Event' From ccf93190d712c27d8c25f9f1b6c280008715cd8d Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 10 Mar 2023 22:33:09 +0530 Subject: [PATCH 602/658] Swagger docs for webhooks (#245) This PR updates and adds to the swagger documentation for /webhooks endpoint --- pages/api/webhooks/[id]/_delete.ts | 12 ++++++--- pages/api/webhooks/[id]/_get.ts | 12 ++++++--- pages/api/webhooks/[id]/_patch.ts | 37 ++++++++++++++++++++++++--- pages/api/webhooks/_get.ts | 11 ++++++-- pages/api/webhooks/_post.ts | 40 ++++++++++++++++++++++++++++-- 5 files changed, 96 insertions(+), 16 deletions(-) diff --git a/pages/api/webhooks/[id]/_delete.ts b/pages/api/webhooks/[id]/_delete.ts index e0e2979ab0..4750741338 100644 --- a/pages/api/webhooks/[id]/_delete.ts +++ b/pages/api/webhooks/[id]/_delete.ts @@ -17,12 +17,16 @@ import { schemaQueryIdAsString } from "~/lib/validations/shared/queryIdString"; * type: integer * required: true * description: Numeric ID of the hooks to delete - * security: - * - ApiKeyAuth: [] + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * tags: - * - hooks + * - webhooks * externalDocs: - * url: https://docs.cal.com/hooks + * url: https://docs.cal.com/core-features/webhooks * responses: * 201: * description: OK, hook removed successfully diff --git a/pages/api/webhooks/[id]/_get.ts b/pages/api/webhooks/[id]/_get.ts index 216684cc90..3bde62987a 100644 --- a/pages/api/webhooks/[id]/_get.ts +++ b/pages/api/webhooks/[id]/_get.ts @@ -18,12 +18,16 @@ import { schemaWebhookReadPublic } from "~/lib/validations/webhook"; * type: integer * required: true * description: Numeric ID of the webhook to get - * security: - * - ApiKeyAuth: [] + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * tags: - * - hooks + * - webhooks * externalDocs: - * url: https://docs.cal.com/hooks + * url: https://docs.cal.com/core-features/webhooks * responses: * 200: * description: OK diff --git a/pages/api/webhooks/[id]/_patch.ts b/pages/api/webhooks/[id]/_patch.ts index baa53d257a..35c2810f39 100644 --- a/pages/api/webhooks/[id]/_patch.ts +++ b/pages/api/webhooks/[id]/_patch.ts @@ -20,12 +20,41 @@ import { schemaWebhookEditBodyParams, schemaWebhookReadPublic } from "~/lib/vali * type: integer * required: true * description: Numeric ID of the webhook to edit - * security: - * - ApiKeyAuth: [] + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key + * requestBody: + * description: Edit an existing webhook + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * subscriberUrl: + * type: string + * format: uri + * description: The URL to subscribe to this webhook + * eventTriggers: + * type: string + * enum: [BOOKING_CREATED, BOOKING_RESCHEDULED, BOOKING_CANCELLED, MEETING_ENDED] + * description: The events which should trigger this webhook call + * active: + * type: boolean + * description: Whether the webhook is active and should trigger on associated trigger events + * payloadTemplate: + * type: string + * description: The template of the webhook's payload + * eventTypeId: + * type: number + * description: The event type ID if this webhook should be associated with only that event type * tags: - * - hooks + * - webhooks * externalDocs: - * url: https://docs.cal.com/hooks + * url: https://docs.cal.com/core-features/webhooks * responses: * 201: * description: OK, webhook edited successfully diff --git a/pages/api/webhooks/_get.ts b/pages/api/webhooks/_get.ts index 6b00b00e47..8708c303e8 100644 --- a/pages/api/webhooks/_get.ts +++ b/pages/api/webhooks/_get.ts @@ -13,10 +13,17 @@ import { schemaWebhookReadPublic } from "~/lib/validations/webhook"; * get: * summary: Find all webhooks * operationId: listWebhooks + * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * tags: - * - hooks + * - webhooks * externalDocs: - * url: https://docs.cal.com/webhooks + * url: https://docs.cal.com/core-features/webhooks * responses: * 200: * description: OK diff --git a/pages/api/webhooks/_post.ts b/pages/api/webhooks/_post.ts index ab8cc028e3..2a99c903e8 100644 --- a/pages/api/webhooks/_post.ts +++ b/pages/api/webhooks/_post.ts @@ -9,14 +9,50 @@ import { schemaWebhookCreateBodyParams, schemaWebhookReadPublic } from "~/lib/va /** * @swagger - * /hooks: + * /webhooks: * post: * summary: Creates a new webhook * operationId: addWebhook + * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key + * requestBody: + * description: Create a new webhook + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - subscriberUrl + * - eventTriggers + * - active + * properties: + * subscriberUrl: + * type: string + * format: uri + * description: The URL to subscribe to this webhook + * eventTriggers: + * type: string + * enum: [BOOKING_CREATED, BOOKING_RESCHEDULED, BOOKING_CANCELLED, MEETING_ENDED] + * description: The events which should trigger this webhook call + * active: + * type: boolean + * description: Whether the webhook is active and should trigger on associated trigger events + * payloadTemplate: + * type: string + * description: The template of the webhook's payload + * eventTypeId: + * type: number + * description: The event type ID if this webhook should be associated with only that event type * tags: * - webhooks * externalDocs: - * url: https://docs.cal.com/webhooks + * url: https://docs.cal.com/core-features/webhooks * responses: * 201: * description: OK, webhook created From 2da8784865588cde31f185bfeffb98a199633254 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 10 Mar 2023 22:33:27 +0530 Subject: [PATCH 603/658] swagger docs update for selected calendars (#246) Adds swagger doc update for selected calendars API endpoint --- pages/api/selected-calendars/[id]/_delete.ts | 6 ++++ pages/api/selected-calendars/[id]/_get.ts | 6 ++++ pages/api/selected-calendars/[id]/_patch.ts | 6 ++++ pages/api/selected-calendars/_get.ts | 7 ++++ pages/api/selected-calendars/_post.ts | 36 +++++++++++++------- 5 files changed, 49 insertions(+), 12 deletions(-) diff --git a/pages/api/selected-calendars/[id]/_delete.ts b/pages/api/selected-calendars/[id]/_delete.ts index 5cc5e4b015..e04b67f711 100644 --- a/pages/api/selected-calendars/[id]/_delete.ts +++ b/pages/api/selected-calendars/[id]/_delete.ts @@ -11,6 +11,12 @@ import { selectedCalendarIdSchema } from "~/lib/validations/selected-calendar"; * operationId: removeSelectedCalendarById * summary: Remove a selected calendar * parameters: + * - in: query + * name: apiKey + * schema: + * type: string + * required: true + * description: Your API Key * - in: path * name: userId * schema: diff --git a/pages/api/selected-calendars/[id]/_get.ts b/pages/api/selected-calendars/[id]/_get.ts index d164afae97..a5549f1a21 100644 --- a/pages/api/selected-calendars/[id]/_get.ts +++ b/pages/api/selected-calendars/[id]/_get.ts @@ -11,6 +11,12 @@ import { schemaSelectedCalendarPublic, selectedCalendarIdSchema } from "~/lib/va * operationId: getSelectedCalendarById * summary: Find a selected calendar by providing the compoundId(userId_integration_externalId) separated by `_` * parameters: + * - in: query + * name: apiKey + * schema: + * type: string + * required: true + * description: Your API Key * - in: path * name: userId * schema: diff --git a/pages/api/selected-calendars/[id]/_patch.ts b/pages/api/selected-calendars/[id]/_patch.ts index 81b09a95df..c2b526303d 100644 --- a/pages/api/selected-calendars/[id]/_patch.ts +++ b/pages/api/selected-calendars/[id]/_patch.ts @@ -17,6 +17,12 @@ import { * operationId: editSelectedCalendarById * summary: Edit a selected calendar * parameters: + * - in: query + * name: apiKey + * schema: + * type: string + * required: true + * description: Your API Key * - in: path * name: userId * schema: diff --git a/pages/api/selected-calendars/_get.ts b/pages/api/selected-calendars/_get.ts index 2d655f860b..c5e2182adf 100644 --- a/pages/api/selected-calendars/_get.ts +++ b/pages/api/selected-calendars/_get.ts @@ -13,6 +13,13 @@ import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/que * get: * operationId: listSelectedCalendars * summary: Find all selected calendars + * parameters: + * - in: query + * name: apiKey + * schema: + * type: string + * required: true + * description: Your API Key * tags: * - selected-calendars * responses: diff --git a/pages/api/selected-calendars/_post.ts b/pages/api/selected-calendars/_post.ts index a62e0f9884..23b26a76e9 100644 --- a/pages/api/selected-calendars/_post.ts +++ b/pages/api/selected-calendars/_post.ts @@ -12,20 +12,32 @@ import { /** * @swagger * /selected-calendars: - * get: - * operationId: addSelectedCalendars - * summary: Find all selected calendars - * tags: - * - selected-calendars - * responses: - * 200: - * description: OK - * 401: - * description: Authorization information is missing or invalid. - * 404: - * description: No selected calendars were found * post: * summary: Creates a new selected calendar + * parameters: + * - in: query + * name: apiKey + * schema: + * type: string + * required: true + * description: Your API Key + * requestBody: + * description: Create a new selected calendar + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - integration + * - externalId + * properties: + * integration: + * type: string + * description: The integration name + * externalId: + * type: string + * description: The external ID of the integration * tags: * - selected-calendars * responses: From 8fc4eedf5f8b0b36081049c217de17fbe3aa0e35 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 10 Mar 2023 22:33:41 +0530 Subject: [PATCH 604/658] Adds swagger for schedules (#247) This PR updates swagger documentation for the Schedules endpoint --- pages/api/schedules/[id]/_delete.ts | 6 ++++++ pages/api/schedules/[id]/_get.ts | 6 ++++++ pages/api/schedules/[id]/_patch.ts | 20 +++++++++++++++++++ pages/api/schedules/_get.ts | 7 +++++++ pages/api/schedules/_post.ts | 30 +++++++++++++++++++++++++++++ 5 files changed, 69 insertions(+) diff --git a/pages/api/schedules/[id]/_delete.ts b/pages/api/schedules/[id]/_delete.ts index 502ab7b029..e48c76c469 100644 --- a/pages/api/schedules/[id]/_delete.ts +++ b/pages/api/schedules/[id]/_delete.ts @@ -17,6 +17,12 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * type: integer * required: true * description: ID of the schedule to delete + * - in: query + * name: apiKey + * schema: + * type: string + * required: true + * description: Your API Key * tags: * - schedules * responses: diff --git a/pages/api/schedules/[id]/_get.ts b/pages/api/schedules/[id]/_get.ts index 568cedcf57..27502833fd 100644 --- a/pages/api/schedules/[id]/_get.ts +++ b/pages/api/schedules/[id]/_get.ts @@ -18,6 +18,12 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * type: integer * required: true * description: ID of the schedule to get + * - in: query + * name: apiKey + * schema: + * type: string + * required: true + * description: Your API Key * tags: * - schedules * responses: diff --git a/pages/api/schedules/[id]/_patch.ts b/pages/api/schedules/[id]/_patch.ts index e121eafa75..85c67e91c0 100644 --- a/pages/api/schedules/[id]/_patch.ts +++ b/pages/api/schedules/[id]/_patch.ts @@ -20,6 +20,26 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * type: integer * required: true * description: ID of the schedule to edit + * - in: query + * name: apiKey + * schema: + * type: string + * required: true + * description: Your API Key + * requestBody: + * description: Create a new schedule + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * name: + * type: string + * description: Name of the schedule + * timezone: + * type: string + * description: The timezone for this schedule * tags: * - schedules * responses: diff --git a/pages/api/schedules/_get.ts b/pages/api/schedules/_get.ts index d6ca98abd6..4790780835 100644 --- a/pages/api/schedules/_get.ts +++ b/pages/api/schedules/_get.ts @@ -18,6 +18,13 @@ export const schemaUserIds = z * get: * operationId: listSchedules * summary: Find all schedules + * parameters: + * - in: query + * name: apiKey + * schema: + * type: string + * required: true + * description: Your API Key * tags: * - schedules * responses: diff --git a/pages/api/schedules/_post.ts b/pages/api/schedules/_post.ts index 885b3cfa88..892d5c0cef 100644 --- a/pages/api/schedules/_post.ts +++ b/pages/api/schedules/_post.ts @@ -13,6 +13,30 @@ import { schemaCreateScheduleBodyParams, schemaSchedulePublic } from "~/lib/vali * post: * operationId: addSchedule * summary: Creates a new schedule + * parameters: + * - in: query + * name: apiKey + * schema: + * type: string + * required: true + * description: Your API Key + * requestBody: + * description: Create a new schedule + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - name + * - timezone + * properties: + * name: + * type: string + * description: Name of the schedule + * timezone: + * type: string + * description: The timezone for this schedule * tags: * - schedules * responses: @@ -23,6 +47,12 @@ import { schemaCreateScheduleBodyParams, schemaSchedulePublic } from "~/lib/vali * 401: * description: Authorization information is missing or invalid. */ + + +eventType EventType[] +name String +timeZone String? +availability Availability[] async function postHandler(req: NextApiRequest) { const { userId, isAdmin, prisma } = req; const body = schemaCreateScheduleBodyParams.parse(req.body); From 4e24b6f7c050f623f12f66dd5cf15d7f83165cea Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 10 Mar 2023 22:34:14 +0530 Subject: [PATCH 605/658] Swagger/multiple fixes (#248) This PR adds - Swagger fixes for Teams endpoint - Removes unintended remnant from custom input - Swagger fixes for Payments endpoint --- pages/api/custom-inputs/_post.ts | 6 ------ pages/api/payments/[id].ts | 6 ++++++ pages/api/teams/[teamId]/_delete.ts | 6 ++++++ pages/api/teams/[teamId]/_get.ts | 6 ++++++ pages/api/teams/[teamId]/_patch.ts | 20 ++++++++++++++++++++ pages/api/teams/_get.ts | 7 +++++++ pages/api/teams/_post.ts | 24 ++++++++++++++++++++++++ 7 files changed, 69 insertions(+), 6 deletions(-) diff --git a/pages/api/custom-inputs/_post.ts b/pages/api/custom-inputs/_post.ts index 56d15816a4..331fdd732f 100644 --- a/pages/api/custom-inputs/_post.ts +++ b/pages/api/custom-inputs/_post.ts @@ -8,12 +8,6 @@ import { schemaEventTypeCustomInputPublic, } from "~/lib/validations/event-type-custom-input"; -// id: z.number().int(), -// eventTypeId: z.number().int(), -// label: z.string(), -// type: z.nativeEnum(EventTypeCustomInputType), -// required: z.boolean(), -// placeholder: z.string(), /** * @swagger * /custom-inputs: diff --git a/pages/api/payments/[id].ts b/pages/api/payments/[id].ts index 8e3657be6a..f8a54ff7f4 100644 --- a/pages/api/payments/[id].ts +++ b/pages/api/payments/[id].ts @@ -14,6 +14,12 @@ import { * get: * summary: Find a payment * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * - in: path * name: id * schema: diff --git a/pages/api/teams/[teamId]/_delete.ts b/pages/api/teams/[teamId]/_delete.ts index 77e3442705..e81be99974 100644 --- a/pages/api/teams/[teamId]/_delete.ts +++ b/pages/api/teams/[teamId]/_delete.ts @@ -19,6 +19,12 @@ import { checkPermissions } from "./_auth-middleware"; * type: integer * required: true * description: ID of the team to delete + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * tags: * - teams * responses: diff --git a/pages/api/teams/[teamId]/_get.ts b/pages/api/teams/[teamId]/_get.ts index 2c22847418..cff0e987c9 100644 --- a/pages/api/teams/[teamId]/_get.ts +++ b/pages/api/teams/[teamId]/_get.ts @@ -19,6 +19,12 @@ import { schemaTeamReadPublic } from "~/lib/validations/team"; * type: integer * required: true * description: ID of the team to get + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * tags: * - teams * responses: diff --git a/pages/api/teams/[teamId]/_patch.ts b/pages/api/teams/[teamId]/_patch.ts index ddf83e5883..93d1a3a46a 100644 --- a/pages/api/teams/[teamId]/_patch.ts +++ b/pages/api/teams/[teamId]/_patch.ts @@ -24,6 +24,26 @@ import { schemaTeamReadPublic, schemaTeamUpdateBodyParams } from "~/lib/validati * type: integer * required: true * description: ID of the team to edit + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key + * requestBody: + * description: Create a new custom input for an event type + * required: true + * content: + * application/json: + * schema: + * type: object + * properties: + * name: + * type: string + * description: Name of the team + * slug: + * type: string + * description: A unique slug that works as path for the team public page * tags: * - teams * responses: diff --git a/pages/api/teams/_get.ts b/pages/api/teams/_get.ts index ca038fdc18..49af07ac8e 100644 --- a/pages/api/teams/_get.ts +++ b/pages/api/teams/_get.ts @@ -11,6 +11,13 @@ import { schemaTeamsReadPublic } from "~/lib/validations/team"; * get: * operationId: listTeams * summary: Find all teams + * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key * tags: * - teams * responses: diff --git a/pages/api/teams/_post.ts b/pages/api/teams/_post.ts index ef0783e4df..af032d00d4 100644 --- a/pages/api/teams/_post.ts +++ b/pages/api/teams/_post.ts @@ -14,6 +14,30 @@ import { schemaTeamBodyParams, schemaTeamReadPublic } from "~/lib/validations/te * post: * operationId: addTeam * summary: Creates a new team + * parameters: + * - in: query + * name: apiKey + * required: true + * schema: + * type: string + * description: Your API key + * requestBody: + * description: Create a new custom input for an event type + * required: true + * content: + * application/json: + * schema: + * type: object + * required: + * - name + * - slug + * properties: + * name: + * type: string + * description: Name of the team + * slug: + * type: string + * description: A unique slug that works as path for the team public page * tags: * - teams * responses: From 464c283e0c2beaa5e4444b3a6c031ba5510ee1ca Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 10 Mar 2023 12:01:46 -0700 Subject: [PATCH 606/658] Reverts oopsie --- pages/api/schedules/_post.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pages/api/schedules/_post.ts b/pages/api/schedules/_post.ts index 892d5c0cef..03c1fb0b6e 100644 --- a/pages/api/schedules/_post.ts +++ b/pages/api/schedules/_post.ts @@ -47,12 +47,6 @@ import { schemaCreateScheduleBodyParams, schemaSchedulePublic } from "~/lib/vali * 401: * description: Authorization information is missing or invalid. */ - - -eventType EventType[] -name String -timeZone String? -availability Availability[] async function postHandler(req: NextApiRequest) { const { userId, isAdmin, prisma } = req; const body = schemaCreateScheduleBodyParams.parse(req.body); From 870b2df538bc7be37ab90de62cfad1583fb5800d Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Mon, 13 Mar 2023 15:27:00 +0530 Subject: [PATCH 607/658] hotfixes swagger delete path (#250) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit a quick hotfix 🙏 --- pages/api/teams/[teamId]/_delete.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/api/teams/[teamId]/_delete.ts b/pages/api/teams/[teamId]/_delete.ts index e81be99974..13c5c35370 100644 --- a/pages/api/teams/[teamId]/_delete.ts +++ b/pages/api/teams/[teamId]/_delete.ts @@ -8,7 +8,7 @@ import { checkPermissions } from "./_auth-middleware"; /** * @swagger - * /users/{teamId}: + * /teams/{teamId}: * delete: * operationId: removeTeamById * summary: Remove an existing team From cb08bba351113aa29083bee8b880b9e5d74fde31 Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Mon, 13 Mar 2023 12:24:10 +0000 Subject: [PATCH 608/658] Add GET /teams/{id}/event-types endpoint (#251) Allows fetching team event types - GET /event-types only lists the user event types - currently fetching the team event types isn't possible. --- pages/api/teams/[teamId]/event-types/_get.ts | 65 +++++++++++++++++++ pages/api/teams/[teamId]/event-types/index.ts | 9 +++ 2 files changed, 74 insertions(+) create mode 100644 pages/api/teams/[teamId]/event-types/_get.ts create mode 100644 pages/api/teams/[teamId]/event-types/index.ts diff --git a/pages/api/teams/[teamId]/event-types/_get.ts b/pages/api/teams/[teamId]/event-types/_get.ts new file mode 100644 index 0000000000..38d1a6d425 --- /dev/null +++ b/pages/api/teams/[teamId]/event-types/_get.ts @@ -0,0 +1,65 @@ +import type { Prisma } from "@prisma/client"; +import type { NextApiRequest } from "next"; +import { z } from "zod"; + +import { defaultResponder } from "@calcom/lib/server"; + +import { schemaEventTypeReadPublic } from "~/lib/validations/event-type"; + +const querySchema = z.object({ + teamId: z.coerce.number(), +}); + +/** + * @swagger + * /teams/{teamId}/event-types: + * get: + * summary: Find all event types that belong to teamId + * operationId: listEventTypesByTeamId + * parameters: + * - in: query + * name: apiKey + * schema: + * type: string + * required: true + * description: Your API Key + * - in: path + * name: teamId + * schema: + * type: number + * required: true + * tags: + * - event-types + * externalDocs: + * url: https://docs.cal.com/core-features/event-types + * responses: + * 200: + * description: OK + * 401: + * description: Authorization information is missing or invalid. + * 404: + * description: No event types were found + */ +async function getHandler(req: NextApiRequest) { + const { userId, isAdmin, prisma } = req; + + const { teamId } = querySchema.parse(req.query); + + const args: Prisma.EventTypeFindManyArgs = { + where: { + team: isAdmin + ? { + id: teamId, + } + : { + id: teamId, + members: { some: { userId } }, + }, + }, + }; + + const data = await prisma.eventType.findMany(args); + return { event_types: data.map((attendee) => schemaEventTypeReadPublic.parse(attendee)) }; +} + +export default defaultResponder(getHandler); diff --git a/pages/api/teams/[teamId]/event-types/index.ts b/pages/api/teams/[teamId]/event-types/index.ts new file mode 100644 index 0000000000..c53e4b8ef3 --- /dev/null +++ b/pages/api/teams/[teamId]/event-types/index.ts @@ -0,0 +1,9 @@ +import { defaultHandler } from "@calcom/lib/server"; + +import { withMiddleware } from "~/lib/helpers/withMiddleware"; + +export default withMiddleware()( + defaultHandler({ + GET: import("./_get"), + }) +); From 2b9af8457cb4232068c2f196265830340d7997b7 Mon Sep 17 00:00:00 2001 From: zomars Date: Wed, 15 Mar 2023 15:31:39 -0700 Subject: [PATCH 609/658] Updates yarn --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d25af3f814..ef4df645a2 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "@calcom/core": "*", "@calcom/dayjs": "*", "@calcom/emails": "*", - "@calcom/embed-core": "*", + "@calcom/embed-core": "workspace:*", "@calcom/embed-snippet": "*", "@calcom/features": "*", "@calcom/lib": "*", From cb54ab670ea3f8083aca5c9d2753a6fc12b8c74e Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Wed, 15 Mar 2023 23:43:00 +0000 Subject: [PATCH 610/658] Added 'hosts' to POST call, PATCH needs a db migration on web (#239) Complete, but bit of a WIP due to _patch --- lib/validations/event-type.ts | 12 ++++-- pages/api/event-types/[id]/_patch.ts | 36 +++++++++++++++-- pages/api/event-types/_post.ts | 39 +++++++++++++++---- .../_utils/ensureOnlyMembersAsHosts.ts | 21 ++++++++++ 4 files changed, 93 insertions(+), 15 deletions(-) create mode 100644 pages/api/event-types/_utils/ensureOnlyMembersAsHosts.ts diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 579793a446..37db4637eb 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -1,6 +1,6 @@ import { z } from "zod"; -import { _EventTypeModel as EventType } from "@calcom/prisma/zod"; +import { _EventTypeModel as EventType, _HostModel } from "@calcom/prisma/zod"; import { customInputSchema } from "@calcom/prisma/zod-utils"; import { Frequency } from "~/lib/types"; @@ -18,6 +18,11 @@ const recurringEventInputSchema = z.object({ tzid: timeZone.optional(), }); +const hostSchema = _HostModel.pick({ + isFixed: true, + userId: true, +}); + export const schemaEventTypeBaseBodyParams = EventType.pick({ title: true, description: true, @@ -25,11 +30,11 @@ export const schemaEventTypeBaseBodyParams = EventType.pick({ length: true, hidden: true, position: true, - teamId: true, eventName: true, timeZone: true, periodType: true, periodStartDate: true, + schedulingType: true, periodEndDate: true, periodDays: true, periodCountCalendarDays: true, @@ -39,13 +44,14 @@ export const schemaEventTypeBaseBodyParams = EventType.pick({ minimumBookingNotice: true, beforeEventBuffer: true, afterEventBuffer: true, - schedulingType: true, + teamId: true, price: true, currency: true, slotInterval: true, successRedirectUrl: true, locations: true, }) + .merge(z.object({ hosts: z.array(hostSchema).optional().default([]) })) .partial() .strict(); diff --git a/pages/api/event-types/[id]/_patch.ts b/pages/api/event-types/[id]/_patch.ts index 57662a623e..d44908b2b1 100644 --- a/pages/api/event-types/[id]/_patch.ts +++ b/pages/api/event-types/[id]/_patch.ts @@ -1,3 +1,5 @@ +import type { Prisma } from "@prisma/client"; +import { SchedulingType } from "@prisma/client"; import type { NextApiRequest } from "next"; import type { z } from "zod"; @@ -7,6 +9,7 @@ import { defaultResponder } from "@calcom/lib/server"; import type { schemaEventTypeBaseBodyParams } from "~/lib/validations/event-type"; import { schemaEventTypeEditBodyParams, schemaEventTypeReadPublic } from "~/lib/validations/event-type"; import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt"; +import ensureOnlyMembersAsHosts from "~/pages/api/event-types/_utils/ensureOnlyMembersAsHosts"; import checkTeamEventEditPermission from "../_utils/checkTeamEventEditPermission"; @@ -49,6 +52,16 @@ import checkTeamEventEditPermission from "../_utils/checkTeamEventEditPermission * slug: * type: string * description: Unique slug for the event type + * hosts: + * type: array + * items: + * type: object + * properties: + * userId: + * type: number + * isFixed: + * type: boolean + * description: Host MUST be available for any slot to be bookable. * hidden: * type: boolean * description: If the event type should be hidden from your public booking page @@ -156,10 +169,25 @@ import checkTeamEventEditPermission from "../_utils/checkTeamEventEditPermission export async function patchHandler(req: NextApiRequest) { const { prisma, query, body } = req; const { id } = schemaQueryIdParseInt.parse(query); - const data = schemaEventTypeEditBodyParams.parse(body); - await checkPermissions(req, body); - const event_type = await prisma.eventType.update({ where: { id }, data }); - return { event_type: schemaEventTypeReadPublic.parse(event_type) }; + const { hosts = [], ...parsedBody } = schemaEventTypeEditBodyParams.parse(body); + + const data: Prisma.EventTypeUpdateArgs["data"] = { + ...parsedBody, + }; + + if (hosts) { + await ensureOnlyMembersAsHosts(req, parsedBody); + data.hosts = { + deleteMany: {}, + create: hosts.map((host) => ({ + ...host, + isFixed: data.schedulingType === SchedulingType.COLLECTIVE || host.isFixed, + })), + }; + } + await checkPermissions(req, parsedBody); + const eventType = await prisma.eventType.update({ where: { id }, data }); + return { event_type: schemaEventTypeReadPublic.parse(eventType) }; } async function checkPermissions(req: NextApiRequest, body: z.infer) { diff --git a/pages/api/event-types/_post.ts b/pages/api/event-types/_post.ts index 28be45e2f5..687f4f220c 100644 --- a/pages/api/event-types/_post.ts +++ b/pages/api/event-types/_post.ts @@ -7,6 +7,7 @@ import { defaultResponder } from "@calcom/lib/server"; import { schemaEventTypeCreateBodyParams, schemaEventTypeReadPublic } from "~/lib/validations/event-type"; import checkTeamEventEditPermission from "./_utils/checkTeamEventEditPermission"; +import ensureOnlyMembersAsHosts from "./_utils/ensureOnlyMembersAsHosts"; /** * @swagger @@ -46,6 +47,17 @@ import checkTeamEventEditPermission from "./_utils/checkTeamEventEditPermission" * slug: * type: string * description: Unique slug for the event type + * example: my-event + * hosts: + * type: array + * items: + * type: object + * properties: + * userId: + * type: number + * isFixed: + * type: boolean + * description: Host MUST be available for any slot to be bookable. * hidden: * type: boolean * description: If the event type should be hidden from your public booking page @@ -176,22 +188,33 @@ import checkTeamEventEditPermission from "./_utils/checkTeamEventEditPermission" * description: Authorization information is missing or invalid. */ async function postHandler(req: NextApiRequest) { - const { userId, isAdmin, prisma } = req; - const body = schemaEventTypeCreateBodyParams.parse(req.body); - let args: Prisma.EventTypeCreateArgs = { - data: { ...body, userId, users: { connect: { id: userId } } }, + const { userId, isAdmin, prisma, body } = req; + + const { hosts = [], ...parsedBody } = schemaEventTypeCreateBodyParams.parse(body || {}); + + let data: Prisma.EventTypeCreateArgs["data"] = { + ...parsedBody, + userId, + users: { connect: { id: userId } }, }; await checkPermissions(req); - if (isAdmin && body.userId) args = { data: { ...body, users: { connect: { id: body.userId } } } }; + if (isAdmin && parsedBody.userId) { + data = { ...parsedBody, users: { connect: { id: parsedBody.userId } } }; + } - await checkTeamEventEditPermission(req, body); + await checkTeamEventEditPermission(req, parsedBody); + await ensureOnlyMembersAsHosts(req, parsedBody); - const data = await prisma.eventType.create(args); + if (hosts) { + data.hosts = { createMany: { data: hosts } }; + } + + const eventType = await prisma.eventType.create({ data }); return { - event_type: schemaEventTypeReadPublic.parse(data), + event_type: schemaEventTypeReadPublic.parse(eventType), message: "Event type created successfully", }; } diff --git a/pages/api/event-types/_utils/ensureOnlyMembersAsHosts.ts b/pages/api/event-types/_utils/ensureOnlyMembersAsHosts.ts new file mode 100644 index 0000000000..301c5307a1 --- /dev/null +++ b/pages/api/event-types/_utils/ensureOnlyMembersAsHosts.ts @@ -0,0 +1,21 @@ +import type { NextApiRequest } from "next"; +import type { z } from "zod"; + +import type { schemaEventTypeCreateBodyParams } from "~/lib/validations/event-type"; + +export default async function ensureOnlyMembersAsHosts( + req: NextApiRequest, + body: Pick, "hosts" | "teamId"> +) { + if (body.teamId && body.hosts && body.hosts.length > 0) { + const teamMemberCount = await req.prisma.membership.count({ + where: { + teamId: body.teamId, + userId: { in: body.hosts.map((host) => host.userId) }, + }, + }); + if (teamMemberCount !== body.hosts.length) { + throw new Error("You can only add members of the team to a team event type."); + } + } +} From 945ab355a541658eca0ef40199c8418e9749e33e Mon Sep 17 00:00:00 2001 From: Nafees Nazik <84864519+G3root@users.noreply.github.com> Date: Fri, 17 Mar 2023 13:57:18 +0530 Subject: [PATCH 611/658] feat: return cal link in event-types query (#244) Co-authored-by: Hariom Balhara --- lib/validations/event-type.ts | 1 + pages/api/event-types/[id]/_get.ts | 17 ++++++++++++-- pages/api/event-types/_get.ts | 26 +++++++++++++++++----- pages/api/event-types/_utils/getCalLink.ts | 16 +++++++++++++ 4 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 pages/api/event-types/_utils/getCalLink.ts diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 37db4637eb..a84305736b 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -130,5 +130,6 @@ export const schemaEventTypeReadPublic = EventType.pick({ .nullable(), metadata: jsonSchema.nullable(), customInputs: customInputSchema.array().optional(), + link: z.string().optional(), }) ); diff --git a/pages/api/event-types/[id]/_get.ts b/pages/api/event-types/[id]/_get.ts index 58046dedcd..74d9d14456 100644 --- a/pages/api/event-types/[id]/_get.ts +++ b/pages/api/event-types/[id]/_get.ts @@ -5,6 +5,8 @@ import { defaultResponder } from "@calcom/lib/server"; import { schemaEventTypeReadPublic } from "~/lib/validations/event-type"; import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransformParseInt"; +import getCalLink from "../_utils/getCalLink"; + /** * @swagger * /event-types/{id}: @@ -40,8 +42,19 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform export async function getHandler(req: NextApiRequest) { const { prisma, query } = req; const { id } = schemaQueryIdParseInt.parse(query); - const event_type = await prisma.eventType.findUnique({ where: { id }, include: { customInputs: true } }); - return { event_type: schemaEventTypeReadPublic.parse(event_type) }; + const event_type = await prisma.eventType.findUnique({ + where: { id }, + include: { + customInputs: true, + team: { select: { slug: true } }, + users: true, + owner: { select: { username: true, id: true } }, + }, + }); + + const link = event_type ? getCalLink(event_type) : null; + + return { event_type: schemaEventTypeReadPublic.parse({ ...event_type, link }) }; } export default defaultResponder(getHandler); diff --git a/pages/api/event-types/_get.ts b/pages/api/event-types/_get.ts index 0f5810a774..acdfdc4dee 100644 --- a/pages/api/event-types/_get.ts +++ b/pages/api/event-types/_get.ts @@ -7,6 +7,8 @@ import { defaultResponder } from "@calcom/lib/server"; import { schemaEventTypeReadPublic } from "~/lib/validations/event-type"; import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/queryUserId"; +import getCalLink from "./_utils/getCalLink"; + /** * @swagger * /event-types: @@ -34,9 +36,10 @@ import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/que */ async function getHandler(req: NextApiRequest) { const { userId, isAdmin, prisma } = req; - const args: Prisma.EventTypeFindManyArgs = isAdmin - ? {} - : { where: { userId }, include: { customInputs: true } }; + + const args: Prisma.EventTypeFindManyArgs = { + where: { userId }, + }; /** Only admins can query other users */ if (!isAdmin && req.query.userId) throw new HttpError({ statusCode: 401, message: "ADMIN required" }); if (isAdmin && req.query.userId) { @@ -44,8 +47,21 @@ async function getHandler(req: NextApiRequest) { const userIds = Array.isArray(query.userId) ? query.userId : [query.userId || userId]; args.where = { userId: { in: userIds } }; } - const data = await prisma.eventType.findMany(args); - return { event_types: data.map((attendee) => schemaEventTypeReadPublic.parse(attendee)) }; + const data = await prisma.eventType.findMany({ + ...args, + include: { + customInputs: true, + team: { select: { slug: true } }, + users: true, + owner: { select: { username: true, id: true } }, + }, + }); + return { + event_types: data.map((eventType) => { + const link = getCalLink(eventType); + return schemaEventTypeReadPublic.parse({ ...eventType, link }); + }), + }; } export default defaultResponder(getHandler); diff --git a/pages/api/event-types/_utils/getCalLink.ts b/pages/api/event-types/_utils/getCalLink.ts new file mode 100644 index 0000000000..5c46575585 --- /dev/null +++ b/pages/api/event-types/_utils/getCalLink.ts @@ -0,0 +1,16 @@ +import { CAL_URL } from "@calcom/lib/constants"; + +export default function getCalLink(eventType: { + team?: { slug: string | null } | null; + owner: { username: string | null } | null; + users?: { username: string | null }[]; + slug: string; +}) { + return `${CAL_URL}/${ + eventType?.team + ? `team/${eventType?.team?.slug}` + : eventType?.owner + ? eventType.owner.username + : eventType?.users?.[0]?.username + }/${eventType?.slug}`; +} From 8aa004c34a722c40cf5a9d1074e5e6592196b3e8 Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 17 Mar 2023 16:57:23 -0700 Subject: [PATCH 612/658] Syncs with monorepo --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ef4df645a2..724e8566d6 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "@calcom/dayjs": "*", "@calcom/emails": "*", "@calcom/embed-core": "workspace:*", - "@calcom/embed-snippet": "*", + "@calcom/embed-snippet": "workspace:*", "@calcom/features": "*", "@calcom/lib": "*", "@calcom/prisma": "*", From 386ad87e641b2424ccd1df0cb7c69e38b80ac8c0 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Tue, 21 Mar 2023 23:02:48 +0530 Subject: [PATCH 613/658] Event type swagger update for location type (#252) Updates Location Type documentation in swagger for event type _post and _patch --- pages/api/event-types/[id]/_patch.ts | 32 +++++++++++++++++++++++++++- pages/api/event-types/_post.ts | 32 +++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/pages/api/event-types/[id]/_patch.ts b/pages/api/event-types/[id]/_patch.ts index d44908b2b1..83bdf156ad 100644 --- a/pages/api/event-types/[id]/_patch.ts +++ b/pages/api/event-types/[id]/_patch.ts @@ -147,7 +147,37 @@ import checkTeamEventEditPermission from "../_utils/checkTeamEventEditPermission * type: array * description: A list of all available locations for the event type * items: - * type: object + * type: array + * items: + * oneOf: + * - type: object + * properties: + * type: + * type: string + * enum: ['integrations:daily'] + * - type: object + * properties: + * type: + * type: string + * enum: ['attendeeInPerson'] + * - type: object + * properties: + * type: + * type: string + * enum: ['inPerson'] + * address: + * type: string + * displayLocationPublicly: + * type: boolean + * - type: object + * properties: + * type: + * type: string + * enum: ['link'] + * link: + * type: string + * displayLocationPublicly: + * type: boolean * example: * event-type: * summary: An example of event type PATCH request diff --git a/pages/api/event-types/_post.ts b/pages/api/event-types/_post.ts index 687f4f220c..488a15e6b9 100644 --- a/pages/api/event-types/_post.ts +++ b/pages/api/event-types/_post.ts @@ -137,7 +137,37 @@ import ensureOnlyMembersAsHosts from "./_utils/ensureOnlyMembersAsHosts"; * type: array * description: A list of all available locations for the event type * items: - * type: object + * type: array + * items: + * oneOf: + * - type: object + * properties: + * type: + * type: string + * enum: ['integrations:daily'] + * - type: object + * properties: + * type: + * type: string + * enum: ['attendeeInPerson'] + * - type: object + * properties: + * type: + * type: string + * enum: ['inPerson'] + * address: + * type: string + * displayLocationPublicly: + * type: boolean + * - type: object + * properties: + * type: + * type: string + * enum: ['link'] + * link: + * type: string + * displayLocationPublicly: + * type: boolean * example: * event-type: * summary: An example of event type POST request From fab5eb948cf32992dde0dc85ef09e2b09246bb60 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed, 12 Apr 2023 20:46:19 +0530 Subject: [PATCH 614/658] Update /booking _post.ts to have eventTypeId as required (#254) Update` /booking` `_post.ts` to have - eventTypeId as a required field - example for request body - Updated schema that represents actual usage --- pages/api/bookings/_post.ts | 73 ++++++++++++++++++++++++++----------- 1 file changed, 52 insertions(+), 21 deletions(-) diff --git a/pages/api/bookings/_post.ts b/pages/api/bookings/_post.ts index 23175b1264..3f9c17978d 100644 --- a/pages/api/bookings/_post.ts +++ b/pages/api/bookings/_post.ts @@ -24,12 +24,20 @@ import { defaultResponder } from "@calcom/lib/server"; * schema: * type: object * required: + * - eventTypeId * - start * - end + * - name + * - email + * - timeZone + * - language + * - metadata + * - customInputs + * - location * properties: - * title: - * type: string - * description: 'Booking event title' + * eventTypeId: + * type: integer + * description: 'ID of the event type to book' * start: * type: string * format: date-time @@ -38,6 +46,32 @@ import { defaultResponder } from "@calcom/lib/server"; * type: string * format: date-time * description: 'End time of the Event' + * name: + * type: string + * description: 'Name of the Attendee' + * email: + * type: string + * format: email + * description: 'Email ID of the Attendee' + * timeZone: + * type: string + * description: 'TimeZone of the Attendee' + * language: + * type: string + * description: 'Language of the Attendee' + * metadata: + * type: object + * properties: {} + * description: 'Any metadata associated with the booking' + * customInputs: + * type: array + * items: {} + * location: + * type: string + * description: 'Meeting location' + * title: + * type: string + * description: 'Booking event title' * recurringEventId: * type: integer * description: 'Recurring event ID if the event is recurring' @@ -47,9 +81,6 @@ import { defaultResponder } from "@calcom/lib/server"; * status: * type: string * description: 'Acceptable values one of ["ACCEPTED", "PENDING", "CANCELLED", "REJECTED"]' - * location: - * type: string - * description: 'Meeting location' * seatsPerTimeSlot: * type: integer * description: 'The number of seats for each time slot' @@ -59,21 +90,21 @@ import { defaultResponder } from "@calcom/lib/server"; * smsReminderNumber: * type: number * description: 'SMS reminder number' - * attendees: - * type: array - * description: 'List of attendees of the booking' - * items: - * type: object - * properties: - * name: - * type: string - * email: - * type: string - * format: email - * timeZone: - * type: string - * locale: - * type: string + * examples: + * New Booking example: + * value: + * { + * "eventTypeId": 1, + * "start": "2023-05-01T14:00:00Z", + * "end": "2023-05-01T15:00:00Z", + * "name": "John Doe", + * "email": "john.doe@example.com", + * "timeZone": "America/New_York", + * "language": "en-US", + * "metadata": {}, + * "customInputs": [], + * "location": "Conference Room A" + * } * * tags: * - bookings From 9654677664afba717116a8388263adedde257cb5 Mon Sep 17 00:00:00 2001 From: zomars Date: Thu, 13 Apr 2023 11:11:54 -0700 Subject: [PATCH 615/658] Removed embeds from API as they trigger unused build scripts --- next.config.js | 2 -- package.json | 2 -- 2 files changed, 4 deletions(-) diff --git a/next.config.js b/next.config.js index 0c9da3ba5b..2dc79b35b2 100644 --- a/next.config.js +++ b/next.config.js @@ -6,8 +6,6 @@ module.exports = withAxiom({ "@calcom/core", "@calcom/dayjs", "@calcom/emails", - "@calcom/embed-core", - "@calcom/embed-snippet", "@calcom/features", "@calcom/lib", "@calcom/prisma", diff --git a/package.json b/package.json index 724e8566d6..115a0e3d1c 100644 --- a/package.json +++ b/package.json @@ -29,8 +29,6 @@ "@calcom/core": "*", "@calcom/dayjs": "*", "@calcom/emails": "*", - "@calcom/embed-core": "workspace:*", - "@calcom/embed-snippet": "workspace:*", "@calcom/features": "*", "@calcom/lib": "*", "@calcom/prisma": "*", From 0d1ad23c57455dae58fdc1e1a9624199da1de316 Mon Sep 17 00:00:00 2001 From: Hariom Balhara Date: Tue, 18 Apr 2023 19:17:29 +0530 Subject: [PATCH 616/658] API Support: Manage Booking Questions and responses (#253) Works with https://github.com/calcom/cal.com/pull/8115 --- lib/validations/booking.ts | 3 +++ lib/validations/event-type.ts | 5 ++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/validations/booking.ts b/lib/validations/booking.ts index b43c2c8ac9..53da5396aa 100644 --- a/lib/validations/booking.ts +++ b/lib/validations/booking.ts @@ -23,6 +23,8 @@ const schemaBookingEditParams = z title: z.string().optional(), startTime: iso8601.optional(), endTime: iso8601.optional(), + // Not supporting responses in edit as that might require re-triggering emails + // responses }) .strict(); @@ -61,4 +63,5 @@ export const schemaBookingReadPublic = Booking.extend({ user: true, metadata: true, status: true, + responses: true, }); diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index a84305736b..5f3f4f2f02 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -1,7 +1,7 @@ import { z } from "zod"; import { _EventTypeModel as EventType, _HostModel } from "@calcom/prisma/zod"; -import { customInputSchema } from "@calcom/prisma/zod-utils"; +import { customInputSchema, eventTypeBookingFields } from "@calcom/prisma/zod-utils"; import { Frequency } from "~/lib/types"; @@ -65,6 +65,7 @@ const schemaEventTypeCreateParams = z recurringEvent: recurringEventInputSchema.optional(), seatsPerTimeSlot: z.number().optional(), seatsShowAttendees: z.boolean().optional(), + bookingFields: eventTypeBookingFields, }) .strict(); @@ -79,6 +80,7 @@ const schemaEventTypeEditParams = z length: z.number().int().optional(), seatsPerTimeSlot: z.number().optional(), seatsShowAttendees: z.boolean().optional(), + bookingFields: eventTypeBookingFields, }) .strict(); @@ -116,6 +118,7 @@ export const schemaEventTypeReadPublic = EventType.pick({ metadata: true, seatsPerTimeSlot: true, seatsShowAttendees: true, + bookingFields: true, }).merge( z.object({ locations: z From d5db1e417129ba6dacc0e5fd04814430dbde2031 Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Wed, 19 Apr 2023 16:28:05 +0530 Subject: [PATCH 617/658] Swagger/booking req resp body (#256) --- pages/api/bookings/[id]/_get.ts | 24 ++++++++- pages/api/bookings/[id]/_patch.ts | 30 ++++++++++- pages/api/bookings/_get.ts | 28 +++++++++- pages/api/bookings/_post.ts | 87 +++++++++++++++++++++++++------ 4 files changed, 150 insertions(+), 19 deletions(-) diff --git a/pages/api/bookings/[id]/_get.ts b/pages/api/bookings/[id]/_get.ts index 2d6ae07a64..5064ba2d78 100644 --- a/pages/api/bookings/[id]/_get.ts +++ b/pages/api/bookings/[id]/_get.ts @@ -32,7 +32,29 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * content: * application/json: * schema: - * $ref: "#/components/schemas/Booking" + * $ref: "#/components/schemas/ArrayOfBookings" + * examples: + * bookings: + * value: [ + * { + * "id": 1, + * "description": "Meeting with John", + * "eventTypeId": 2, + * "uid": "a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8", + * "title": "Business Meeting", + * "startTime": "2023-04-20T10:00:00.000Z", + * "endTime": "2023-04-20T11:00:00.000Z", + * "timeZone": "Europe/London", + * "attendees": [ + * { + * "email": "example@cal.com", + * "name": "John Doe", + * "timeZone": "Europe/London", + * "locale": "en" + * } + * ] + * } + * ] * 401: * description: Authorization information is missing or invalid. * 404: diff --git a/pages/api/bookings/[id]/_patch.ts b/pages/api/bookings/[id]/_patch.ts index 8c1638e2a4..74999ab13c 100644 --- a/pages/api/bookings/[id]/_patch.ts +++ b/pages/api/bookings/[id]/_patch.ts @@ -35,6 +35,15 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * status: * type: string * description: 'Acceptable values one of ["ACCEPTED", "PENDING", "CANCELLED", "REJECTED"]' + * examples: + * editBooking: + * value: + * { + * "title": "Debugging between Syed Ali Shahbaz and Hello Hello", + * "start": "2023-05-24T13:00:00.000Z", + * "end": "2023-05-24T13:30:00.000Z", + * "status": "CANCELLED" + * } * * parameters: * - in: query @@ -52,8 +61,27 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * tags: * - bookings * responses: - * 201: + * 200: * description: OK, booking edited successfully + * content: + * application/json: + * examples: + * bookings: + * value: + * { + * "booking": { + * "id": 11223344, + * "userId": 182, + * "description": null, + * "eventTypeId": 2323232, + * "uid": "stoSJtnh83PEL4rZmqdHe2", + * "title": "Debugging between Syed Ali Shahbaz and Hello Hello", + * "startTime": "2023-05-24T13:00:00.000Z", + * "endTime": "2023-05-24T13:30:00.000Z", + * "metadata": {}, + * "status": "CANCELLED" + * } + * } * 400: * description: Bad request. Booking body is invalid. * 401: diff --git a/pages/api/bookings/_get.ts b/pages/api/bookings/_get.ts index e610f42103..006b39472e 100644 --- a/pages/api/bookings/_get.ts +++ b/pages/api/bookings/_get.ts @@ -19,15 +19,18 @@ import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/que * schema: * type: string * description: Your API key + * example: 123456789abcdefgh * - in: query * name: userId * required: false * schema: * oneOf: * - type: integer + * example: 1 * - type: array * items: * type: integer + * example: [2, 3, 4] * operationId: listBookings * tags: * - bookings @@ -38,11 +41,34 @@ import { schemaQuerySingleOrMultipleUserIds } from "~/lib/validations/shared/que * application/json: * schema: * $ref: "#/components/schemas/ArrayOfBookings" + * examples: + * bookings: + * value: [ + * { + * "id": 1, + * "description": "Meeting with John", + * "eventTypeId": 2, + * "uid": "a1b2c3d4-e5f6-7890-g1h2-i3j4k5l6m7n8", + * "title": "Business Meeting", + * "startTime": "2023-04-20T10:00:00.000Z", + * "endTime": "2023-04-20T11:00:00.000Z", + * "timeZone": "Europe/London", + * "attendees": [ + * { + * "email": "example@cal.com", + * "name": "John Doe", + * "timeZone": "Europe/London", + * "locale": "en" + * } + * ] + * } + * ] * 401: - * description: Authorization information is missing or invalid. + * description: Authorization information is missing or invalid. * 404: * description: No bookings were found */ + async function handler(req: NextApiRequest) { const { userId, isAdmin, prisma } = req; const args: Prisma.BookingFindManyArgs = {}; diff --git a/pages/api/bookings/_post.ts b/pages/api/bookings/_post.ts index 3f9c17978d..d6baaa4891 100644 --- a/pages/api/bookings/_post.ts +++ b/pages/api/bookings/_post.ts @@ -90,27 +90,82 @@ import { defaultResponder } from "@calcom/lib/server"; * smsReminderNumber: * type: number * description: 'SMS reminder number' - * examples: - * New Booking example: - * value: - * { - * "eventTypeId": 1, - * "start": "2023-05-01T14:00:00Z", - * "end": "2023-05-01T15:00:00Z", - * "name": "John Doe", - * "email": "john.doe@example.com", - * "timeZone": "America/New_York", - * "language": "en-US", - * "metadata": {}, - * "customInputs": [], - * "location": "Conference Room A" - * } + * examples: + * New Booking example: + * value: + * { + * "eventTypeId": 2323232, + * "start": "2023-05-24T13:00:00.000Z", + * "end": "2023-05-24T13:30:00.000Z", + * "name": "Hello Hello", + * "email": "hello@gmail.com", + * "timeZone": "Europe/London", + * "language": "en", + * "metadata": {}, + * "customInputs": [], + * "location": "Calcom HQ", + * "title": "Debugging between Syed Ali Shahbaz and Hello Hello", + * "description": null, + * "status": "PENDING", + * "smsReminderNumber": null + * } * * tags: * - bookings * responses: - * 201: + * 200: * description: Booking(s) created successfully. + * content: + * application/json: + * examples: + * bookings: + * value: + * { + * "id": 11223344, + * "uid": "5yUjmAYTDF6MXo98re8SkX", + * "userId": 123, + * "eventTypeId": 2323232, + * "title": "Debugging between Syed Ali Shahbaz and Hello Hello", + * "description": null, + * "customInputs": {}, + * "responses": null, + * "startTime": "2023-05-24T13:00:00.000Z", + * "endTime": "2023-05-24T13:30:00.000Z", + * "location": "Calcom HQ", + * "createdAt": "2023-04-19T10:17:58.580Z", + * "updatedAt": null, + * "status": "PENDING", + * "paid": false, + * "destinationCalendarId": 2180, + * "cancellationReason": null, + * "rejectionReason": null, + * "dynamicEventSlugRef": null, + * "dynamicGroupSlugRef": null, + * "rescheduled": null, + * "fromReschedule": null, + * "recurringEventId": null, + * "smsReminderNumber": null, + * "scheduledJobs": [], + * "metadata": {}, + * "isRecorded": false, + * "user": { + * "email": "test@cal.com", + * "name": "Syed Ali Shahbaz", + * "timeZone": "Asia/Calcutta" + * }, + * "attendees": [ + * { + * "id": 12345, + * "email": "hello@gmail.com", + * "name": "Hello Hello", + * "timeZone": "Europe/London", + * "locale": "en", + * "bookingId": 11223344 + * } + * ], + * "payment": [], + * "references": [] + * } * 400: * description: | * Bad request From 38987b77bb82089edf869dfc3b09e1e96625192a Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Thu, 20 Apr 2023 00:52:07 +0530 Subject: [PATCH 618/658] Swagger/schedules request and response examples (#257) This PR adds request body and response body examples to swagger in /schedules endpoint Added for: - [x] `/schedules/_post` - [x] `/schedules/_get` - [x] `/schedules/[id]/_get` - [x] `/schedules/[id]/_post` - [x] `/schedules/[id]/_patch` --- pages/api/schedules/[id]/_get.ts | 37 +++++++++++++++++++++++++++ pages/api/schedules/[id]/_patch.ts | 36 ++++++++++++++++++++++++--- pages/api/schedules/_get.ts | 40 ++++++++++++++++++++++++++++++ pages/api/schedules/_post.ts | 39 ++++++++++++++++++++++++++--- 4 files changed, 145 insertions(+), 7 deletions(-) diff --git a/pages/api/schedules/[id]/_get.ts b/pages/api/schedules/[id]/_get.ts index 27502833fd..fdadce2cba 100644 --- a/pages/api/schedules/[id]/_get.ts +++ b/pages/api/schedules/[id]/_get.ts @@ -29,11 +29,48 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * responses: * 200: * description: OK + * content: + * application/json: + * examples: + * schedule: + * value: + * { + * "schedule": { + * "id": 12345, + * "userId": 182, + * "name": "Sample Schedule", + * "timeZone": "Asia/Calcutta", + * "availability": [ + * { + * "id": 111, + * "eventTypeId": null, + * "days": [0, 1, 2, 3, 4, 6], + * "startTime": "00:00:00", + * "endTime": "23:45:00" + * }, + * { + * "id": 112, + * "eventTypeId": null, + * "days": [5], + * "startTime": "00:00:00", + * "endTime": "12:00:00" + * }, + * { + * "id": 113, + * "eventTypeId": null, + * "days": [5], + * "startTime": "15:00:00", + * "endTime": "23:45:00" + * } + * ] + * } + * } * 401: * description: Authorization information is missing or invalid. * 404: * description: Schedule was not found */ + export async function getHandler(req: NextApiRequest) { const { prisma, query } = req; const { id } = schemaQueryIdParseInt.parse(query); diff --git a/pages/api/schedules/[id]/_patch.ts b/pages/api/schedules/[id]/_patch.ts index 85c67e91c0..1c8f52d688 100644 --- a/pages/api/schedules/[id]/_patch.ts +++ b/pages/api/schedules/[id]/_patch.ts @@ -27,7 +27,7 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * required: true * description: Your API Key * requestBody: - * description: Create a new schedule + * description: Edit an existing schedule * required: true * content: * application/json: @@ -37,19 +37,49 @@ import { schemaQueryIdParseInt } from "~/lib/validations/shared/queryIdTransform * name: * type: string * description: Name of the schedule - * timezone: + * timeZone: * type: string * description: The timezone for this schedule + * examples: + * schedule: + * value: + * { + * "name": "Updated Schedule", + * "timeZone": "Asia/Calcutta" + * } * tags: * - schedules * responses: - * 201: + * 200: * description: OK, schedule edited successfully + * content: + * application/json: + * examples: + * schedule: + * value: + * { + * "schedule": { + * "id": 12345, + * "userId": 1, + * "name": "Total Testing Part 2", + * "timeZone": "Asia/Calcutta", + * "availability": [ + * { + * "id": 4567, + * "eventTypeId": null, + * "days": [1, 2, 3, 4, 5], + * "startTime": "09:00:00", + * "endTime": "17:00:00" + * } + * ] + * } + * } * 400: * description: Bad request. Schedule body is invalid. * 401: * description: Authorization information is missing or invalid. */ + export async function patchHandler(req: NextApiRequest) { const { prisma, query } = req; const { id } = schemaQueryIdParseInt.parse(query); diff --git a/pages/api/schedules/_get.ts b/pages/api/schedules/_get.ts index 4790780835..1b06a116e9 100644 --- a/pages/api/schedules/_get.ts +++ b/pages/api/schedules/_get.ts @@ -30,11 +30,51 @@ export const schemaUserIds = z * responses: * 200: * description: OK + * content: + * application/json: + * examples: + * schedules: + * value: + * { + * "schedules": [ + * { + * "id": 1234, + * "userId": 5678, + * "name": "Sample Schedule 1", + * "timeZone": "America/Chicago", + * "availability": [ + * { + * "id": 987, + * "eventTypeId": null, + * "days": [1, 2, 3, 4, 5], + * "startTime": "09:00:00", + * "endTime": "23:00:00" + * } + * ] + * }, + * { + * "id": 2345, + * "userId": 6789, + * "name": "Sample Schedule 2", + * "timeZone": "Europe/Amsterdam", + * "availability": [ + * { + * "id": 876, + * "eventTypeId": null, + * "days": [1, 2, 3, 4, 5], + * "startTime": "09:00:00", + * "endTime": "17:00:00" + * } + * ] + * } + * ] + * } * 401: * description: Authorization information is missing or invalid. * 404: * description: No schedules were found */ + async function handler(req: NextApiRequest) { const { prisma, userId, isAdmin } = req; const args: Prisma.ScheduleFindManyArgs = isAdmin ? {} : { where: { userId } }; diff --git a/pages/api/schedules/_post.ts b/pages/api/schedules/_post.ts index 03c1fb0b6e..a50f2cd5b6 100644 --- a/pages/api/schedules/_post.ts +++ b/pages/api/schedules/_post.ts @@ -29,24 +29,55 @@ import { schemaCreateScheduleBodyParams, schemaSchedulePublic } from "~/lib/vali * type: object * required: * - name - * - timezone + * - timeZone * properties: * name: * type: string * description: Name of the schedule - * timezone: + * timeZone: * type: string - * description: The timezone for this schedule + * description: The timeZone for this schedule + * examples: + * schedule: + * value: + * { + * "name": "Sample Schedule", + * "timeZone": "Asia/Calcutta" + * } * tags: * - schedules * responses: - * 201: + * 200: * description: OK, schedule created + * content: + * application/json: + * examples: + * schedule: + * value: + * { + * "schedule": { + * "id": 79471, + * "userId": 182, + * "name": "Total Testing", + * "timeZone": "Asia/Calcutta", + * "availability": [ + * { + * "id": 337917, + * "eventTypeId": null, + * "days": [1, 2, 3, 4, 5], + * "startTime": "09:00:00", + * "endTime": "17:00:00" + * } + * ] + * }, + * "message": "Schedule created successfully" + * } * 400: * description: Bad request. Schedule body is invalid. * 401: * description: Authorization information is missing or invalid. */ + async function postHandler(req: NextApiRequest) { const { userId, isAdmin, prisma } = req; const body = schemaCreateScheduleBodyParams.parse(req.body); From 37a22098716b7bbbb39cd232dce7962a2d99979b Mon Sep 17 00:00:00 2001 From: Hariom Balhara Date: Thu, 20 Apr 2023 09:57:25 +0530 Subject: [PATCH 619/658] Hotfix: Make bookingFields optional (#258) --- lib/validations/event-type.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/validations/event-type.ts b/lib/validations/event-type.ts index 5f3f4f2f02..2b7768a656 100644 --- a/lib/validations/event-type.ts +++ b/lib/validations/event-type.ts @@ -65,7 +65,7 @@ const schemaEventTypeCreateParams = z recurringEvent: recurringEventInputSchema.optional(), seatsPerTimeSlot: z.number().optional(), seatsShowAttendees: z.boolean().optional(), - bookingFields: eventTypeBookingFields, + bookingFields: eventTypeBookingFields.optional(), }) .strict(); @@ -80,7 +80,7 @@ const schemaEventTypeEditParams = z length: z.number().int().optional(), seatsPerTimeSlot: z.number().optional(), seatsShowAttendees: z.boolean().optional(), - bookingFields: eventTypeBookingFields, + bookingFields: eventTypeBookingFields.optional(), }) .strict(); @@ -134,5 +134,6 @@ export const schemaEventTypeReadPublic = EventType.pick({ metadata: jsonSchema.nullable(), customInputs: customInputSchema.array().optional(), link: z.string().optional(), + bookingFields: eventTypeBookingFields.optional().nullable(), }) ); From 02094904be3d959e7555ef588b1b672569767b21 Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Sun, 23 Apr 2023 18:43:23 +0200 Subject: [PATCH 620/658] Patch vulnerability that allowed self-promotion --- pages/api/users/[userId]/_patch.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pages/api/users/[userId]/_patch.ts b/pages/api/users/[userId]/_patch.ts index 1d823f067f..59d8b76f94 100644 --- a/pages/api/users/[userId]/_patch.ts +++ b/pages/api/users/[userId]/_patch.ts @@ -94,6 +94,11 @@ export async function patchHandler(req: NextApiRequest) { if (!isAdmin && query.userId !== req.userId) throw new HttpError({ statusCode: 403, message: "Forbidden" }); const body = await schemaUserEditBodyParams.parseAsync(req.body); + // disable role changes unless admin. + if (!isAdmin && body.role) { + body.role = undefined; + } + const userSchedules = await prisma.schedule.findMany({ where: { userId: query.userId }, }); From 9490b65775fdc1fdd79f0e8216c80dad254e9315 Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Sun, 23 Apr 2023 18:57:21 +0200 Subject: [PATCH 621/658] Fix type error by no longer initialData the user --- pages/api/availability/_get.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/pages/api/availability/_get.ts b/pages/api/availability/_get.ts index f601251609..2f8add247f 100644 --- a/pages/api/availability/_get.ts +++ b/pages/api/availability/_get.ts @@ -103,15 +103,12 @@ async function handler(req: NextApiRequest) { const availabilities = members.map(async (user) => { return { userId: user.id, - availability: await getUserAvailability( - { - userId: user.id, - dateFrom, - dateTo, - eventTypeId, - }, - { user } - ), + availability: await getUserAvailability({ + userId: user.id, + dateFrom, + dateTo, + eventTypeId, + }), }; }); const settled = await Promise.all(availabilities); From b6c3dce6921d31dc3d312890bcd10f2a44efee62 Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Fri, 5 May 2023 16:33:24 +0200 Subject: [PATCH 622/658] Fix with upstream (#263) --- lib/utils/isAdmin.ts | 3 ++- lib/validations/membership.ts | 2 +- pages/api/event-types/[id]/_patch.ts | 2 +- pages/api/teams/[teamId]/_auth-middleware.ts | 2 +- pages/api/teams/[teamId]/publish.ts | 11 +++++++---- pages/api/teams/_post.ts | 2 +- 6 files changed, 13 insertions(+), 9 deletions(-) diff --git a/lib/utils/isAdmin.ts b/lib/utils/isAdmin.ts index c07086fbd6..9db0cb5026 100644 --- a/lib/utils/isAdmin.ts +++ b/lib/utils/isAdmin.ts @@ -1,6 +1,7 @@ -import { UserPermissionRole } from "@prisma/client"; import type { NextApiRequest } from "next/types"; +import { UserPermissionRole } from "@calcom/prisma/enums"; + export const isAdminGuard = async (req: NextApiRequest) => { const { userId, prisma } = req; const user = await prisma.user.findUnique({ where: { id: userId } }); diff --git a/lib/validations/membership.ts b/lib/validations/membership.ts index 90b4e966fb..24740eaa52 100644 --- a/lib/validations/membership.ts +++ b/lib/validations/membership.ts @@ -1,6 +1,6 @@ -import { MembershipRole } from "@prisma/client"; import { z } from "zod"; +import { MembershipRole } from "@calcom/prisma/enums"; import { _MembershipModel as Membership, _TeamModel } from "@calcom/prisma/zod"; import { stringOrNumber } from "@calcom/prisma/zod-utils"; diff --git a/pages/api/event-types/[id]/_patch.ts b/pages/api/event-types/[id]/_patch.ts index 83bdf156ad..2468d1621b 100644 --- a/pages/api/event-types/[id]/_patch.ts +++ b/pages/api/event-types/[id]/_patch.ts @@ -1,10 +1,10 @@ import type { Prisma } from "@prisma/client"; -import { SchedulingType } from "@prisma/client"; import type { NextApiRequest } from "next"; import type { z } from "zod"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; +import { SchedulingType } from "@calcom/prisma/enums"; import type { schemaEventTypeBaseBodyParams } from "~/lib/validations/event-type"; import { schemaEventTypeEditBodyParams, schemaEventTypeReadPublic } from "~/lib/validations/event-type"; diff --git a/pages/api/teams/[teamId]/_auth-middleware.ts b/pages/api/teams/[teamId]/_auth-middleware.ts index e6fd918043..bde11bb75c 100644 --- a/pages/api/teams/[teamId]/_auth-middleware.ts +++ b/pages/api/teams/[teamId]/_auth-middleware.ts @@ -1,8 +1,8 @@ import type { Prisma } from "@prisma/client"; -import { MembershipRole } from "@prisma/client"; import type { NextApiRequest } from "next"; import { HttpError } from "@calcom/lib/http-error"; +import { MembershipRole } from "@calcom/prisma/enums"; import { schemaQueryTeamId } from "~/lib/validations/shared/queryTeamId"; diff --git a/pages/api/teams/[teamId]/publish.ts b/pages/api/teams/[teamId]/publish.ts index edb36be796..25f1c74785 100644 --- a/pages/api/teams/[teamId]/publish.ts +++ b/pages/api/teams/[teamId]/publish.ts @@ -1,10 +1,10 @@ -import { MembershipRole, UserPermissionRole } from "@prisma/client"; import type { NextApiRequest, NextApiResponse } from "next"; import { HttpError } from "@calcom/lib/http-error"; import { defaultHandler, defaultResponder } from "@calcom/lib/server"; +import { MembershipRole, UserPermissionRole } from "@calcom/prisma/enums"; import { createContext } from "@calcom/trpc/server/createContext"; -import { viewerRouter } from "@calcom/trpc/server/routers/viewer"; +import { publishHandler } from "@calcom/trpc/server/routers/viewer/teams/publish.handler"; import { TRPCError } from "@trpc/server"; import { getHTTPStatusCodeFromError } from "@trpc/server/http"; @@ -33,10 +33,13 @@ const patchHandler = async (req: NextApiRequest, res: NextApiResponse) => { /** @see https://trpc.io/docs/server-side-calls */ const ctx = await createContext({ req, res }, sessionGetter); - const caller = viewerRouter.createCaller(ctx); + const user = ctx.user; + if (!user) { + throw new Error("Internal Error."); + } try { const { teamId } = schemaQueryTeamId.parse(req.query); - return await caller.teams.publish({ teamId }); + return await publishHandler({ input: { teamId }, ctx: { ...ctx, user } }); } catch (cause) { if (cause instanceof TRPCError) { const statusCode = getHTTPStatusCodeFromError(cause); diff --git a/pages/api/teams/_post.ts b/pages/api/teams/_post.ts index af032d00d4..56e0820535 100644 --- a/pages/api/teams/_post.ts +++ b/pages/api/teams/_post.ts @@ -1,9 +1,9 @@ -import { MembershipRole } from "@prisma/client"; import type { NextApiRequest } from "next"; import { IS_TEAM_BILLING_ENABLED } from "@calcom/lib/constants"; import { HttpError } from "@calcom/lib/http-error"; import { defaultResponder } from "@calcom/lib/server"; +import { MembershipRole } from "@calcom/prisma/enums"; import { schemaMembershipPublic } from "~/lib/validations/membership"; import { schemaTeamBodyParams, schemaTeamReadPublic } from "~/lib/validations/team"; From 4c02bb960bc36af175294976e85ae30635f037e2 Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Fri, 12 May 2023 00:22:24 +0200 Subject: [PATCH 623/658] Remove sessionGetter as it's deprecated (#265) Fixes API build, error introduced in https://github.com/calcom/cal.com/pull/8419 --- pages/api/teams/[teamId]/publish.ts | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/pages/api/teams/[teamId]/publish.ts b/pages/api/teams/[teamId]/publish.ts index 25f1c74785..4cf45e12fd 100644 --- a/pages/api/teams/[teamId]/publish.ts +++ b/pages/api/teams/[teamId]/publish.ts @@ -2,7 +2,7 @@ import type { NextApiRequest, NextApiResponse } from "next"; import { HttpError } from "@calcom/lib/http-error"; import { defaultHandler, defaultResponder } from "@calcom/lib/server"; -import { MembershipRole, UserPermissionRole } from "@calcom/prisma/enums"; +import { MembershipRole } from "@calcom/prisma/enums"; import { createContext } from "@calcom/trpc/server/createContext"; import { publishHandler } from "@calcom/trpc/server/routers/viewer/teams/publish.handler"; @@ -15,24 +15,9 @@ import { schemaQueryTeamId } from "~/lib/validations/shared/queryTeamId"; import authMiddleware, { checkPermissions } from "./_auth-middleware"; const patchHandler = async (req: NextApiRequest, res: NextApiResponse) => { - const { isAdmin } = req; await checkPermissions(req, { in: [MembershipRole.OWNER, MembershipRole.ADMIN] }); - - /** We shape the session as required by tRPC rounter */ - async function sessionGetter() { - return { - user: { - id: req.userId, - username: "" /* Not used in this context */, - role: isAdmin ? UserPermissionRole.ADMIN : UserPermissionRole.USER, - }, - hasValidLicense: true, - expires: "" /* Not used in this context */, - }; - } - /** @see https://trpc.io/docs/server-side-calls */ - const ctx = await createContext({ req, res }, sessionGetter); + const ctx = await createContext({ req, res }); const user = ctx.user; if (!user) { throw new Error("Internal Error."); From 98e0a97c476e017d1b964213b98ea40be4db973b Mon Sep 17 00:00:00 2001 From: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Date: Fri, 12 May 2023 18:16:06 +0530 Subject: [PATCH 624/658] SWAGGER: Adds query example and response body example to /Availability (#264) This PR adds query examples and response body example to /Availability --------- Co-authored-by: Alex van Andel --- pages/api/availability/_get.ts | 35 ++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/pages/api/availability/_get.ts b/pages/api/availability/_get.ts index 2f8add247f..42371e0be7 100644 --- a/pages/api/availability/_get.ts +++ b/pages/api/availability/_get.ts @@ -18,38 +18,45 @@ import { stringOrNumber } from "@calcom/prisma/zod-utils"; * required: true * schema: * type: string + * example: "1234abcd5678efgh" * description: Your API key * - in: query * name: userId * schema: * type: integer + * example: 101 * description: ID of the user to fetch the availability for * - in: query * name: teamId * schema: * type: integer + * example: 123 * description: ID of the team to fetch the availability for * - in: query * name: username * schema: * type: string + * example: "alice" * description: username of the user to fetch the availability for * - in: query * name: dateFrom * schema: * type: string * format: date + * example: "2023-05-14 00:00:00" * description: Start Date of the availability query * - in: query * name: dateTo * schema: * type: string * format: date + * example: "2023-05-20 00:00:00" * description: End Date of the availability query * - in: query * name: eventTypeId * schema: * type: integer + * example: 123 * description: Event Type ID of the event type to fetch the availability for * operationId: availability * tags: @@ -57,6 +64,34 @@ import { stringOrNumber } from "@calcom/prisma/zod-utils"; * responses: * 200: * description: OK + * content: + * application/json: + * schema: + * type: object + * example: + * busy: + * - start: "2023-05-14T10:00:00.000Z" + * end: "2023-05-14T11:00:00.000Z" + * title: "Team meeting between Alice and Bob" + * - start: "2023-05-15T14:00:00.000Z" + * end: "2023-05-15T15:00:00.000Z" + * title: "Project review between Carol and Dave" + * - start: "2023-05-16T09:00:00.000Z" + * end: "2023-05-16T10:00:00.000Z" + * - start: "2023-05-17T13:00:00.000Z" + * end: "2023-05-17T14:00:00.000Z" + * timeZone: "America/New_York" + * workingHours: + * - days: [1, 2, 3, 4, 5] + * startTime: 540 + * endTime: 1020 + * userId: 101 + * dateOverrides: + * - date: "2023-05-15" + * startTime: 600 + * endTime: 960 + * userId: 101 + * currentSeats: 4 * 401: * description: Authorization information is missing or invalid. * 404: From ff69481cb9a6a947b254298abb277207dd79745a Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Wed, 17 May 2023 19:40:27 +0200 Subject: [PATCH 625/658] Keep next v13.2 for now --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 115a0e3d1c..9ec3b44b5a 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "bcryptjs": "^2.4.3", "memory-cache": "^0.2.0", "modify-response-middleware": "^1.1.0", - "next": "^13.2.1", + "next": "~13.2.1", "next-api-middleware": "^1.0.1", "next-axiom": "^0.16.0", "next-swagger-doc": "^0.3.4", From b7e65e31d658e3d1c0c37e426fa08400922e134c Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Fri, 19 May 2023 19:38:19 +0200 Subject: [PATCH 626/658] Fix API types, detach from main repo --- lib/helpers/customPrisma.ts | 2 +- lib/utils/isAdmin.ts | 2 +- next.d.ts | 21 +++++++++++++++++++++ pages/api/docs.ts | 2 +- 4 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 next.d.ts diff --git a/lib/helpers/customPrisma.ts b/lib/helpers/customPrisma.ts index 54bb8e76e4..a30cb6bcb6 100644 --- a/lib/helpers/customPrisma.ts +++ b/lib/helpers/customPrisma.ts @@ -9,7 +9,7 @@ const LOCAL_CONSOLE_URL = process.env.NEXT_PUBLIC_CONSOLE_URL || CONSOLE_URL; export const customPrismaClient: NextMiddleware = async (req, res, next) => { const { query: { key }, - }: { query: { key?: string } } = req; + } = req; // If no custom api Id is provided, attach to request the regular cal.com prisma client. if (!key) { req.prisma = new PrismaClient(); diff --git a/lib/utils/isAdmin.ts b/lib/utils/isAdmin.ts index 9db0cb5026..9b9e6f5342 100644 --- a/lib/utils/isAdmin.ts +++ b/lib/utils/isAdmin.ts @@ -1,4 +1,4 @@ -import type { NextApiRequest } from "next/types"; +import type { NextApiRequest } from "next"; import { UserPermissionRole } from "@calcom/prisma/enums"; diff --git a/next.d.ts b/next.d.ts new file mode 100644 index 0000000000..7d5f82441a --- /dev/null +++ b/next.d.ts @@ -0,0 +1,21 @@ +import type { Session } from "next-auth"; +import type { NextApiRequest as BaseNextApiRequest } from "next/types"; + +import type { PrismaClient } from "@calcom/prisma/client"; + +export type * from "next/types"; + +export declare module "next" { + interface NextApiRequest extends BaseNextApiRequest { + session?: Session | null; + + userId: number; + method: string; + prisma: PrismaClient; + // session: { user: { id: number } }; + // query: Partial<{ [key: string]: string | string[] }>; + isAdmin: boolean; + isCustomPrisma: boolean; + pagination: { take: number; skip: number }; + } +} diff --git a/pages/api/docs.ts b/pages/api/docs.ts index 27a09c650c..fb48027c35 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -1,7 +1,7 @@ import modifyRes from "modify-response-middleware"; +import type { NextApiRequest, NextApiResponse } from "next"; import { use } from "next-api-middleware"; import { withSwagger } from "next-swagger-doc"; -import type { NextApiRequest, NextApiResponse } from "next/types"; import pjson from "~/package.json"; From 39a7a2240fe20b0edb72343370ffebaf56e3df5e Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Fri, 19 May 2023 20:00:04 +0200 Subject: [PATCH 627/658] Remove modify-response middleware (it's huge and redundant) (#266) Remove custom types and now redundant express middlware. --- next.config.js | 26 ++++++++++++++++++++++++++ package.json | 3 +-- pages/api/docs.ts | 23 +---------------------- types.d.ts | 1 - 4 files changed, 28 insertions(+), 25 deletions(-) delete mode 100644 types.d.ts diff --git a/next.config.js b/next.config.js index 2dc79b35b2..ba2dcbf89b 100644 --- a/next.config.js +++ b/next.config.js @@ -11,6 +11,32 @@ module.exports = withAxiom({ "@calcom/prisma", "@calcom/trpc", ], + async headers() { + return [ + { + source: "/docs", + headers: [ + { + key: "Access-Control-Allow-Credentials", + value: "true", + }, + { + key: "Access-Control-Allow-Origin", + value: "*", + }, + { + key: "Access-Control-Allow-Methods", + value: "GET, OPTIONS, PATCH, DELETE, POST, PUT", + }, + { + key: "Access-Control-Allow-Headers", + value: + "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version, Content-Type, api_key, Authorization", + }, + ], + }, + ]; + }, async rewrites() { return { afterFiles: [ diff --git a/package.json b/package.json index 9ec3b44b5a..fea62daa18 100644 --- a/package.json +++ b/package.json @@ -36,11 +36,10 @@ "@sentry/nextjs": "^7.20.0", "bcryptjs": "^2.4.3", "memory-cache": "^0.2.0", - "modify-response-middleware": "^1.1.0", "next": "~13.2.1", "next-api-middleware": "^1.0.1", "next-axiom": "^0.16.0", - "next-swagger-doc": "^0.3.4", + "next-swagger-doc": "^0.3.6", "next-validations": "^0.2.0", "typescript": "^4.9.4", "tzdata": "^1.0.30", diff --git a/pages/api/docs.ts b/pages/api/docs.ts index fb48027c35..1773d87457 100644 --- a/pages/api/docs.ts +++ b/pages/api/docs.ts @@ -1,6 +1,3 @@ -import modifyRes from "modify-response-middleware"; -import type { NextApiRequest, NextApiResponse } from "next"; -import { use } from "next-api-middleware"; import { withSwagger } from "next-swagger-doc"; import pjson from "~/package.json"; @@ -129,22 +126,4 @@ const swaggerHandler = withSwagger({ apiFolder: "pages/api", }); -export default use( - modifyRes((content: string, _req: NextApiRequest, res: NextApiResponse) => { - // Add all headers here instead of next.config.js as it is throwing error( Cannot set headers after they are sent to the client) for OPTIONS method - // It is known to happen only in Dev Mode. - res.setHeader("Access-Control-Allow-Credentials", "true"); - res.setHeader("Access-Control-Allow-Origin", "*"); - res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS, PATCH, DELETE, POST, PUT"); - res.setHeader( - "Access-Control-Allow-Headers", - "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version, Content-Type, api_key, Authorization" - ); - if (content) { - const parsed = JSON.parse(content); - // HACK: This is a hack to fix the swagger-ui issue with the extra channels property. - delete parsed.channels; - return Buffer.from(JSON.stringify(parsed)); - } - }) -)(swaggerHandler()); +export default swaggerHandler(); diff --git a/types.d.ts b/types.d.ts deleted file mode 100644 index 9a7af651d1..0000000000 --- a/types.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module "modify-response-middleware"; From 8b4ce91fefef68ace34f88f225f8465e7d6b0aaa Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 19 May 2023 13:37:19 -0700 Subject: [PATCH 628/658] Add missing production condition for deploy script --- scripts/vercel-deploy.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/vercel-deploy.sh b/scripts/vercel-deploy.sh index e9ef0538b3..689616931c 100755 --- a/scripts/vercel-deploy.sh +++ b/scripts/vercel-deploy.sh @@ -17,6 +17,9 @@ if [ "$GITHUB_ACCESS_TOKEN" == "" ]; then fi # We add an exception to test on staging +if [ "$VERCEL_GIT_COMMIT_REF" == "production" ]; then + BRANCH_TO_CLONE="-b $VERCEL_GIT_COMMIT_REF" +fi if [ "$VERCEL_GIT_COMMIT_REF" == "staging" ]; then BRANCH_TO_CLONE="-b $VERCEL_GIT_COMMIT_REF" fi From 064c0306b5b179fbebdb426f61c8d082a905c5a3 Mon Sep 17 00:00:00 2001 From: zomars Date: Tue, 23 May 2023 13:08:56 -0700 Subject: [PATCH 629/658] Move all files into apps/api directory --- .env.example => apps/api/.env.example | 0 .eslintrc.js => apps/api/.eslintrc.js | 0 .gitignore => apps/api/.gitignore | 0 .prettierignore => apps/api/.prettierignore | 0 LICENSE => apps/api/LICENSE | 0 README.md => apps/api/README.md | 0 jest.setup.ts => apps/api/jest.setup.ts | 0 {lib => apps/api/lib}/constants.ts | 0 {lib => apps/api/lib}/helpers/addRequestid.ts | 0 {lib => apps/api/lib}/helpers/captureErrors.ts | 0 {lib => apps/api/lib}/helpers/customPrisma.ts | 0 {lib => apps/api/lib}/helpers/extendRequest.ts | 0 {lib => apps/api/lib}/helpers/httpMethods.ts | 0 {lib => apps/api/lib}/helpers/safeParseJSON.ts | 0 {lib => apps/api/lib}/helpers/verifyApiKey.ts | 0 {lib => apps/api/lib}/helpers/withMiddleware.ts | 0 {lib => apps/api/lib}/helpers/withPagination.ts | 0 {lib => apps/api/lib}/types.ts | 0 {lib => apps/api/lib}/utils/isAdmin.ts | 0 {lib => apps/api/lib}/utils/stringifyISODate.ts | 0 {lib => apps/api/lib}/validations/api-key.ts | 0 {lib => apps/api/lib}/validations/attendee.ts | 0 {lib => apps/api/lib}/validations/availability.ts | 0 {lib => apps/api/lib}/validations/booking-reference.ts | 0 {lib => apps/api/lib}/validations/booking.ts | 0 {lib => apps/api/lib}/validations/destination-calendar.ts | 0 {lib => apps/api/lib}/validations/event-type-custom-input.ts | 0 {lib => apps/api/lib}/validations/event-type.ts | 0 {lib => apps/api/lib}/validations/membership.ts | 0 {lib => apps/api/lib}/validations/payment.ts | 0 {lib => apps/api/lib}/validations/reminder-mail.ts | 0 {lib => apps/api/lib}/validations/schedule.ts | 0 {lib => apps/api/lib}/validations/selected-calendar.ts | 0 {lib => apps/api/lib}/validations/shared/baseApiParams.ts | 0 {lib => apps/api/lib}/validations/shared/jsonSchema.ts | 0 {lib => apps/api/lib}/validations/shared/queryIdString.ts | 0 .../api/lib}/validations/shared/queryIdTransformParseInt.ts | 0 {lib => apps/api/lib}/validations/shared/queryTeamId.ts | 0 {lib => apps/api/lib}/validations/shared/queryUserId.ts | 0 {lib => apps/api/lib}/validations/shared/timeZone.ts | 0 {lib => apps/api/lib}/validations/team.ts | 0 {lib => apps/api/lib}/validations/user.ts | 0 {lib => apps/api/lib}/validations/webhook.ts | 0 next-env.d.ts => apps/api/next-env.d.ts | 0 next-i18next.config.js => apps/api/next-i18next.config.js | 0 next.config.js => apps/api/next.config.js | 0 next.d.ts => apps/api/next.d.ts | 0 package.json => apps/api/package.json | 0 {pages => apps/api/pages}/api/api-keys/[id]/_auth-middleware.ts | 0 {pages => apps/api/pages}/api/api-keys/[id]/_delete.ts | 0 {pages => apps/api/pages}/api/api-keys/[id]/_get.ts | 0 {pages => apps/api/pages}/api/api-keys/[id]/_patch.ts | 0 {pages => apps/api/pages}/api/api-keys/[id]/index.ts | 0 {pages => apps/api/pages}/api/api-keys/_get.ts | 0 {pages => apps/api/pages}/api/api-keys/_post.ts | 0 {pages => apps/api/pages}/api/api-keys/index.ts | 0 {pages => apps/api/pages}/api/attendees/[id]/_auth-middleware.ts | 0 {pages => apps/api/pages}/api/attendees/[id]/_delete.ts | 0 {pages => apps/api/pages}/api/attendees/[id]/_get.ts | 0 {pages => apps/api/pages}/api/attendees/[id]/_patch.ts | 0 {pages => apps/api/pages}/api/attendees/[id]/index.ts | 0 {pages => apps/api/pages}/api/attendees/_get.ts | 0 {pages => apps/api/pages}/api/attendees/_post.ts | 0 {pages => apps/api/pages}/api/attendees/index.ts | 0 .../api/pages}/api/availabilities/[id]/_auth-middleware.ts | 0 {pages => apps/api/pages}/api/availabilities/[id]/_delete.ts | 0 {pages => apps/api/pages}/api/availabilities/[id]/_get.ts | 0 {pages => apps/api/pages}/api/availabilities/[id]/_patch.ts | 0 {pages => apps/api/pages}/api/availabilities/[id]/index.ts | 0 {pages => apps/api/pages}/api/availabilities/_post.ts | 0 {pages => apps/api/pages}/api/availabilities/index.ts | 0 {pages => apps/api/pages}/api/availability/_get.ts | 0 {pages => apps/api/pages}/api/availability/index.ts | 0 .../api/pages}/api/booking-references/[id]/_auth-middleware.ts | 0 {pages => apps/api/pages}/api/booking-references/[id]/_delete.ts | 0 {pages => apps/api/pages}/api/booking-references/[id]/_get.ts | 0 {pages => apps/api/pages}/api/booking-references/[id]/_patch.ts | 0 {pages => apps/api/pages}/api/booking-references/[id]/index.ts | 0 {pages => apps/api/pages}/api/booking-references/_get.ts | 0 {pages => apps/api/pages}/api/booking-references/_post.ts | 0 {pages => apps/api/pages}/api/booking-references/index.ts | 0 {pages => apps/api/pages}/api/bookings/[id]/_auth-middleware.ts | 0 {pages => apps/api/pages}/api/bookings/[id]/_delete.ts | 0 {pages => apps/api/pages}/api/bookings/[id]/_get.ts | 0 {pages => apps/api/pages}/api/bookings/[id]/_patch.ts | 0 {pages => apps/api/pages}/api/bookings/[id]/cancel.ts | 0 {pages => apps/api/pages}/api/bookings/[id]/index.ts | 0 {pages => apps/api/pages}/api/bookings/_get.ts | 0 {pages => apps/api/pages}/api/bookings/_post.ts | 0 {pages => apps/api/pages}/api/bookings/index.ts | 0 .../api/pages}/api/custom-inputs/[id]/_auth-middleware.ts | 0 {pages => apps/api/pages}/api/custom-inputs/[id]/_delete.ts | 0 {pages => apps/api/pages}/api/custom-inputs/[id]/_get.ts | 0 {pages => apps/api/pages}/api/custom-inputs/[id]/_patch.ts | 0 {pages => apps/api/pages}/api/custom-inputs/[id]/index.ts | 0 {pages => apps/api/pages}/api/custom-inputs/_get.ts | 0 {pages => apps/api/pages}/api/custom-inputs/_post.ts | 0 {pages => apps/api/pages}/api/custom-inputs/index.ts | 0 {pages => apps/api/pages}/api/destination-calendars/[id].ts | 0 {pages => apps/api/pages}/api/destination-calendars/index.ts | 0 {pages => apps/api/pages}/api/docs.ts | 0 .../api/pages}/api/event-types/[id]/_auth-middleware.ts | 0 {pages => apps/api/pages}/api/event-types/[id]/_delete.ts | 0 {pages => apps/api/pages}/api/event-types/[id]/_get.ts | 0 {pages => apps/api/pages}/api/event-types/[id]/_patch.ts | 0 {pages => apps/api/pages}/api/event-types/[id]/index.ts | 0 {pages => apps/api/pages}/api/event-types/_get.ts | 0 {pages => apps/api/pages}/api/event-types/_post.ts | 0 .../pages}/api/event-types/_utils/checkTeamEventEditPermission.ts | 0 .../api/pages}/api/event-types/_utils/ensureOnlyMembersAsHosts.ts | 0 {pages => apps/api/pages}/api/event-types/_utils/getCalLink.ts | 0 {pages => apps/api/pages}/api/event-types/index.ts | 0 {pages => apps/api/pages}/api/index.ts | 0 {pages => apps/api/pages}/api/me/_get.ts | 0 {pages => apps/api/pages}/api/me/index.ts | 0 .../api/pages}/api/memberships/[id]/_auth-middleware.ts | 0 {pages => apps/api/pages}/api/memberships/[id]/_delete.ts | 0 {pages => apps/api/pages}/api/memberships/[id]/_get.ts | 0 {pages => apps/api/pages}/api/memberships/[id]/_patch.ts | 0 {pages => apps/api/pages}/api/memberships/[id]/index.ts | 0 {pages => apps/api/pages}/api/memberships/_get.ts | 0 {pages => apps/api/pages}/api/memberships/_post.ts | 0 {pages => apps/api/pages}/api/memberships/index.ts | 0 {pages => apps/api/pages}/api/payments/[id].ts | 0 {pages => apps/api/pages}/api/payments/index.ts | 0 {pages => apps/api/pages}/api/schedules/[id]/_auth-middleware.ts | 0 {pages => apps/api/pages}/api/schedules/[id]/_delete.ts | 0 {pages => apps/api/pages}/api/schedules/[id]/_get.ts | 0 {pages => apps/api/pages}/api/schedules/[id]/_patch.ts | 0 {pages => apps/api/pages}/api/schedules/[id]/index.ts | 0 {pages => apps/api/pages}/api/schedules/_get.ts | 0 {pages => apps/api/pages}/api/schedules/_post.ts | 0 {pages => apps/api/pages}/api/schedules/index.ts | 0 .../api/pages}/api/selected-calendars/[id]/_auth-middleware.ts | 0 {pages => apps/api/pages}/api/selected-calendars/[id]/_delete.ts | 0 {pages => apps/api/pages}/api/selected-calendars/[id]/_get.ts | 0 {pages => apps/api/pages}/api/selected-calendars/[id]/_patch.ts | 0 {pages => apps/api/pages}/api/selected-calendars/[id]/index.ts | 0 {pages => apps/api/pages}/api/selected-calendars/_get.ts | 0 {pages => apps/api/pages}/api/selected-calendars/_post.ts | 0 {pages => apps/api/pages}/api/selected-calendars/index.ts | 0 {pages => apps/api/pages}/api/teams/[teamId]/_auth-middleware.ts | 0 {pages => apps/api/pages}/api/teams/[teamId]/_delete.ts | 0 {pages => apps/api/pages}/api/teams/[teamId]/_get.ts | 0 {pages => apps/api/pages}/api/teams/[teamId]/_patch.ts | 0 .../api/pages}/api/teams/[teamId]/availability/index.ts | 0 {pages => apps/api/pages}/api/teams/[teamId]/event-types/_get.ts | 0 {pages => apps/api/pages}/api/teams/[teamId]/event-types/index.ts | 0 {pages => apps/api/pages}/api/teams/[teamId]/index.ts | 0 {pages => apps/api/pages}/api/teams/[teamId]/publish.ts | 0 {pages => apps/api/pages}/api/teams/_get.ts | 0 {pages => apps/api/pages}/api/teams/_post.ts | 0 {pages => apps/api/pages}/api/teams/index.ts | 0 {pages => apps/api/pages}/api/users/[userId]/_delete.ts | 0 {pages => apps/api/pages}/api/users/[userId]/_get.ts | 0 {pages => apps/api/pages}/api/users/[userId]/_patch.ts | 0 .../api/pages}/api/users/[userId]/availability/index.ts | 0 {pages => apps/api/pages}/api/users/[userId]/index.ts | 0 {pages => apps/api/pages}/api/users/_get.ts | 0 {pages => apps/api/pages}/api/users/_post.ts | 0 {pages => apps/api/pages}/api/users/index.ts | 0 {pages => apps/api/pages}/api/webhooks/[id]/_auth-middleware.ts | 0 {pages => apps/api/pages}/api/webhooks/[id]/_delete.ts | 0 {pages => apps/api/pages}/api/webhooks/[id]/_get.ts | 0 {pages => apps/api/pages}/api/webhooks/[id]/_patch.ts | 0 {pages => apps/api/pages}/api/webhooks/[id]/index.ts | 0 {pages => apps/api/pages}/api/webhooks/_get.ts | 0 {pages => apps/api/pages}/api/webhooks/_post.ts | 0 {pages => apps/api/pages}/api/webhooks/index.ts | 0 {scripts => apps/api/scripts}/vercel-deploy.sh | 0 {test => apps/api/test}/README.md | 0 {test => apps/api/test}/docker-compose.yml | 0 {test => apps/api/test}/jest-resolver.js | 0 {test => apps/api/test}/jest-setup.js | 0 {test => apps/api/test}/lib/bookings/_post.test.ts | 0 tsconfig.json => apps/api/tsconfig.json | 0 176 files changed, 0 insertions(+), 0 deletions(-) rename .env.example => apps/api/.env.example (100%) rename .eslintrc.js => apps/api/.eslintrc.js (100%) rename .gitignore => apps/api/.gitignore (100%) rename .prettierignore => apps/api/.prettierignore (100%) rename LICENSE => apps/api/LICENSE (100%) rename README.md => apps/api/README.md (100%) rename jest.setup.ts => apps/api/jest.setup.ts (100%) rename {lib => apps/api/lib}/constants.ts (100%) rename {lib => apps/api/lib}/helpers/addRequestid.ts (100%) rename {lib => apps/api/lib}/helpers/captureErrors.ts (100%) rename {lib => apps/api/lib}/helpers/customPrisma.ts (100%) rename {lib => apps/api/lib}/helpers/extendRequest.ts (100%) rename {lib => apps/api/lib}/helpers/httpMethods.ts (100%) rename {lib => apps/api/lib}/helpers/safeParseJSON.ts (100%) rename {lib => apps/api/lib}/helpers/verifyApiKey.ts (100%) rename {lib => apps/api/lib}/helpers/withMiddleware.ts (100%) rename {lib => apps/api/lib}/helpers/withPagination.ts (100%) rename {lib => apps/api/lib}/types.ts (100%) rename {lib => apps/api/lib}/utils/isAdmin.ts (100%) rename {lib => apps/api/lib}/utils/stringifyISODate.ts (100%) rename {lib => apps/api/lib}/validations/api-key.ts (100%) rename {lib => apps/api/lib}/validations/attendee.ts (100%) rename {lib => apps/api/lib}/validations/availability.ts (100%) rename {lib => apps/api/lib}/validations/booking-reference.ts (100%) rename {lib => apps/api/lib}/validations/booking.ts (100%) rename {lib => apps/api/lib}/validations/destination-calendar.ts (100%) rename {lib => apps/api/lib}/validations/event-type-custom-input.ts (100%) rename {lib => apps/api/lib}/validations/event-type.ts (100%) rename {lib => apps/api/lib}/validations/membership.ts (100%) rename {lib => apps/api/lib}/validations/payment.ts (100%) rename {lib => apps/api/lib}/validations/reminder-mail.ts (100%) rename {lib => apps/api/lib}/validations/schedule.ts (100%) rename {lib => apps/api/lib}/validations/selected-calendar.ts (100%) rename {lib => apps/api/lib}/validations/shared/baseApiParams.ts (100%) rename {lib => apps/api/lib}/validations/shared/jsonSchema.ts (100%) rename {lib => apps/api/lib}/validations/shared/queryIdString.ts (100%) rename {lib => apps/api/lib}/validations/shared/queryIdTransformParseInt.ts (100%) rename {lib => apps/api/lib}/validations/shared/queryTeamId.ts (100%) rename {lib => apps/api/lib}/validations/shared/queryUserId.ts (100%) rename {lib => apps/api/lib}/validations/shared/timeZone.ts (100%) rename {lib => apps/api/lib}/validations/team.ts (100%) rename {lib => apps/api/lib}/validations/user.ts (100%) rename {lib => apps/api/lib}/validations/webhook.ts (100%) rename next-env.d.ts => apps/api/next-env.d.ts (100%) rename next-i18next.config.js => apps/api/next-i18next.config.js (100%) rename next.config.js => apps/api/next.config.js (100%) rename next.d.ts => apps/api/next.d.ts (100%) rename package.json => apps/api/package.json (100%) rename {pages => apps/api/pages}/api/api-keys/[id]/_auth-middleware.ts (100%) rename {pages => apps/api/pages}/api/api-keys/[id]/_delete.ts (100%) rename {pages => apps/api/pages}/api/api-keys/[id]/_get.ts (100%) rename {pages => apps/api/pages}/api/api-keys/[id]/_patch.ts (100%) rename {pages => apps/api/pages}/api/api-keys/[id]/index.ts (100%) rename {pages => apps/api/pages}/api/api-keys/_get.ts (100%) rename {pages => apps/api/pages}/api/api-keys/_post.ts (100%) rename {pages => apps/api/pages}/api/api-keys/index.ts (100%) rename {pages => apps/api/pages}/api/attendees/[id]/_auth-middleware.ts (100%) rename {pages => apps/api/pages}/api/attendees/[id]/_delete.ts (100%) rename {pages => apps/api/pages}/api/attendees/[id]/_get.ts (100%) rename {pages => apps/api/pages}/api/attendees/[id]/_patch.ts (100%) rename {pages => apps/api/pages}/api/attendees/[id]/index.ts (100%) rename {pages => apps/api/pages}/api/attendees/_get.ts (100%) rename {pages => apps/api/pages}/api/attendees/_post.ts (100%) rename {pages => apps/api/pages}/api/attendees/index.ts (100%) rename {pages => apps/api/pages}/api/availabilities/[id]/_auth-middleware.ts (100%) rename {pages => apps/api/pages}/api/availabilities/[id]/_delete.ts (100%) rename {pages => apps/api/pages}/api/availabilities/[id]/_get.ts (100%) rename {pages => apps/api/pages}/api/availabilities/[id]/_patch.ts (100%) rename {pages => apps/api/pages}/api/availabilities/[id]/index.ts (100%) rename {pages => apps/api/pages}/api/availabilities/_post.ts (100%) rename {pages => apps/api/pages}/api/availabilities/index.ts (100%) rename {pages => apps/api/pages}/api/availability/_get.ts (100%) rename {pages => apps/api/pages}/api/availability/index.ts (100%) rename {pages => apps/api/pages}/api/booking-references/[id]/_auth-middleware.ts (100%) rename {pages => apps/api/pages}/api/booking-references/[id]/_delete.ts (100%) rename {pages => apps/api/pages}/api/booking-references/[id]/_get.ts (100%) rename {pages => apps/api/pages}/api/booking-references/[id]/_patch.ts (100%) rename {pages => apps/api/pages}/api/booking-references/[id]/index.ts (100%) rename {pages => apps/api/pages}/api/booking-references/_get.ts (100%) rename {pages => apps/api/pages}/api/booking-references/_post.ts (100%) rename {pages => apps/api/pages}/api/booking-references/index.ts (100%) rename {pages => apps/api/pages}/api/bookings/[id]/_auth-middleware.ts (100%) rename {pages => apps/api/pages}/api/bookings/[id]/_delete.ts (100%) rename {pages => apps/api/pages}/api/bookings/[id]/_get.ts (100%) rename {pages => apps/api/pages}/api/bookings/[id]/_patch.ts (100%) rename {pages => apps/api/pages}/api/bookings/[id]/cancel.ts (100%) rename {pages => apps/api/pages}/api/bookings/[id]/index.ts (100%) rename {pages => apps/api/pages}/api/bookings/_get.ts (100%) rename {pages => apps/api/pages}/api/bookings/_post.ts (100%) rename {pages => apps/api/pages}/api/bookings/index.ts (100%) rename {pages => apps/api/pages}/api/custom-inputs/[id]/_auth-middleware.ts (100%) rename {pages => apps/api/pages}/api/custom-inputs/[id]/_delete.ts (100%) rename {pages => apps/api/pages}/api/custom-inputs/[id]/_get.ts (100%) rename {pages => apps/api/pages}/api/custom-inputs/[id]/_patch.ts (100%) rename {pages => apps/api/pages}/api/custom-inputs/[id]/index.ts (100%) rename {pages => apps/api/pages}/api/custom-inputs/_get.ts (100%) rename {pages => apps/api/pages}/api/custom-inputs/_post.ts (100%) rename {pages => apps/api/pages}/api/custom-inputs/index.ts (100%) rename {pages => apps/api/pages}/api/destination-calendars/[id].ts (100%) rename {pages => apps/api/pages}/api/destination-calendars/index.ts (100%) rename {pages => apps/api/pages}/api/docs.ts (100%) rename {pages => apps/api/pages}/api/event-types/[id]/_auth-middleware.ts (100%) rename {pages => apps/api/pages}/api/event-types/[id]/_delete.ts (100%) rename {pages => apps/api/pages}/api/event-types/[id]/_get.ts (100%) rename {pages => apps/api/pages}/api/event-types/[id]/_patch.ts (100%) rename {pages => apps/api/pages}/api/event-types/[id]/index.ts (100%) rename {pages => apps/api/pages}/api/event-types/_get.ts (100%) rename {pages => apps/api/pages}/api/event-types/_post.ts (100%) rename {pages => apps/api/pages}/api/event-types/_utils/checkTeamEventEditPermission.ts (100%) rename {pages => apps/api/pages}/api/event-types/_utils/ensureOnlyMembersAsHosts.ts (100%) rename {pages => apps/api/pages}/api/event-types/_utils/getCalLink.ts (100%) rename {pages => apps/api/pages}/api/event-types/index.ts (100%) rename {pages => apps/api/pages}/api/index.ts (100%) rename {pages => apps/api/pages}/api/me/_get.ts (100%) rename {pages => apps/api/pages}/api/me/index.ts (100%) rename {pages => apps/api/pages}/api/memberships/[id]/_auth-middleware.ts (100%) rename {pages => apps/api/pages}/api/memberships/[id]/_delete.ts (100%) rename {pages => apps/api/pages}/api/memberships/[id]/_get.ts (100%) rename {pages => apps/api/pages}/api/memberships/[id]/_patch.ts (100%) rename {pages => apps/api/pages}/api/memberships/[id]/index.ts (100%) rename {pages => apps/api/pages}/api/memberships/_get.ts (100%) rename {pages => apps/api/pages}/api/memberships/_post.ts (100%) rename {pages => apps/api/pages}/api/memberships/index.ts (100%) rename {pages => apps/api/pages}/api/payments/[id].ts (100%) rename {pages => apps/api/pages}/api/payments/index.ts (100%) rename {pages => apps/api/pages}/api/schedules/[id]/_auth-middleware.ts (100%) rename {pages => apps/api/pages}/api/schedules/[id]/_delete.ts (100%) rename {pages => apps/api/pages}/api/schedules/[id]/_get.ts (100%) rename {pages => apps/api/pages}/api/schedules/[id]/_patch.ts (100%) rename {pages => apps/api/pages}/api/schedules/[id]/index.ts (100%) rename {pages => apps/api/pages}/api/schedules/_get.ts (100%) rename {pages => apps/api/pages}/api/schedules/_post.ts (100%) rename {pages => apps/api/pages}/api/schedules/index.ts (100%) rename {pages => apps/api/pages}/api/selected-calendars/[id]/_auth-middleware.ts (100%) rename {pages => apps/api/pages}/api/selected-calendars/[id]/_delete.ts (100%) rename {pages => apps/api/pages}/api/selected-calendars/[id]/_get.ts (100%) rename {pages => apps/api/pages}/api/selected-calendars/[id]/_patch.ts (100%) rename {pages => apps/api/pages}/api/selected-calendars/[id]/index.ts (100%) rename {pages => apps/api/pages}/api/selected-calendars/_get.ts (100%) rename {pages => apps/api/pages}/api/selected-calendars/_post.ts (100%) rename {pages => apps/api/pages}/api/selected-calendars/index.ts (100%) rename {pages => apps/api/pages}/api/teams/[teamId]/_auth-middleware.ts (100%) rename {pages => apps/api/pages}/api/teams/[teamId]/_delete.ts (100%) rename {pages => apps/api/pages}/api/teams/[teamId]/_get.ts (100%) rename {pages => apps/api/pages}/api/teams/[teamId]/_patch.ts (100%) rename {pages => apps/api/pages}/api/teams/[teamId]/availability/index.ts (100%) rename {pages => apps/api/pages}/api/teams/[teamId]/event-types/_get.ts (100%) rename {pages => apps/api/pages}/api/teams/[teamId]/event-types/index.ts (100%) rename {pages => apps/api/pages}/api/teams/[teamId]/index.ts (100%) rename {pages => apps/api/pages}/api/teams/[teamId]/publish.ts (100%) rename {pages => apps/api/pages}/api/teams/_get.ts (100%) rename {pages => apps/api/pages}/api/teams/_post.ts (100%) rename {pages => apps/api/pages}/api/teams/index.ts (100%) rename {pages => apps/api/pages}/api/users/[userId]/_delete.ts (100%) rename {pages => apps/api/pages}/api/users/[userId]/_get.ts (100%) rename {pages => apps/api/pages}/api/users/[userId]/_patch.ts (100%) rename {pages => apps/api/pages}/api/users/[userId]/availability/index.ts (100%) rename {pages => apps/api/pages}/api/users/[userId]/index.ts (100%) rename {pages => apps/api/pages}/api/users/_get.ts (100%) rename {pages => apps/api/pages}/api/users/_post.ts (100%) rename {pages => apps/api/pages}/api/users/index.ts (100%) rename {pages => apps/api/pages}/api/webhooks/[id]/_auth-middleware.ts (100%) rename {pages => apps/api/pages}/api/webhooks/[id]/_delete.ts (100%) rename {pages => apps/api/pages}/api/webhooks/[id]/_get.ts (100%) rename {pages => apps/api/pages}/api/webhooks/[id]/_patch.ts (100%) rename {pages => apps/api/pages}/api/webhooks/[id]/index.ts (100%) rename {pages => apps/api/pages}/api/webhooks/_get.ts (100%) rename {pages => apps/api/pages}/api/webhooks/_post.ts (100%) rename {pages => apps/api/pages}/api/webhooks/index.ts (100%) rename {scripts => apps/api/scripts}/vercel-deploy.sh (100%) rename {test => apps/api/test}/README.md (100%) rename {test => apps/api/test}/docker-compose.yml (100%) rename {test => apps/api/test}/jest-resolver.js (100%) rename {test => apps/api/test}/jest-setup.js (100%) rename {test => apps/api/test}/lib/bookings/_post.test.ts (100%) rename tsconfig.json => apps/api/tsconfig.json (100%) diff --git a/.env.example b/apps/api/.env.example similarity index 100% rename from .env.example rename to apps/api/.env.example diff --git a/.eslintrc.js b/apps/api/.eslintrc.js similarity index 100% rename from .eslintrc.js rename to apps/api/.eslintrc.js diff --git a/.gitignore b/apps/api/.gitignore similarity index 100% rename from .gitignore rename to apps/api/.gitignore diff --git a/.prettierignore b/apps/api/.prettierignore similarity index 100% rename from .prettierignore rename to apps/api/.prettierignore diff --git a/LICENSE b/apps/api/LICENSE similarity index 100% rename from LICENSE rename to apps/api/LICENSE diff --git a/README.md b/apps/api/README.md similarity index 100% rename from README.md rename to apps/api/README.md diff --git a/jest.setup.ts b/apps/api/jest.setup.ts similarity index 100% rename from jest.setup.ts rename to apps/api/jest.setup.ts diff --git a/lib/constants.ts b/apps/api/lib/constants.ts similarity index 100% rename from lib/constants.ts rename to apps/api/lib/constants.ts diff --git a/lib/helpers/addRequestid.ts b/apps/api/lib/helpers/addRequestid.ts similarity index 100% rename from lib/helpers/addRequestid.ts rename to apps/api/lib/helpers/addRequestid.ts diff --git a/lib/helpers/captureErrors.ts b/apps/api/lib/helpers/captureErrors.ts similarity index 100% rename from lib/helpers/captureErrors.ts rename to apps/api/lib/helpers/captureErrors.ts diff --git a/lib/helpers/customPrisma.ts b/apps/api/lib/helpers/customPrisma.ts similarity index 100% rename from lib/helpers/customPrisma.ts rename to apps/api/lib/helpers/customPrisma.ts diff --git a/lib/helpers/extendRequest.ts b/apps/api/lib/helpers/extendRequest.ts similarity index 100% rename from lib/helpers/extendRequest.ts rename to apps/api/lib/helpers/extendRequest.ts diff --git a/lib/helpers/httpMethods.ts b/apps/api/lib/helpers/httpMethods.ts similarity index 100% rename from lib/helpers/httpMethods.ts rename to apps/api/lib/helpers/httpMethods.ts diff --git a/lib/helpers/safeParseJSON.ts b/apps/api/lib/helpers/safeParseJSON.ts similarity index 100% rename from lib/helpers/safeParseJSON.ts rename to apps/api/lib/helpers/safeParseJSON.ts diff --git a/lib/helpers/verifyApiKey.ts b/apps/api/lib/helpers/verifyApiKey.ts similarity index 100% rename from lib/helpers/verifyApiKey.ts rename to apps/api/lib/helpers/verifyApiKey.ts diff --git a/lib/helpers/withMiddleware.ts b/apps/api/lib/helpers/withMiddleware.ts similarity index 100% rename from lib/helpers/withMiddleware.ts rename to apps/api/lib/helpers/withMiddleware.ts diff --git a/lib/helpers/withPagination.ts b/apps/api/lib/helpers/withPagination.ts similarity index 100% rename from lib/helpers/withPagination.ts rename to apps/api/lib/helpers/withPagination.ts diff --git a/lib/types.ts b/apps/api/lib/types.ts similarity index 100% rename from lib/types.ts rename to apps/api/lib/types.ts diff --git a/lib/utils/isAdmin.ts b/apps/api/lib/utils/isAdmin.ts similarity index 100% rename from lib/utils/isAdmin.ts rename to apps/api/lib/utils/isAdmin.ts diff --git a/lib/utils/stringifyISODate.ts b/apps/api/lib/utils/stringifyISODate.ts similarity index 100% rename from lib/utils/stringifyISODate.ts rename to apps/api/lib/utils/stringifyISODate.ts diff --git a/lib/validations/api-key.ts b/apps/api/lib/validations/api-key.ts similarity index 100% rename from lib/validations/api-key.ts rename to apps/api/lib/validations/api-key.ts diff --git a/lib/validations/attendee.ts b/apps/api/lib/validations/attendee.ts similarity index 100% rename from lib/validations/attendee.ts rename to apps/api/lib/validations/attendee.ts diff --git a/lib/validations/availability.ts b/apps/api/lib/validations/availability.ts similarity index 100% rename from lib/validations/availability.ts rename to apps/api/lib/validations/availability.ts diff --git a/lib/validations/booking-reference.ts b/apps/api/lib/validations/booking-reference.ts similarity index 100% rename from lib/validations/booking-reference.ts rename to apps/api/lib/validations/booking-reference.ts diff --git a/lib/validations/booking.ts b/apps/api/lib/validations/booking.ts similarity index 100% rename from lib/validations/booking.ts rename to apps/api/lib/validations/booking.ts diff --git a/lib/validations/destination-calendar.ts b/apps/api/lib/validations/destination-calendar.ts similarity index 100% rename from lib/validations/destination-calendar.ts rename to apps/api/lib/validations/destination-calendar.ts diff --git a/lib/validations/event-type-custom-input.ts b/apps/api/lib/validations/event-type-custom-input.ts similarity index 100% rename from lib/validations/event-type-custom-input.ts rename to apps/api/lib/validations/event-type-custom-input.ts diff --git a/lib/validations/event-type.ts b/apps/api/lib/validations/event-type.ts similarity index 100% rename from lib/validations/event-type.ts rename to apps/api/lib/validations/event-type.ts diff --git a/lib/validations/membership.ts b/apps/api/lib/validations/membership.ts similarity index 100% rename from lib/validations/membership.ts rename to apps/api/lib/validations/membership.ts diff --git a/lib/validations/payment.ts b/apps/api/lib/validations/payment.ts similarity index 100% rename from lib/validations/payment.ts rename to apps/api/lib/validations/payment.ts diff --git a/lib/validations/reminder-mail.ts b/apps/api/lib/validations/reminder-mail.ts similarity index 100% rename from lib/validations/reminder-mail.ts rename to apps/api/lib/validations/reminder-mail.ts diff --git a/lib/validations/schedule.ts b/apps/api/lib/validations/schedule.ts similarity index 100% rename from lib/validations/schedule.ts rename to apps/api/lib/validations/schedule.ts diff --git a/lib/validations/selected-calendar.ts b/apps/api/lib/validations/selected-calendar.ts similarity index 100% rename from lib/validations/selected-calendar.ts rename to apps/api/lib/validations/selected-calendar.ts diff --git a/lib/validations/shared/baseApiParams.ts b/apps/api/lib/validations/shared/baseApiParams.ts similarity index 100% rename from lib/validations/shared/baseApiParams.ts rename to apps/api/lib/validations/shared/baseApiParams.ts diff --git a/lib/validations/shared/jsonSchema.ts b/apps/api/lib/validations/shared/jsonSchema.ts similarity index 100% rename from lib/validations/shared/jsonSchema.ts rename to apps/api/lib/validations/shared/jsonSchema.ts diff --git a/lib/validations/shared/queryIdString.ts b/apps/api/lib/validations/shared/queryIdString.ts similarity index 100% rename from lib/validations/shared/queryIdString.ts rename to apps/api/lib/validations/shared/queryIdString.ts diff --git a/lib/validations/shared/queryIdTransformParseInt.ts b/apps/api/lib/validations/shared/queryIdTransformParseInt.ts similarity index 100% rename from lib/validations/shared/queryIdTransformParseInt.ts rename to apps/api/lib/validations/shared/queryIdTransformParseInt.ts diff --git a/lib/validations/shared/queryTeamId.ts b/apps/api/lib/validations/shared/queryTeamId.ts similarity index 100% rename from lib/validations/shared/queryTeamId.ts rename to apps/api/lib/validations/shared/queryTeamId.ts diff --git a/lib/validations/shared/queryUserId.ts b/apps/api/lib/validations/shared/queryUserId.ts similarity index 100% rename from lib/validations/shared/queryUserId.ts rename to apps/api/lib/validations/shared/queryUserId.ts diff --git a/lib/validations/shared/timeZone.ts b/apps/api/lib/validations/shared/timeZone.ts similarity index 100% rename from lib/validations/shared/timeZone.ts rename to apps/api/lib/validations/shared/timeZone.ts diff --git a/lib/validations/team.ts b/apps/api/lib/validations/team.ts similarity index 100% rename from lib/validations/team.ts rename to apps/api/lib/validations/team.ts diff --git a/lib/validations/user.ts b/apps/api/lib/validations/user.ts similarity index 100% rename from lib/validations/user.ts rename to apps/api/lib/validations/user.ts diff --git a/lib/validations/webhook.ts b/apps/api/lib/validations/webhook.ts similarity index 100% rename from lib/validations/webhook.ts rename to apps/api/lib/validations/webhook.ts diff --git a/next-env.d.ts b/apps/api/next-env.d.ts similarity index 100% rename from next-env.d.ts rename to apps/api/next-env.d.ts diff --git a/next-i18next.config.js b/apps/api/next-i18next.config.js similarity index 100% rename from next-i18next.config.js rename to apps/api/next-i18next.config.js diff --git a/next.config.js b/apps/api/next.config.js similarity index 100% rename from next.config.js rename to apps/api/next.config.js diff --git a/next.d.ts b/apps/api/next.d.ts similarity index 100% rename from next.d.ts rename to apps/api/next.d.ts diff --git a/package.json b/apps/api/package.json similarity index 100% rename from package.json rename to apps/api/package.json diff --git a/pages/api/api-keys/[id]/_auth-middleware.ts b/apps/api/pages/api/api-keys/[id]/_auth-middleware.ts similarity index 100% rename from pages/api/api-keys/[id]/_auth-middleware.ts rename to apps/api/pages/api/api-keys/[id]/_auth-middleware.ts diff --git a/pages/api/api-keys/[id]/_delete.ts b/apps/api/pages/api/api-keys/[id]/_delete.ts similarity index 100% rename from pages/api/api-keys/[id]/_delete.ts rename to apps/api/pages/api/api-keys/[id]/_delete.ts diff --git a/pages/api/api-keys/[id]/_get.ts b/apps/api/pages/api/api-keys/[id]/_get.ts similarity index 100% rename from pages/api/api-keys/[id]/_get.ts rename to apps/api/pages/api/api-keys/[id]/_get.ts diff --git a/pages/api/api-keys/[id]/_patch.ts b/apps/api/pages/api/api-keys/[id]/_patch.ts similarity index 100% rename from pages/api/api-keys/[id]/_patch.ts rename to apps/api/pages/api/api-keys/[id]/_patch.ts diff --git a/pages/api/api-keys/[id]/index.ts b/apps/api/pages/api/api-keys/[id]/index.ts similarity index 100% rename from pages/api/api-keys/[id]/index.ts rename to apps/api/pages/api/api-keys/[id]/index.ts diff --git a/pages/api/api-keys/_get.ts b/apps/api/pages/api/api-keys/_get.ts similarity index 100% rename from pages/api/api-keys/_get.ts rename to apps/api/pages/api/api-keys/_get.ts diff --git a/pages/api/api-keys/_post.ts b/apps/api/pages/api/api-keys/_post.ts similarity index 100% rename from pages/api/api-keys/_post.ts rename to apps/api/pages/api/api-keys/_post.ts diff --git a/pages/api/api-keys/index.ts b/apps/api/pages/api/api-keys/index.ts similarity index 100% rename from pages/api/api-keys/index.ts rename to apps/api/pages/api/api-keys/index.ts diff --git a/pages/api/attendees/[id]/_auth-middleware.ts b/apps/api/pages/api/attendees/[id]/_auth-middleware.ts similarity index 100% rename from pages/api/attendees/[id]/_auth-middleware.ts rename to apps/api/pages/api/attendees/[id]/_auth-middleware.ts diff --git a/pages/api/attendees/[id]/_delete.ts b/apps/api/pages/api/attendees/[id]/_delete.ts similarity index 100% rename from pages/api/attendees/[id]/_delete.ts rename to apps/api/pages/api/attendees/[id]/_delete.ts diff --git a/pages/api/attendees/[id]/_get.ts b/apps/api/pages/api/attendees/[id]/_get.ts similarity index 100% rename from pages/api/attendees/[id]/_get.ts rename to apps/api/pages/api/attendees/[id]/_get.ts diff --git a/pages/api/attendees/[id]/_patch.ts b/apps/api/pages/api/attendees/[id]/_patch.ts similarity index 100% rename from pages/api/attendees/[id]/_patch.ts rename to apps/api/pages/api/attendees/[id]/_patch.ts diff --git a/pages/api/attendees/[id]/index.ts b/apps/api/pages/api/attendees/[id]/index.ts similarity index 100% rename from pages/api/attendees/[id]/index.ts rename to apps/api/pages/api/attendees/[id]/index.ts diff --git a/pages/api/attendees/_get.ts b/apps/api/pages/api/attendees/_get.ts similarity index 100% rename from pages/api/attendees/_get.ts rename to apps/api/pages/api/attendees/_get.ts diff --git a/pages/api/attendees/_post.ts b/apps/api/pages/api/attendees/_post.ts similarity index 100% rename from pages/api/attendees/_post.ts rename to apps/api/pages/api/attendees/_post.ts diff --git a/pages/api/attendees/index.ts b/apps/api/pages/api/attendees/index.ts similarity index 100% rename from pages/api/attendees/index.ts rename to apps/api/pages/api/attendees/index.ts diff --git a/pages/api/availabilities/[id]/_auth-middleware.ts b/apps/api/pages/api/availabilities/[id]/_auth-middleware.ts similarity index 100% rename from pages/api/availabilities/[id]/_auth-middleware.ts rename to apps/api/pages/api/availabilities/[id]/_auth-middleware.ts diff --git a/pages/api/availabilities/[id]/_delete.ts b/apps/api/pages/api/availabilities/[id]/_delete.ts similarity index 100% rename from pages/api/availabilities/[id]/_delete.ts rename to apps/api/pages/api/availabilities/[id]/_delete.ts diff --git a/pages/api/availabilities/[id]/_get.ts b/apps/api/pages/api/availabilities/[id]/_get.ts similarity index 100% rename from pages/api/availabilities/[id]/_get.ts rename to apps/api/pages/api/availabilities/[id]/_get.ts diff --git a/pages/api/availabilities/[id]/_patch.ts b/apps/api/pages/api/availabilities/[id]/_patch.ts similarity index 100% rename from pages/api/availabilities/[id]/_patch.ts rename to apps/api/pages/api/availabilities/[id]/_patch.ts diff --git a/pages/api/availabilities/[id]/index.ts b/apps/api/pages/api/availabilities/[id]/index.ts similarity index 100% rename from pages/api/availabilities/[id]/index.ts rename to apps/api/pages/api/availabilities/[id]/index.ts diff --git a/pages/api/availabilities/_post.ts b/apps/api/pages/api/availabilities/_post.ts similarity index 100% rename from pages/api/availabilities/_post.ts rename to apps/api/pages/api/availabilities/_post.ts diff --git a/pages/api/availabilities/index.ts b/apps/api/pages/api/availabilities/index.ts similarity index 100% rename from pages/api/availabilities/index.ts rename to apps/api/pages/api/availabilities/index.ts diff --git a/pages/api/availability/_get.ts b/apps/api/pages/api/availability/_get.ts similarity index 100% rename from pages/api/availability/_get.ts rename to apps/api/pages/api/availability/_get.ts diff --git a/pages/api/availability/index.ts b/apps/api/pages/api/availability/index.ts similarity index 100% rename from pages/api/availability/index.ts rename to apps/api/pages/api/availability/index.ts diff --git a/pages/api/booking-references/[id]/_auth-middleware.ts b/apps/api/pages/api/booking-references/[id]/_auth-middleware.ts similarity index 100% rename from pages/api/booking-references/[id]/_auth-middleware.ts rename to apps/api/pages/api/booking-references/[id]/_auth-middleware.ts diff --git a/pages/api/booking-references/[id]/_delete.ts b/apps/api/pages/api/booking-references/[id]/_delete.ts similarity index 100% rename from pages/api/booking-references/[id]/_delete.ts rename to apps/api/pages/api/booking-references/[id]/_delete.ts diff --git a/pages/api/booking-references/[id]/_get.ts b/apps/api/pages/api/booking-references/[id]/_get.ts similarity index 100% rename from pages/api/booking-references/[id]/_get.ts rename to apps/api/pages/api/booking-references/[id]/_get.ts diff --git a/pages/api/booking-references/[id]/_patch.ts b/apps/api/pages/api/booking-references/[id]/_patch.ts similarity index 100% rename from pages/api/booking-references/[id]/_patch.ts rename to apps/api/pages/api/booking-references/[id]/_patch.ts diff --git a/pages/api/booking-references/[id]/index.ts b/apps/api/pages/api/booking-references/[id]/index.ts similarity index 100% rename from pages/api/booking-references/[id]/index.ts rename to apps/api/pages/api/booking-references/[id]/index.ts diff --git a/pages/api/booking-references/_get.ts b/apps/api/pages/api/booking-references/_get.ts similarity index 100% rename from pages/api/booking-references/_get.ts rename to apps/api/pages/api/booking-references/_get.ts diff --git a/pages/api/booking-references/_post.ts b/apps/api/pages/api/booking-references/_post.ts similarity index 100% rename from pages/api/booking-references/_post.ts rename to apps/api/pages/api/booking-references/_post.ts diff --git a/pages/api/booking-references/index.ts b/apps/api/pages/api/booking-references/index.ts similarity index 100% rename from pages/api/booking-references/index.ts rename to apps/api/pages/api/booking-references/index.ts diff --git a/pages/api/bookings/[id]/_auth-middleware.ts b/apps/api/pages/api/bookings/[id]/_auth-middleware.ts similarity index 100% rename from pages/api/bookings/[id]/_auth-middleware.ts rename to apps/api/pages/api/bookings/[id]/_auth-middleware.ts diff --git a/pages/api/bookings/[id]/_delete.ts b/apps/api/pages/api/bookings/[id]/_delete.ts similarity index 100% rename from pages/api/bookings/[id]/_delete.ts rename to apps/api/pages/api/bookings/[id]/_delete.ts diff --git a/pages/api/bookings/[id]/_get.ts b/apps/api/pages/api/bookings/[id]/_get.ts similarity index 100% rename from pages/api/bookings/[id]/_get.ts rename to apps/api/pages/api/bookings/[id]/_get.ts diff --git a/pages/api/bookings/[id]/_patch.ts b/apps/api/pages/api/bookings/[id]/_patch.ts similarity index 100% rename from pages/api/bookings/[id]/_patch.ts rename to apps/api/pages/api/bookings/[id]/_patch.ts diff --git a/pages/api/bookings/[id]/cancel.ts b/apps/api/pages/api/bookings/[id]/cancel.ts similarity index 100% rename from pages/api/bookings/[id]/cancel.ts rename to apps/api/pages/api/bookings/[id]/cancel.ts diff --git a/pages/api/bookings/[id]/index.ts b/apps/api/pages/api/bookings/[id]/index.ts similarity index 100% rename from pages/api/bookings/[id]/index.ts rename to apps/api/pages/api/bookings/[id]/index.ts diff --git a/pages/api/bookings/_get.ts b/apps/api/pages/api/bookings/_get.ts similarity index 100% rename from pages/api/bookings/_get.ts rename to apps/api/pages/api/bookings/_get.ts diff --git a/pages/api/bookings/_post.ts b/apps/api/pages/api/bookings/_post.ts similarity index 100% rename from pages/api/bookings/_post.ts rename to apps/api/pages/api/bookings/_post.ts diff --git a/pages/api/bookings/index.ts b/apps/api/pages/api/bookings/index.ts similarity index 100% rename from pages/api/bookings/index.ts rename to apps/api/pages/api/bookings/index.ts diff --git a/pages/api/custom-inputs/[id]/_auth-middleware.ts b/apps/api/pages/api/custom-inputs/[id]/_auth-middleware.ts similarity index 100% rename from pages/api/custom-inputs/[id]/_auth-middleware.ts rename to apps/api/pages/api/custom-inputs/[id]/_auth-middleware.ts diff --git a/pages/api/custom-inputs/[id]/_delete.ts b/apps/api/pages/api/custom-inputs/[id]/_delete.ts similarity index 100% rename from pages/api/custom-inputs/[id]/_delete.ts rename to apps/api/pages/api/custom-inputs/[id]/_delete.ts diff --git a/pages/api/custom-inputs/[id]/_get.ts b/apps/api/pages/api/custom-inputs/[id]/_get.ts similarity index 100% rename from pages/api/custom-inputs/[id]/_get.ts rename to apps/api/pages/api/custom-inputs/[id]/_get.ts diff --git a/pages/api/custom-inputs/[id]/_patch.ts b/apps/api/pages/api/custom-inputs/[id]/_patch.ts similarity index 100% rename from pages/api/custom-inputs/[id]/_patch.ts rename to apps/api/pages/api/custom-inputs/[id]/_patch.ts diff --git a/pages/api/custom-inputs/[id]/index.ts b/apps/api/pages/api/custom-inputs/[id]/index.ts similarity index 100% rename from pages/api/custom-inputs/[id]/index.ts rename to apps/api/pages/api/custom-inputs/[id]/index.ts diff --git a/pages/api/custom-inputs/_get.ts b/apps/api/pages/api/custom-inputs/_get.ts similarity index 100% rename from pages/api/custom-inputs/_get.ts rename to apps/api/pages/api/custom-inputs/_get.ts diff --git a/pages/api/custom-inputs/_post.ts b/apps/api/pages/api/custom-inputs/_post.ts similarity index 100% rename from pages/api/custom-inputs/_post.ts rename to apps/api/pages/api/custom-inputs/_post.ts diff --git a/pages/api/custom-inputs/index.ts b/apps/api/pages/api/custom-inputs/index.ts similarity index 100% rename from pages/api/custom-inputs/index.ts rename to apps/api/pages/api/custom-inputs/index.ts diff --git a/pages/api/destination-calendars/[id].ts b/apps/api/pages/api/destination-calendars/[id].ts similarity index 100% rename from pages/api/destination-calendars/[id].ts rename to apps/api/pages/api/destination-calendars/[id].ts diff --git a/pages/api/destination-calendars/index.ts b/apps/api/pages/api/destination-calendars/index.ts similarity index 100% rename from pages/api/destination-calendars/index.ts rename to apps/api/pages/api/destination-calendars/index.ts diff --git a/pages/api/docs.ts b/apps/api/pages/api/docs.ts similarity index 100% rename from pages/api/docs.ts rename to apps/api/pages/api/docs.ts diff --git a/pages/api/event-types/[id]/_auth-middleware.ts b/apps/api/pages/api/event-types/[id]/_auth-middleware.ts similarity index 100% rename from pages/api/event-types/[id]/_auth-middleware.ts rename to apps/api/pages/api/event-types/[id]/_auth-middleware.ts diff --git a/pages/api/event-types/[id]/_delete.ts b/apps/api/pages/api/event-types/[id]/_delete.ts similarity index 100% rename from pages/api/event-types/[id]/_delete.ts rename to apps/api/pages/api/event-types/[id]/_delete.ts diff --git a/pages/api/event-types/[id]/_get.ts b/apps/api/pages/api/event-types/[id]/_get.ts similarity index 100% rename from pages/api/event-types/[id]/_get.ts rename to apps/api/pages/api/event-types/[id]/_get.ts diff --git a/pages/api/event-types/[id]/_patch.ts b/apps/api/pages/api/event-types/[id]/_patch.ts similarity index 100% rename from pages/api/event-types/[id]/_patch.ts rename to apps/api/pages/api/event-types/[id]/_patch.ts diff --git a/pages/api/event-types/[id]/index.ts b/apps/api/pages/api/event-types/[id]/index.ts similarity index 100% rename from pages/api/event-types/[id]/index.ts rename to apps/api/pages/api/event-types/[id]/index.ts diff --git a/pages/api/event-types/_get.ts b/apps/api/pages/api/event-types/_get.ts similarity index 100% rename from pages/api/event-types/_get.ts rename to apps/api/pages/api/event-types/_get.ts diff --git a/pages/api/event-types/_post.ts b/apps/api/pages/api/event-types/_post.ts similarity index 100% rename from pages/api/event-types/_post.ts rename to apps/api/pages/api/event-types/_post.ts diff --git a/pages/api/event-types/_utils/checkTeamEventEditPermission.ts b/apps/api/pages/api/event-types/_utils/checkTeamEventEditPermission.ts similarity index 100% rename from pages/api/event-types/_utils/checkTeamEventEditPermission.ts rename to apps/api/pages/api/event-types/_utils/checkTeamEventEditPermission.ts diff --git a/pages/api/event-types/_utils/ensureOnlyMembersAsHosts.ts b/apps/api/pages/api/event-types/_utils/ensureOnlyMembersAsHosts.ts similarity index 100% rename from pages/api/event-types/_utils/ensureOnlyMembersAsHosts.ts rename to apps/api/pages/api/event-types/_utils/ensureOnlyMembersAsHosts.ts diff --git a/pages/api/event-types/_utils/getCalLink.ts b/apps/api/pages/api/event-types/_utils/getCalLink.ts similarity index 100% rename from pages/api/event-types/_utils/getCalLink.ts rename to apps/api/pages/api/event-types/_utils/getCalLink.ts diff --git a/pages/api/event-types/index.ts b/apps/api/pages/api/event-types/index.ts similarity index 100% rename from pages/api/event-types/index.ts rename to apps/api/pages/api/event-types/index.ts diff --git a/pages/api/index.ts b/apps/api/pages/api/index.ts similarity index 100% rename from pages/api/index.ts rename to apps/api/pages/api/index.ts diff --git a/pages/api/me/_get.ts b/apps/api/pages/api/me/_get.ts similarity index 100% rename from pages/api/me/_get.ts rename to apps/api/pages/api/me/_get.ts diff --git a/pages/api/me/index.ts b/apps/api/pages/api/me/index.ts similarity index 100% rename from pages/api/me/index.ts rename to apps/api/pages/api/me/index.ts diff --git a/pages/api/memberships/[id]/_auth-middleware.ts b/apps/api/pages/api/memberships/[id]/_auth-middleware.ts similarity index 100% rename from pages/api/memberships/[id]/_auth-middleware.ts rename to apps/api/pages/api/memberships/[id]/_auth-middleware.ts diff --git a/pages/api/memberships/[id]/_delete.ts b/apps/api/pages/api/memberships/[id]/_delete.ts similarity index 100% rename from pages/api/memberships/[id]/_delete.ts rename to apps/api/pages/api/memberships/[id]/_delete.ts diff --git a/pages/api/memberships/[id]/_get.ts b/apps/api/pages/api/memberships/[id]/_get.ts similarity index 100% rename from pages/api/memberships/[id]/_get.ts rename to apps/api/pages/api/memberships/[id]/_get.ts diff --git a/pages/api/memberships/[id]/_patch.ts b/apps/api/pages/api/memberships/[id]/_patch.ts similarity index 100% rename from pages/api/memberships/[id]/_patch.ts rename to apps/api/pages/api/memberships/[id]/_patch.ts diff --git a/pages/api/memberships/[id]/index.ts b/apps/api/pages/api/memberships/[id]/index.ts similarity index 100% rename from pages/api/memberships/[id]/index.ts rename to apps/api/pages/api/memberships/[id]/index.ts diff --git a/pages/api/memberships/_get.ts b/apps/api/pages/api/memberships/_get.ts similarity index 100% rename from pages/api/memberships/_get.ts rename to apps/api/pages/api/memberships/_get.ts diff --git a/pages/api/memberships/_post.ts b/apps/api/pages/api/memberships/_post.ts similarity index 100% rename from pages/api/memberships/_post.ts rename to apps/api/pages/api/memberships/_post.ts diff --git a/pages/api/memberships/index.ts b/apps/api/pages/api/memberships/index.ts similarity index 100% rename from pages/api/memberships/index.ts rename to apps/api/pages/api/memberships/index.ts diff --git a/pages/api/payments/[id].ts b/apps/api/pages/api/payments/[id].ts similarity index 100% rename from pages/api/payments/[id].ts rename to apps/api/pages/api/payments/[id].ts diff --git a/pages/api/payments/index.ts b/apps/api/pages/api/payments/index.ts similarity index 100% rename from pages/api/payments/index.ts rename to apps/api/pages/api/payments/index.ts diff --git a/pages/api/schedules/[id]/_auth-middleware.ts b/apps/api/pages/api/schedules/[id]/_auth-middleware.ts similarity index 100% rename from pages/api/schedules/[id]/_auth-middleware.ts rename to apps/api/pages/api/schedules/[id]/_auth-middleware.ts diff --git a/pages/api/schedules/[id]/_delete.ts b/apps/api/pages/api/schedules/[id]/_delete.ts similarity index 100% rename from pages/api/schedules/[id]/_delete.ts rename to apps/api/pages/api/schedules/[id]/_delete.ts diff --git a/pages/api/schedules/[id]/_get.ts b/apps/api/pages/api/schedules/[id]/_get.ts similarity index 100% rename from pages/api/schedules/[id]/_get.ts rename to apps/api/pages/api/schedules/[id]/_get.ts diff --git a/pages/api/schedules/[id]/_patch.ts b/apps/api/pages/api/schedules/[id]/_patch.ts similarity index 100% rename from pages/api/schedules/[id]/_patch.ts rename to apps/api/pages/api/schedules/[id]/_patch.ts diff --git a/pages/api/schedules/[id]/index.ts b/apps/api/pages/api/schedules/[id]/index.ts similarity index 100% rename from pages/api/schedules/[id]/index.ts rename to apps/api/pages/api/schedules/[id]/index.ts diff --git a/pages/api/schedules/_get.ts b/apps/api/pages/api/schedules/_get.ts similarity index 100% rename from pages/api/schedules/_get.ts rename to apps/api/pages/api/schedules/_get.ts diff --git a/pages/api/schedules/_post.ts b/apps/api/pages/api/schedules/_post.ts similarity index 100% rename from pages/api/schedules/_post.ts rename to apps/api/pages/api/schedules/_post.ts diff --git a/pages/api/schedules/index.ts b/apps/api/pages/api/schedules/index.ts similarity index 100% rename from pages/api/schedules/index.ts rename to apps/api/pages/api/schedules/index.ts diff --git a/pages/api/selected-calendars/[id]/_auth-middleware.ts b/apps/api/pages/api/selected-calendars/[id]/_auth-middleware.ts similarity index 100% rename from pages/api/selected-calendars/[id]/_auth-middleware.ts rename to apps/api/pages/api/selected-calendars/[id]/_auth-middleware.ts diff --git a/pages/api/selected-calendars/[id]/_delete.ts b/apps/api/pages/api/selected-calendars/[id]/_delete.ts similarity index 100% rename from pages/api/selected-calendars/[id]/_delete.ts rename to apps/api/pages/api/selected-calendars/[id]/_delete.ts diff --git a/pages/api/selected-calendars/[id]/_get.ts b/apps/api/pages/api/selected-calendars/[id]/_get.ts similarity index 100% rename from pages/api/selected-calendars/[id]/_get.ts rename to apps/api/pages/api/selected-calendars/[id]/_get.ts diff --git a/pages/api/selected-calendars/[id]/_patch.ts b/apps/api/pages/api/selected-calendars/[id]/_patch.ts similarity index 100% rename from pages/api/selected-calendars/[id]/_patch.ts rename to apps/api/pages/api/selected-calendars/[id]/_patch.ts diff --git a/pages/api/selected-calendars/[id]/index.ts b/apps/api/pages/api/selected-calendars/[id]/index.ts similarity index 100% rename from pages/api/selected-calendars/[id]/index.ts rename to apps/api/pages/api/selected-calendars/[id]/index.ts diff --git a/pages/api/selected-calendars/_get.ts b/apps/api/pages/api/selected-calendars/_get.ts similarity index 100% rename from pages/api/selected-calendars/_get.ts rename to apps/api/pages/api/selected-calendars/_get.ts diff --git a/pages/api/selected-calendars/_post.ts b/apps/api/pages/api/selected-calendars/_post.ts similarity index 100% rename from pages/api/selected-calendars/_post.ts rename to apps/api/pages/api/selected-calendars/_post.ts diff --git a/pages/api/selected-calendars/index.ts b/apps/api/pages/api/selected-calendars/index.ts similarity index 100% rename from pages/api/selected-calendars/index.ts rename to apps/api/pages/api/selected-calendars/index.ts diff --git a/pages/api/teams/[teamId]/_auth-middleware.ts b/apps/api/pages/api/teams/[teamId]/_auth-middleware.ts similarity index 100% rename from pages/api/teams/[teamId]/_auth-middleware.ts rename to apps/api/pages/api/teams/[teamId]/_auth-middleware.ts diff --git a/pages/api/teams/[teamId]/_delete.ts b/apps/api/pages/api/teams/[teamId]/_delete.ts similarity index 100% rename from pages/api/teams/[teamId]/_delete.ts rename to apps/api/pages/api/teams/[teamId]/_delete.ts diff --git a/pages/api/teams/[teamId]/_get.ts b/apps/api/pages/api/teams/[teamId]/_get.ts similarity index 100% rename from pages/api/teams/[teamId]/_get.ts rename to apps/api/pages/api/teams/[teamId]/_get.ts diff --git a/pages/api/teams/[teamId]/_patch.ts b/apps/api/pages/api/teams/[teamId]/_patch.ts similarity index 100% rename from pages/api/teams/[teamId]/_patch.ts rename to apps/api/pages/api/teams/[teamId]/_patch.ts diff --git a/pages/api/teams/[teamId]/availability/index.ts b/apps/api/pages/api/teams/[teamId]/availability/index.ts similarity index 100% rename from pages/api/teams/[teamId]/availability/index.ts rename to apps/api/pages/api/teams/[teamId]/availability/index.ts diff --git a/pages/api/teams/[teamId]/event-types/_get.ts b/apps/api/pages/api/teams/[teamId]/event-types/_get.ts similarity index 100% rename from pages/api/teams/[teamId]/event-types/_get.ts rename to apps/api/pages/api/teams/[teamId]/event-types/_get.ts diff --git a/pages/api/teams/[teamId]/event-types/index.ts b/apps/api/pages/api/teams/[teamId]/event-types/index.ts similarity index 100% rename from pages/api/teams/[teamId]/event-types/index.ts rename to apps/api/pages/api/teams/[teamId]/event-types/index.ts diff --git a/pages/api/teams/[teamId]/index.ts b/apps/api/pages/api/teams/[teamId]/index.ts similarity index 100% rename from pages/api/teams/[teamId]/index.ts rename to apps/api/pages/api/teams/[teamId]/index.ts diff --git a/pages/api/teams/[teamId]/publish.ts b/apps/api/pages/api/teams/[teamId]/publish.ts similarity index 100% rename from pages/api/teams/[teamId]/publish.ts rename to apps/api/pages/api/teams/[teamId]/publish.ts diff --git a/pages/api/teams/_get.ts b/apps/api/pages/api/teams/_get.ts similarity index 100% rename from pages/api/teams/_get.ts rename to apps/api/pages/api/teams/_get.ts diff --git a/pages/api/teams/_post.ts b/apps/api/pages/api/teams/_post.ts similarity index 100% rename from pages/api/teams/_post.ts rename to apps/api/pages/api/teams/_post.ts diff --git a/pages/api/teams/index.ts b/apps/api/pages/api/teams/index.ts similarity index 100% rename from pages/api/teams/index.ts rename to apps/api/pages/api/teams/index.ts diff --git a/pages/api/users/[userId]/_delete.ts b/apps/api/pages/api/users/[userId]/_delete.ts similarity index 100% rename from pages/api/users/[userId]/_delete.ts rename to apps/api/pages/api/users/[userId]/_delete.ts diff --git a/pages/api/users/[userId]/_get.ts b/apps/api/pages/api/users/[userId]/_get.ts similarity index 100% rename from pages/api/users/[userId]/_get.ts rename to apps/api/pages/api/users/[userId]/_get.ts diff --git a/pages/api/users/[userId]/_patch.ts b/apps/api/pages/api/users/[userId]/_patch.ts similarity index 100% rename from pages/api/users/[userId]/_patch.ts rename to apps/api/pages/api/users/[userId]/_patch.ts diff --git a/pages/api/users/[userId]/availability/index.ts b/apps/api/pages/api/users/[userId]/availability/index.ts similarity index 100% rename from pages/api/users/[userId]/availability/index.ts rename to apps/api/pages/api/users/[userId]/availability/index.ts diff --git a/pages/api/users/[userId]/index.ts b/apps/api/pages/api/users/[userId]/index.ts similarity index 100% rename from pages/api/users/[userId]/index.ts rename to apps/api/pages/api/users/[userId]/index.ts diff --git a/pages/api/users/_get.ts b/apps/api/pages/api/users/_get.ts similarity index 100% rename from pages/api/users/_get.ts rename to apps/api/pages/api/users/_get.ts diff --git a/pages/api/users/_post.ts b/apps/api/pages/api/users/_post.ts similarity index 100% rename from pages/api/users/_post.ts rename to apps/api/pages/api/users/_post.ts diff --git a/pages/api/users/index.ts b/apps/api/pages/api/users/index.ts similarity index 100% rename from pages/api/users/index.ts rename to apps/api/pages/api/users/index.ts diff --git a/pages/api/webhooks/[id]/_auth-middleware.ts b/apps/api/pages/api/webhooks/[id]/_auth-middleware.ts similarity index 100% rename from pages/api/webhooks/[id]/_auth-middleware.ts rename to apps/api/pages/api/webhooks/[id]/_auth-middleware.ts diff --git a/pages/api/webhooks/[id]/_delete.ts b/apps/api/pages/api/webhooks/[id]/_delete.ts similarity index 100% rename from pages/api/webhooks/[id]/_delete.ts rename to apps/api/pages/api/webhooks/[id]/_delete.ts diff --git a/pages/api/webhooks/[id]/_get.ts b/apps/api/pages/api/webhooks/[id]/_get.ts similarity index 100% rename from pages/api/webhooks/[id]/_get.ts rename to apps/api/pages/api/webhooks/[id]/_get.ts diff --git a/pages/api/webhooks/[id]/_patch.ts b/apps/api/pages/api/webhooks/[id]/_patch.ts similarity index 100% rename from pages/api/webhooks/[id]/_patch.ts rename to apps/api/pages/api/webhooks/[id]/_patch.ts diff --git a/pages/api/webhooks/[id]/index.ts b/apps/api/pages/api/webhooks/[id]/index.ts similarity index 100% rename from pages/api/webhooks/[id]/index.ts rename to apps/api/pages/api/webhooks/[id]/index.ts diff --git a/pages/api/webhooks/_get.ts b/apps/api/pages/api/webhooks/_get.ts similarity index 100% rename from pages/api/webhooks/_get.ts rename to apps/api/pages/api/webhooks/_get.ts diff --git a/pages/api/webhooks/_post.ts b/apps/api/pages/api/webhooks/_post.ts similarity index 100% rename from pages/api/webhooks/_post.ts rename to apps/api/pages/api/webhooks/_post.ts diff --git a/pages/api/webhooks/index.ts b/apps/api/pages/api/webhooks/index.ts similarity index 100% rename from pages/api/webhooks/index.ts rename to apps/api/pages/api/webhooks/index.ts diff --git a/scripts/vercel-deploy.sh b/apps/api/scripts/vercel-deploy.sh similarity index 100% rename from scripts/vercel-deploy.sh rename to apps/api/scripts/vercel-deploy.sh diff --git a/test/README.md b/apps/api/test/README.md similarity index 100% rename from test/README.md rename to apps/api/test/README.md diff --git a/test/docker-compose.yml b/apps/api/test/docker-compose.yml similarity index 100% rename from test/docker-compose.yml rename to apps/api/test/docker-compose.yml diff --git a/test/jest-resolver.js b/apps/api/test/jest-resolver.js similarity index 100% rename from test/jest-resolver.js rename to apps/api/test/jest-resolver.js diff --git a/test/jest-setup.js b/apps/api/test/jest-setup.js similarity index 100% rename from test/jest-setup.js rename to apps/api/test/jest-setup.js diff --git a/test/lib/bookings/_post.test.ts b/apps/api/test/lib/bookings/_post.test.ts similarity index 100% rename from test/lib/bookings/_post.test.ts rename to apps/api/test/lib/bookings/_post.test.ts diff --git a/tsconfig.json b/apps/api/tsconfig.json similarity index 100% rename from tsconfig.json rename to apps/api/tsconfig.json From fa131e034015f014a1abc6689051ab4e3ab04946 Mon Sep 17 00:00:00 2001 From: zomars Date: Tue, 23 May 2023 13:12:58 -0700 Subject: [PATCH 630/658] Updates git init scripts --- .gitignore | 1 - git-init.sh | 2 +- git-setup.sh | 10 ++-------- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/.gitignore b/.gitignore index 28ce05562d..a89fca99ab 100644 --- a/.gitignore +++ b/.gitignore @@ -84,7 +84,6 @@ apps/storybook/build-storybook.log # Submodules .gitmodules -apps/api apps/website apps/console apps/auth diff --git a/git-init.sh b/git-init.sh index 045c134681..a480c0c3d4 100755 --- a/git-init.sh +++ b/git-init.sh @@ -5,4 +5,4 @@ exit 0 } -./git-setup.sh api website console +./git-setup.sh website console diff --git a/git-setup.sh b/git-setup.sh index 9524ce21af..f9deccf6d5 100755 --- a/git-setup.sh +++ b/git-setup.sh @@ -2,7 +2,7 @@ # If no project name is given if [ $# -eq 0 ]; then # Display usage and stop - echo "Usage: git-setup.sh " + echo "Usage: git-setup.sh " exit 1 fi # Get remote url to support either https or ssh @@ -30,13 +30,7 @@ for module in "$@"; do # We forcefully added the subdmoule which was in .gitignore, so unstage it. git restore --staged apps/$module else - # If the module is the API, display a link to request access - if [ "$module" = "api" ]; then - echo "You don't have access to: '${module}' module. You can request access in: https://console.cal.com" - else - # If the module is not the API, display normal message - echo "You don't have access to: '${module}' module." - fi + echo "You don't have access to: '${module}' module." fi done git restore --staged .gitmodules From b9116f69ae2919bd94e13cca38ad850631cd99cb Mon Sep 17 00:00:00 2001 From: Peer Richelsen Date: Thu, 25 May 2023 12:18:37 +0100 Subject: [PATCH 631/658] removing commercial license in favour of AGPLv3 --- apps/api/apps/api/LICENSE | 42 --------------------------------------- 1 file changed, 42 deletions(-) delete mode 100644 apps/api/apps/api/LICENSE diff --git a/apps/api/apps/api/LICENSE b/apps/api/apps/api/LICENSE deleted file mode 100644 index fa89efec90..0000000000 --- a/apps/api/apps/api/LICENSE +++ /dev/null @@ -1,42 +0,0 @@ -The Cal.com Enterprise Edition (EE) license (the “EE License”) -Copyright (c) 2020-present Cal.com, Inc - -With regard to the Cal.com Software: - -This software and associated documentation files (the "Software") may only be -used in production, if you (and any entity that you represent) have agreed to, -and are in compliance with, the Cal.com Subscription Terms available -at https://cal.com/terms (the “EE Terms”), or other agreements governing -the use of the Software, as mutually agreed by you and Cal.com, Inc ("Cal.com"), -and otherwise have a valid Cal.com Enterprise Edition subscription ("EE Subscription") -for the correct number of hosts as defined in the EE Terms ("Hosts"). Subject to the foregoing sentence, -you are free to modify this Software and publish patches to the Software. You agree -that Cal.com and/or its licensors (as applicable) retain all right, title and interest in -and to all such modifications and/or patches, and all such modifications and/or -patches may only be used, copied, modified, displayed, distributed, or otherwise -exploited with a valid EE Subscription for the correct number of hosts. -Notwithstanding the foregoing, you may copy and modify the Software for development -and testing purposes, without requiring a subscription. You agree that Cal.com and/or -its licensors (as applicable) retain all right, title and interest in and to all such -modifications. You are not granted any other rights beyond what is expressly stated herein. -Subject to the foregoing, it is forbidden to copy, merge, publish, distribute, sublicense, -and/or sell the Software. - -This EE License applies only to the part of this Software that is not distributed under -the AGPLv3 license. Any part of this Software distributed under the MIT license or which -is served client-side as an image, font, cascading stylesheet (CSS), file which produces -or is compiled, arranged, augmented, or combined into client-side JavaScript, in whole or -in part, is copyrighted under the AGPLv3 license. The full text of this EE License shall -be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -For all third party components incorporated into the Cal.com Software, those -components are licensed under the original license provided by the owner of the -applicable component. \ No newline at end of file From d6c73621624842ec1ceb79d2846e05f37acab424 Mon Sep 17 00:00:00 2001 From: Peer Richelsen Date: Thu, 25 May 2023 12:22:18 +0100 Subject: [PATCH 632/658] removing commercial language from readme --- apps/api/apps/api/README.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/apps/api/apps/api/README.md b/apps/api/apps/api/README.md index c31304595b..6601764d73 100644 --- a/apps/api/apps/api/README.md +++ b/apps/api/apps/api/README.md @@ -1,19 +1,15 @@ -# Cal.com Public API - Enterprise Edition +# Cal.com Public API -Welcome to the Public API Enterprise Edition ("/apps/api") of the Cal.com Public API. - -The [/apps/api](https://github.com/calcom/cal.com/tree/main/apps/api) subfolder is the place for our Public API, which we serve at api.cal.com, and enterprise customers can also run [enterprise-grade](https://cal.com/enterprise) - -> _❗ WARNING: This repository is copyrighted (unlike our [main repo](https://github.com/calcom/cal.com)). You are not allowed to use this code to host your own version of app.cal.com without obtaining a proper [license](https://cal.com/pricing?infra) first❗_ +Welcome to the Public API ("/apps/api") of the Cal.com. This is the public REST api for cal.com. It exposes CRUD Endpoints of all our most important resources. From cff134efc6a1b8a577dc282be27fce02af1f2cb8 Mon Sep 17 00:00:00 2001 From: Peer Richelsen Date: Thu, 25 May 2023 16:48:11 +0100 Subject: [PATCH 633/658] chore: delete code owners (#9112) its causing more harm than good. We ideally wanna tag people based on a per-PR basis not pure file-basis we can bring it back later --- .github/CODEOWNERS | 70 ---------------------------------------------- 1 file changed, 70 deletions(-) delete mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 52cd9dec28..0000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,70 +0,0 @@ -# This is a comment. -# Each line is a file pattern followed by one or more owners. - -# These owners will be the default owners for everything in -# the repo. Unless a later match takes precedence, -# @global-owner1 and @global-owner2 will be requested for -# review when someone opens a pull request. - -# ⬇️ Current Teams -# @calcom/app-store # https://github.com/orgs/calcom/teams/app-store -# @calcom/authentication # https://github.com/orgs/calcom/teams/authentication -# @calcom/automated-testing # https://github.com/orgs/calcom/teams/automated-testing -# @calcom/billing # https://github.com/orgs/calcom/teams/billing -# @calcom/bookings # https://github.com/orgs/calcom/teams/bookings -# @calcom/caldav # https://github.com/orgs/calcom/teams/caldav -# @calcom/calendar-apps # https://github.com/orgs/calcom/teams/calendar-apps -# @calcom/ci-dx # https://github.com/orgs/calcom/teams/ci-dx -# @calcom/console # https://github.com/orgs/calcom/teams/console -# @calcom/crm-apps # https://github.com/orgs/calcom/teams/crm-apps -# @calcom/desktop-app # https://github.com/orgs/calcom/teams/desktop-app -# @calcom/docker # https://github.com/orgs/calcom/teams/docker -# @calcom/docs # https://github.com/orgs/calcom/teams/docs -# @calcom/documentation # https://github.com/orgs/calcom/teams/documentation -# @calcom/embeds # https://github.com/orgs/calcom/teams/embeds -# @calcom/event-types # https://github.com/orgs/calcom/teams/event-types -# @calcom/impersonation # https://github.com/orgs/calcom/teams/impersonation -# @calcom/ops-stack # https://github.com/orgs/calcom/teams/ops-stack -# @calcom/public-api # https://github.com/orgs/calcom/teams/public-api -# @calcom/routing-forms # https://github.com/orgs/calcom/teams/routing-forms -# @calcom/seats # https://github.com/orgs/calcom/teams/seats -# @calcom/teams # https://github.com/orgs/calcom/teams/teams -# @calcom/ui # https://github.com/orgs/calcom/teams/ui -# @calcom/webhooks # https://github.com/orgs/calcom/teams/webhooks -# @calcom/workflows # https://github.com/orgs/calcom/teams/workflows -# @calcom/zapier # https://github.com/orgs/calcom/teams/zapier - - -.github/ @calcom/ci-dx -.husky/ @calcom/ci-dx -.vcode/ @calcom/ci-dx -deploy/ @calcom/ci-dx -scripts/ @calcom/ci-dx - -apps/swagger @calcom/docs -apps/web/playwright @calcom/automated-testing -packages/app-store-cli @calcom/app-store -packages/app-store/routing-forms @calcom/routing-forms -packages/app-store/applecalendar @calcom/caldav -packages/app-store/caldavcalendar @calcom/caldav -packages/app-store/googlecalendar @calcom/calendar-apps -packages/app-store/exchange2013calendar @calcom/calendar-apps -packages/app-store/exchange2016calendar @calcom/calendar-apps -packages/app-store/larkcalendar @calcom/calendar-apps -packages/app-store/office365calendar @calcom/calendar-apps -packages/config @calcom/leads -packages/core @calcom/bookings -packages/dayjs @calcom/leads -packages/emails @calcom/leads -packages/embeds @calcom/embeds -packages/eslint-plugin @calcom/leads -packages/features @calcom/leads -packages/features/bookings @calcom/bookings -packages/features/ee/impersonation @calcom/impersonation -packages/features/ee/payments @calcom/billing -packages/features/ee/workflows @calcom/workflows -packages/features/kbar @alishaz-polymath -packages/features/tips @PeerRich -packages/features/webhooks @calcom/webhooks -packages/ui @calcom/ui -playwright.config.ts @calcom/automated-testing From bbf93a74352cd5eda5c7be81cd49ece2d431b45b Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Thu, 25 May 2023 15:49:09 +0000 Subject: [PATCH 634/658] New Crowdin translations by Github Action --- apps/web/public/static/locales/de/common.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/web/public/static/locales/de/common.json b/apps/web/public/static/locales/de/common.json index f773f7dcec..586004142c 100644 --- a/apps/web/public/static/locales/de/common.json +++ b/apps/web/public/static/locales/de/common.json @@ -1326,7 +1326,7 @@ "exchange_version_2013_SP1": "2013 SP1", "exchange_version_2015": "2015", "exchange_version_2016": "2016", - "routing_forms_description": "Hier sehen Sie alle Formulare und Weiterleitungen, die Sie erstellt haben.", + "routing_forms_description": "Erstellen Sie Formulare , um Teilnehmer zu den richtigen Stellen weiterzuleiten", "routing_forms_send_email_owner": "E-Mail an Eigentümer senden", "routing_forms_send_email_owner_description": "Sendet eine E-Mail an den Eigentümer, wenn das Formular abgeschickt wird", "add_new_form": "Neues Formular hinzufügen", @@ -1704,8 +1704,8 @@ "can_you_try_again": "Können Sie es zu einem anderen Zeitpunkt erneut versuchen?", "verify": "Bestätigen", "timezone_variable": "Zeitzone", - "timezone_info": "Die Zeitzone der empfangenen Person", - "event_end_time_variable": "Ereignis-Endzeitpunkt", + "timezone_info": "Die Zeitzone der empfangenden Person", + "event_end_time_variable": "Endzeitpunkt des Ereignisses", "event_end_time_info": "Der Endzeitpunkt des Termins", "cancel_url_variable": "Absage-URL", "cancel_url_info": "Die URL, um die Buchung abzusagen", @@ -1732,7 +1732,7 @@ "managed_event_dialog_title_other": "Die URL /{{slug}} ist bereits für {{count}} Mitglieder vorhanden. Möchten Sie sie ersetzen?", "managed_event_dialog_information_one": "{{names}} verwendet bereits die /{{slug}}-URL.", "managed_event_dialog_information_other": "{{names}} verwenden bereits die /{{slug}}-URL.", - "managed_event_dialog_clarification": "Wenn Sie die URL ersetzen, werden wir sie benachrichtigen. Gehen Sie zurück und entfernen Sie sie, wenn Sie ihn nicht überschreiben möchten.", + "managed_event_dialog_clarification": "Wenn Sie die URL ersetzen, werden wir sie benachrichtigen. Gehen Sie zurück und entfernen Sie sie, wenn Sie sie nicht überschreiben möchten.", "review_event_type": "Ereignistyp überprüfen", "looking_for_more_analytics": "Suchen Sie nach weiteren Analysedaten?", "looking_for_more_insights": "Suchen Sie nach weiteren Einsichten?", @@ -1778,7 +1778,7 @@ "insights_no_data_found_for_filter": "Keine Daten für den ausgewählten Filter oder das ausgewählte Datum gefunden.", "acknowledge_booking_no_show_fee": "Ich bestätige, dass meiner Karte eine Gebühr von {{amount, currency}} berechnet wird, sofern ich nicht an diesem Ereignis teilnehme.", "card_details": "Karteninformationen", - "seats_and_no_show_fee_error": "Aktuell können keine Plätze aktiviert werden oder eine Gebühr für das Nichterscheinen berechnet werden", + "seats_and_no_show_fee_error": "Aktuell können keine Plätze aktiviert oder eine Gebühr für das Nichterscheinen berechnet werden", "complete_your_booking": "Schließen Sie Ihre Buchung ab", "complete_your_booking_subject": "Schließen Sie Ihre Buchung ab: {{title}} am {{date}}", "email_invite_team": "{{email}} wurde eingeladen" From abc9dfdaf47ec67a903c2809679a46ec15571ade Mon Sep 17 00:00:00 2001 From: Nafees Nazik <84864519+G3root@users.noreply.github.com> Date: Thu, 25 May 2023 21:20:56 +0530 Subject: [PATCH 635/658] fix: translate (#9108) --- .../AttendeeWasRequestedToRescheduleEmail.tsx | 44 ++++++++++--------- ...endee-was-requested-to-reschedule-email.ts | 7 +-- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/packages/emails/src/templates/AttendeeWasRequestedToRescheduleEmail.tsx b/packages/emails/src/templates/AttendeeWasRequestedToRescheduleEmail.tsx index 256e77596b..fe45ce2aca 100644 --- a/packages/emails/src/templates/AttendeeWasRequestedToRescheduleEmail.tsx +++ b/packages/emails/src/templates/AttendeeWasRequestedToRescheduleEmail.tsx @@ -3,23 +3,27 @@ import { OrganizerScheduledEmail } from "./OrganizerScheduledEmail"; export const AttendeeWasRequestedToRescheduleEmail = ( props: { metadata: { rescheduleLink: string } } & React.ComponentProps -) => ( - - {props.calEvent.organizer.language.translate("request_reschedule_subtitle", { - organizer: props.calEvent.organizer.name, - })} - - } - headerType="calendarCircle" - subject="rescheduled_event_type_subject" - callToAction={ - - - - } - {...props} - /> -); +) => { + const t = props.attendee.language.translate; + return ( + + {t("request_reschedule_subtitle", { + organizer: props.calEvent.organizer.name, + })} + + } + headerType="calendarCircle" + subject="rescheduled_event_type_subject" + callToAction={ + + + + } + {...props} + /> + ); +}; diff --git a/packages/emails/templates/attendee-was-requested-to-reschedule-email.ts b/packages/emails/templates/attendee-was-requested-to-reschedule-email.ts index 6b4ca01e82..881c9890e5 100644 --- a/packages/emails/templates/attendee-was-requested-to-reschedule-email.ts +++ b/packages/emails/templates/attendee-was-requested-to-reschedule-email.ts @@ -1,10 +1,10 @@ -import type { DateArray, Person } from "ics"; +import type { DateArray } from "ics"; import { createEvent } from "ics"; import dayjs from "@calcom/dayjs"; import { getManageLink } from "@calcom/lib/CalEventParser"; import { APP_NAME } from "@calcom/lib/constants"; -import type { CalendarEvent } from "@calcom/types/Calendar"; +import type { CalendarEvent, Person } from "@calcom/types/Calendar"; import { renderEmail } from ".."; import OrganizerScheduledEmail from "./organizer-scheduled-email"; @@ -14,6 +14,7 @@ export default class AttendeeWasRequestedToRescheduleEmail extends OrganizerSche constructor(calEvent: CalendarEvent, metadata: { rescheduleLink: string }) { super({ calEvent }); this.metadata = metadata; + this.t = this.calEvent.attendees[0].language.translate; } protected getNodeMailerPayload(): Record { const toAddresses = [this.calEvent.attendees[0].email]; @@ -31,7 +32,7 @@ export default class AttendeeWasRequestedToRescheduleEmail extends OrganizerSche })}`, html: renderEmail("AttendeeWasRequestedToRescheduleEmail", { calEvent: this.calEvent, - attendee: this.calEvent.organizer, + attendee: this.calEvent.attendees[0], metadata: this.metadata, }), text: this.getTextBody(), From 0f0943066e12201e8f5b095dccd4558291cf068a Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Thu, 25 May 2023 16:15:05 +0000 Subject: [PATCH 636/658] New Crowdin translations by Github Action --- apps/web/public/static/locales/pl/common.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/public/static/locales/pl/common.json b/apps/web/public/static/locales/pl/common.json index 272cb65195..ea52d26c94 100644 --- a/apps/web/public/static/locales/pl/common.json +++ b/apps/web/public/static/locales/pl/common.json @@ -601,8 +601,8 @@ "no_assigned_members": "Brak przypisanych członków", "assigned_to": "Przypisano do:", "start_assigning_members_above": "Rozpocznij przypisywanie członków powyżej", - "locked_fields_admin_description": "Członkowie nie będą mogli tego edytować.", - "locked_fields_member_description": "Ta opcja została zablokowana przez administratora zespołu.", + "locked_fields_admin_description": "Członkowie nie będą mogli tego edytować", + "locked_fields_member_description": "Ta opcja została zablokowana przez administratora zespołu", "url": "Adres URL", "hidden": "Ukryte", "readonly": "Tylko do odczytu", From 9042bba3129b3b3f13247a9e8c9c46c7b6c2c393 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Thu, 25 May 2023 16:16:02 +0000 Subject: [PATCH 637/658] New Crowdin translations by Github Action --- apps/web/public/static/locales/pl/common.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/web/public/static/locales/pl/common.json b/apps/web/public/static/locales/pl/common.json index ea52d26c94..016be948b5 100644 --- a/apps/web/public/static/locales/pl/common.json +++ b/apps/web/public/static/locales/pl/common.json @@ -1154,7 +1154,7 @@ "variable_format": "Format zmiennej", "webhook_subscriber_url_reserved": "Adres URL subskrybenta Webhook jest już zdefiniowany.", "custom_input_as_variable_info": "Ignoruj wszystkie znaki specjalne etykiety dodatkowych danych wejściowych (używaj tylko liter i cyfr), użyj wielkich liter w przypadku wszystkich liter i zastąp spacje znakami podkreślenia.", - "using_booking_questions_as_variables": "Jak mogę używać pytań dotyczących rezerwacji jako zmiennych?", + "using_booking_questions_as_variables": "Jak używać pytań dotyczących rezerwacji jako zmiennych?", "download_desktop_app": "Pobierz aplikację komputerową", "set_ping_link": "Ustaw link do aplikacji Ping", "rate_limit_exceeded": "Przekroczono limit prób", @@ -1177,7 +1177,7 @@ "event_advanced_tab_title": "Zaawansowane", "event_setup_multiple_duration_error": "Konfiguracja wydarzeń: wiele czasów trwania wymaga co najmniej 1 opcji.", "event_setup_multiple_duration_default_error": "Konfiguracja wydarzenia: wybierz prawidłowy domyślny czas trwania.", - "event_setup_booking_limits_error": "Limity rezerwacji muszą być podane w kolejności rosnącej. [dzień,tydzień,miesiąc,rok]", + "event_setup_booking_limits_error": "Limity rezerwacji muszą być podane w kolejności rosnącej. [dzień, tydzień, miesiąc, rok]", "event_setup_duration_limits_error": "Limity czasu trwania muszą być podane w kolejności rosnącej. [dzień, tydzień, miesiąc, rok]", "select_which_cal": "Wybierz kalendarz, do którego chcesz dodać rezerwacje.", "custom_event_name": "Niestandardowa nazwa wydarzenia", From e2a811a967f0078be90666e4c540be5f1934e7bf Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Thu, 25 May 2023 16:18:23 +0000 Subject: [PATCH 638/658] New Crowdin translations by Github Action --- apps/web/public/static/locales/pl/common.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/web/public/static/locales/pl/common.json b/apps/web/public/static/locales/pl/common.json index 016be948b5..f7d5fd2b2a 100644 --- a/apps/web/public/static/locales/pl/common.json +++ b/apps/web/public/static/locales/pl/common.json @@ -1280,7 +1280,7 @@ "download_responses_description": "Pobierz wszystkie odpowiedzi do formularza w formacie CSV.", "download": "Pobierz", "download_recording": "Pobierz nagranie", - "recording_from_your_recent_call": "Nagranie z ostatniego połączenia w witrynie Cal.com jest gotowe do pobrania.", + "recording_from_your_recent_call": "Nagranie z ostatniego połączenia w witrynie Cal.com jest gotowe do pobrania", "create_your_first_form": "Utwórz pierwszy formularz", "create_your_first_form_description": "Za pomocą formularzy przekierowujących możesz zadawać pytania profilujące i przekierowywać użytkowników do odpowiednich osób lub typów wydarzeń.", "create_your_first_webhook": "Utwórz pierwszy Webhook", @@ -1326,7 +1326,7 @@ "exchange_version_2013_SP1": "2013 SP1", "exchange_version_2015": "2015", "exchange_version_2016": "2016", - "routing_forms_description": "Możesz tutaj zobaczyć wszystkie utworzone przez siebie formularze i przekierowania.", + "routing_forms_description": "Utwórz formularze kierujące uczestników do właściwych miejsc docelowych", "routing_forms_send_email_owner": "Wyślij wiadomość e-mail do właściciela", "routing_forms_send_email_owner_description": "Wysyła wiadomość e-mail do właściciela, gdy formularz zostanie przesłany.", "add_new_form": "Dodaj nowy formularz", @@ -1484,7 +1484,7 @@ "duration_limit_reached": "Osiągnięto limit czasu trwania tego typu wydarzenia", "admin_has_disabled": "Administrator wyłączył aplikację {{appName}}", "disabled_app_affects_event_type": "Administrator wyłączył aplikację {{appName}}, która ma wpływ na Twój typ wydarzenia ({{eventType}})", - "event_replaced_notice": "Administrator zastąpił jeden z Twoich typów wydarzeń.", + "event_replaced_notice": "Administrator zastąpił jeden z Twoich typów wydarzeń", "email_subject_slug_replacement": "Administrator zespołu zastąpił Twoje wydarzenie /{{slug}}", "email_body_slug_replacement_notice": "Administrator zespołu {{teamName}} zastąpił Twój typ wydarzenia /{{slug}} kontrolowanym przez siebie typem zarządzanego wydarzenia.", "email_body_slug_replacement_info": "Twój link nadal będzie działał, ale niektóre z jego ustawień mogły ulec zmianie. Możesz zobaczyć szczegóły w typach wydarzeń.", From f3fd74dd6bbd97bae9bc7b9f6ec46b8e4d71b2f3 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Thu, 25 May 2023 16:22:26 +0000 Subject: [PATCH 639/658] New Crowdin translations by Github Action --- apps/web/public/static/locales/pl/common.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/web/public/static/locales/pl/common.json b/apps/web/public/static/locales/pl/common.json index f7d5fd2b2a..2423fba9f1 100644 --- a/apps/web/public/static/locales/pl/common.json +++ b/apps/web/public/static/locales/pl/common.json @@ -1488,7 +1488,7 @@ "email_subject_slug_replacement": "Administrator zespołu zastąpił Twoje wydarzenie /{{slug}}", "email_body_slug_replacement_notice": "Administrator zespołu {{teamName}} zastąpił Twój typ wydarzenia /{{slug}} kontrolowanym przez siebie typem zarządzanego wydarzenia.", "email_body_slug_replacement_info": "Twój link nadal będzie działał, ale niektóre z jego ustawień mogły ulec zmianie. Możesz zobaczyć szczegóły w typach wydarzeń.", - "email_body_slug_replacement_suggestion": "Jeśli masz jakiekolwiek pytania dotyczące typu wydarzenia, skontaktuj się z administratorem.

Miłego planowania
Zespół Cal.com", + "email_body_slug_replacement_suggestion": "Jeśli masz jakiekolwiek pytania dotyczące typu wydarzenia, skontaktuj się z administratorem.

Miłego planowania,
Zespół Cal.com", "disable_payment_app": "Administrator wyłączył aplikację {{appName}}, która ma wpływ na Twój typ wydarzenia ({{title}}). Uczestnicy nadal mogą rezerwować wydarzenie tego typu, ale nie zostaną poproszeni o płatność. Możesz ukryć ten typ wydarzenia, aby temu zapobiec, póki administrator nie włączy ponownie Twojej metody płatności.", "payment_disabled_still_able_to_book": "Uczestnicy nadal mogą rezerwować wydarzenie tego typu, ale nie zostaną poproszeni o płatność. Możesz ukryć ten typ wydarzenia, aby temu zapobiec, póki administrator nie włączy ponownie Twojej metody płatności.", "app_disabled_with_event_type": "Administrator wyłączył aplikację {{appName}}, która ma wpływ na Twój typ wydarzenia ({{title}}).", @@ -1661,7 +1661,7 @@ "not_enough_seats": "Za mało miejsc", "form_builder_field_already_exists": "Pole o tej nazwie już istnieje", "form_builder_field_add_subtitle": "Dostosuj pytania zadawane na stronie rezerwacji", - "show_on_booking_page": "Wyświetl na stronie rezerwacji", + "show_on_booking_page": "Pokaż na stronie rezerwacji", "get_started_zapier_templates": "Zacznij korzystać z szablonów Zapier", "team_is_unpublished": "Zespół {{team}} nie został opublikowany", "team_is_unpublished_description": "Link tego zespołu jest obecnie niedostępny. Skontaktuj się z właścicielem zespołu lub poproś o jego opublikowanie.", @@ -1687,7 +1687,7 @@ "add_a_new_route": "Dodaj nowe przekierowanie", "make_informed_decisions": "Podejmuj świadome decyzje dzięki funkcji Insights", "make_informed_decisions_description": "Panel Insights zawiera informacje o całej aktywności zespołu i trendach umożliwiających lepsze planowanie i podejmowanie decyzji w zespole.", - "view_bookings_across": "Zobacz rezerwacje wszystkich członków", + "view_bookings_across": "Wyświetl rezerwacje wszystkich członków", "view_bookings_across_description": "Zobacz, kto ma najwięcej rezerwacji i upewnij się, że Twój zespół jest równomiernie obciążony pracą.", "identify_booking_trends": "Identyfikuj trendy w rezerwacjach", "identify_booking_trends_description": "Zobacz, które dni tygodnia i pory dnia są popularne wśród rezerwujących.", From 08604a9008e485c86d4e2324af57d41119b4e4c2 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Thu, 25 May 2023 16:27:51 +0000 Subject: [PATCH 640/658] New Crowdin translations by Github Action --- apps/web/public/static/locales/pl/common.json | 26 +++++++++---------- apps/web/public/static/locales/pt/common.json | 4 +-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/web/public/static/locales/pl/common.json b/apps/web/public/static/locales/pl/common.json index 2423fba9f1..1dccb90117 100644 --- a/apps/web/public/static/locales/pl/common.json +++ b/apps/web/public/static/locales/pl/common.json @@ -1688,11 +1688,11 @@ "make_informed_decisions": "Podejmuj świadome decyzje dzięki funkcji Insights", "make_informed_decisions_description": "Panel Insights zawiera informacje o całej aktywności zespołu i trendach umożliwiających lepsze planowanie i podejmowanie decyzji w zespole.", "view_bookings_across": "Wyświetl rezerwacje wszystkich członków", - "view_bookings_across_description": "Zobacz, kto ma najwięcej rezerwacji i upewnij się, że Twój zespół jest równomiernie obciążony pracą.", + "view_bookings_across_description": "Zobacz, kto ma najwięcej rezerwacji i upewnij się, że Twój zespół jest równomiernie obciążony", "identify_booking_trends": "Identyfikuj trendy w rezerwacjach", - "identify_booking_trends_description": "Zobacz, które dni tygodnia i pory dnia są popularne wśród rezerwujących.", + "identify_booking_trends_description": "Zobacz, które dni tygodnia i pory dnia są popularne wśród rezerwujących", "spot_popular_event_types": "Przekonaj się, które typy wydarzeń są popularne", - "spot_popular_event_types_description": "Zobacz, które typy wydarzeń są najczęściej klikane i rezerwowane.", + "spot_popular_event_types_description": "Zobacz, które typy wydarzeń są najczęściej klikane i rezerwowane", "no_responses_yet": "Nie ma jeszcze odpowiedzi", "this_will_be_the_placeholder": "To będzie symbol zastępczy", "this_meeting_has_not_started_yet": "To spotkanie jeszcze się nie rozpoczęło", @@ -1707,22 +1707,22 @@ "timezone_info": "Strefa czasowa osoby rezerwowanej", "event_end_time_variable": "Czas zakończenia wydarzenia", "event_end_time_info": "Czas zakończenia wydarzenia", - "cancel_url_variable": "Adres URL do anulowania", - "cancel_url_info": "Adres URL do anulowania rezerwacji", - "reschedule_url_variable": "Adres URL do zmiany terminu", - "reschedule_url_info": "Adres URL do zmiany terminu rezerwacji", + "cancel_url_variable": "Adres URL umożliwiający anulowanie", + "cancel_url_info": "Adres URL umożliwiający anulowanie rezerwacji", + "reschedule_url_variable": "Adres URL umożliwiający zmianę terminu", + "reschedule_url_info": "Adres URL umożliwiający zmianę terminu rezerwacji", "invalid_event_name_variables": "W Twojej nazwie wydarzenia występuje nieprawidłowa zmienna.", "select_all": "Zaznacz wszystko", "default_conferencing_bulk_title": "Zbiorcza aktualizacja istniejących typów wydarzeń", - "members_default_schedule": "Domyślny harmonogram użytkownika", - "set_by_admin": "Ustalone przez administratora zespołu", + "members_default_schedule": "Domyślny harmonogram członka", + "set_by_admin": "Ustawia administrator zespołu", "members_default_location": "Domyślna lokalizacja członka", "members_default_schedule_description": "Będziemy używać domyślnego harmonogramu dostępności każdego członka. Każdy z nich będzie mógł go edytować lub zmienić.", - "requires_at_least_one_schedule": "Musisz mieć co najmniej jeden harmonogram.", + "requires_at_least_one_schedule": "Musisz mieć co najmniej jeden harmonogram", "default_conferencing_bulk_description": "Aktualizuj lokalizacje wybranych typów wydarzeń", - "locked_for_members": "Zablokowane dla członków", - "locked_apps_description": "Członkowie będą mogli zobaczyć aktywne aplikacje, ale nie będą mogli zmieniać ich ustawień.", - "locked_webhooks_description": "Członkowie będą mogli zobaczyć aktywne webhooki, ale nie będą mogli zmieniać ich ustawień.", + "locked_for_members": "Zablokowany dla członków", + "locked_apps_description": "Członkowie będą mogli sprawdzić aktywne aplikacje, ale nie będą mogli edytować ich ustawień", + "locked_webhooks_description": "Członkowie będą mogli sprawdzić aktywne webhooki, ale nie będą mogli edytować ich ustawień", "locked_workflows_description": "Członkowie będą mogli zobaczyć aktywne przepływy pracy, ale nie będą mogli zmieniać ich ustawień.", "app_not_connected": "Nie połączono konta aplikacji {{appName}}.", "connect_now": "Połącz teraz", diff --git a/apps/web/public/static/locales/pt/common.json b/apps/web/public/static/locales/pt/common.json index 65c83e4aa3..de0fcf67ac 100644 --- a/apps/web/public/static/locales/pt/common.json +++ b/apps/web/public/static/locales/pt/common.json @@ -71,7 +71,7 @@ "event_still_awaiting_approval": "Um evento ainda aguarda a sua aprovação", "booking_submitted_subject": "Reserva submetida: {{title}} em {{date}}", "download_recording_subject": "Transferir gravação: {{title}} em {{date}}", - "download_your_recording": "Transferir a sua gravação", + "download_your_recording": "Transfira a sua gravação", "your_meeting_has_been_booked": "A sua reunião foi reservada", "event_type_has_been_rescheduled_on_time_date": "Seu {{title}} foi remarcado para {{date}}.", "event_has_been_rescheduled": "O seu evento foi reagendado.", @@ -593,7 +593,7 @@ "username_placeholder": "nome-de-utilizador", "managed_event_description": "Criar e distribuir tipos de eventos em conjunto para os membros da equipa", "managed": "Gerido", - "managed_event_url_clarification": "\"username\" será substituído pelo nome de utilizador dos membros atribuídos", + "managed_event_url_clarification": "\"nome-de-utilizador\" será substituído pelo nome de utilizador dos membros atribuídos", "assign_to": "Atribuir a", "add_members": "Adicionar membros...", "count_members_one": "{{count}} membro", From 417050596a73b7b274bd1706f445276fbfdd380d Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Thu, 25 May 2023 16:36:54 +0000 Subject: [PATCH 641/658] New Crowdin translations by Github Action --- apps/web/public/static/locales/pl/common.json | 20 +++++++++---------- apps/web/public/static/locales/pt/common.json | 10 +++++----- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/apps/web/public/static/locales/pl/common.json b/apps/web/public/static/locales/pl/common.json index 1dccb90117..201aa60600 100644 --- a/apps/web/public/static/locales/pl/common.json +++ b/apps/web/public/static/locales/pl/common.json @@ -1723,37 +1723,37 @@ "locked_for_members": "Zablokowany dla członków", "locked_apps_description": "Członkowie będą mogli sprawdzić aktywne aplikacje, ale nie będą mogli edytować ich ustawień", "locked_webhooks_description": "Członkowie będą mogli sprawdzić aktywne webhooki, ale nie będą mogli edytować ich ustawień", - "locked_workflows_description": "Członkowie będą mogli zobaczyć aktywne przepływy pracy, ale nie będą mogli zmieniać ich ustawień.", - "app_not_connected": "Nie połączono konta aplikacji {{appName}}.", - "connect_now": "Połącz teraz", + "locked_workflows_description": "Członkowie będą mogli sprawdzić aktywne przepływy pracy, ale nie będą mogli edytować ich ustawień", + "app_not_connected": "Nie podłączono konta {{appName}}.", + "connect_now": "Podłącz teraz", "managed_event_dialog_confirm_button_one": "Zastąp i poinformuj {{count}} członka", - "managed_event_dialog_confirm_button_other": "Zastąp i poinformuj {{count}} członków", + "managed_event_dialog_confirm_button_other": "Zastąp i powiadom {{count}} członków", "managed_event_dialog_title_one": "Adres URL /{{slug}} już istnieje dla {{count}} członka. Czy chcesz go zastąpić?", "managed_event_dialog_title_other": "Adres URL /{{slug}} już istnieje dla {{count}} członków. Czy chcesz go zastąpić?", "managed_event_dialog_information_one": "{{names}} używa już adresu URL /{{slug}}.", "managed_event_dialog_information_other": "{{names}} używają już adresu URL /{{slug}}.", - "managed_event_dialog_clarification": "Jeśli zdecydujesz się go zastąpić, powiadomimy te osoby. Wróć i usuń je, jeśli nie chcesz nadpisywać adresu.", - "review_event_type": "Zobacz szczegóły typu wydarzenia", + "managed_event_dialog_clarification": "Jeśli zdecydujesz się go zastąpić, powiadomimy te osoby. Wróć i usuń je, jeśli nie chcesz zastępować adresu.", + "review_event_type": "Sprawdź typ wydarzenia", "looking_for_more_analytics": "Szukasz dokładniejszych danych analitycznych?", - "looking_for_more_insights": "Potrzebujesz dokładniejszych Statystyk?", + "looking_for_more_insights": "Szukasz dokładniejszych danych Insights?", "add_filter": "Dodaj filtr", "select_user": "Wybierz użytkownika", "select_event_type": "Wybierz typ wydarzenia", "select_date_range": "Wybierz zakres dat", "popular_events": "Popularne wydarzenia", - "no_event_types_found": "Nie znaleziono typów wydarzeń", + "no_event_types_found": "Nie znaleziono żadnych typów wydarzeń", "average_event_duration": "Średni czas trwania wydarzenia", "most_booked_members": "Najczęściej rezerwowani członkowie", "least_booked_members": "Najrzadziej rezerwowani członkowie", "events_created": "Utworzone wydarzenia", - "events_completed": "Zakończone wydarzenia", + "events_completed": "Ukończone wydarzenia", "events_cancelled": "Anulowane wydarzenia", "events_rescheduled": "Przełożone wydarzenia", "from_last_period": "od ostatniego okresu", "from_to_date_period": "Od: {{startDate}} Do: {{endDate}}", "analytics_for_organisation": "Insights", "subtitle_analytics": "Dowiedz się więcej o aktywności Twojego zespołu", - "redirect_url_warning": "Dodanie przekierowania sprawi, że strona powodzenia zostanie wyłączona. Upewnij się, że na Twojej niestandardowej stronie powodzenia umieścisz informację o potwierdzeniu rezerwacji.", + "redirect_url_warning": "Dodanie przekierowania wyłączy stronę powodzenia. Upewnij się, że na Twojej niestandardowej stronie powodzenia znajduje się wzmianka o potwierdzeniu rezerwacji.", "event_trends": "Trendy wydarzeń", "clear_filters": "Wyczyść filtry", "hold": "Zablokowano", diff --git a/apps/web/public/static/locales/pt/common.json b/apps/web/public/static/locales/pt/common.json index de0fcf67ac..b3eb0917ff 100644 --- a/apps/web/public/static/locales/pt/common.json +++ b/apps/web/public/static/locales/pt/common.json @@ -1551,7 +1551,7 @@ "create_your_first_team_webhook_description": "Crie o seu primeiro webhook para este tipo de evento de equipa", "create_webhook_team_event_type": "Crie um webhook para este tipo de evento de equipa", "disable_success_page": "Desativar a Página de sucesso (só funciona se tiver um URL de redirecionamento)", - "invalid_admin_password": "Você é um administrador, mas ainda não tem uma palavra-passe com pelo menos 15 caracteres", + "invalid_admin_password": "Você é administrador, mas ainda não tem uma palavra-passe com pelo menos 15 caracteres", "change_password_admin": "Altere a palavra-passe para ter acesso de administrador", "username_already_taken": "O nome de utilizador já está a ser utilizado", "assignment": "Atribuição", @@ -1743,8 +1743,8 @@ "popular_events": "Eventos populares", "no_event_types_found": "Não foram encontrados tipos de eventos", "average_event_duration": "Duração média do evento", - "most_booked_members": "Membros mais reservados", - "least_booked_members": "Membros menos reservados", + "most_booked_members": "Membros com mais reservas", + "least_booked_members": "Membros com menos reservas", "events_created": "Eventos criados", "events_completed": "Eventos concluídos", "events_cancelled": "Eventos cancelados", @@ -1756,10 +1756,10 @@ "redirect_url_warning": "Ao adicionar um redirecionamento irá desativar a página de sucesso. Certifique-se que indica que \"A reserva foi confirmada\" na sua página de sucesso personalizada.", "event_trends": "Tendências de evento", "clear_filters": "Limpar filtros", - "hold": "Cativo", + "hold": "Reter", "on_booking_option": "Receber o pagamento na reserva", "hold_option": "Cobrar taxa de não-comparência", - "card_held": "Cartão cativo", + "card_held": "Cartão retido", "charge_card": "Debitar no cartão", "card_charged": "Cartão debitado", "no_show_fee_amount": "Taxa de não-comparência de {{amount, currency}}", From d939cf20ecc3082201d987bc268bf9cfee943c78 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Thu, 25 May 2023 16:54:06 +0000 Subject: [PATCH 642/658] New Crowdin translations by Github Action --- apps/web/public/static/locales/pl/common.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/web/public/static/locales/pl/common.json b/apps/web/public/static/locales/pl/common.json index 201aa60600..160ded39c7 100644 --- a/apps/web/public/static/locales/pl/common.json +++ b/apps/web/public/static/locales/pl/common.json @@ -1774,10 +1774,10 @@ "collect_no_show_fee": "Pobierz opłatę za niestawienie się", "no_show_fee_charged": "Pobrano opłatę za niestawienie się", "insights": "Insights", - "testing_workflow_info_message": "Podczas testowania tego przepływu pracy pamiętaj, że wiadomości e-mail i SMS mogą zostać zaplanowane najpóźniej godzinę przed terminem ich dostarczenia.", - "insights_no_data_found_for_filter": "Nie znaleziono danych dotyczących wybranego filtra lub wskazanych dat.", - "acknowledge_booking_no_show_fee": "Rozumiem, że jeśli nie wezmę udziału w wydarzeniu, z mojej karty pobrana zostanie opłata w wysokości {{amount, currency}}.", - "card_details": "Dane karty płatniczej", + "testing_workflow_info_message": "Podczas testowania tego przepływu pracy pamiętaj, że wiadomości e-mail i SMS można zaplanować jedynie z co najmniej 1-godzinnym wyprzedzeniem", + "insights_no_data_found_for_filter": "Nie znaleziono danych dotyczących wybranego filtru lub wskazanych dat.", + "acknowledge_booking_no_show_fee": "Rozumiem, że jeśli nie wezmę udziału w wydarzeniu, z mojej karty pobrana zostanie opłata za niestawienie się w wysokości {{amount, currency}}.", + "card_details": "Dane karty", "seats_and_no_show_fee_error": "Obecnie nie można udostępnić miejsc ani naliczyć opłaty za niestawienie się.", "complete_your_booking": "Ukończ rezerwację", "complete_your_booking_subject": "Ukończ rezerwację: {{title}} dnia {{date}}", From 47488f5fff33ff922f62f5c69985ab1dda78df56 Mon Sep 17 00:00:00 2001 From: zomars Date: Thu, 25 May 2023 11:29:10 -0700 Subject: [PATCH 643/658] Moved API files to correct dir --- apps/api/{apps/api => }/.env.example | 0 apps/api/{apps/api => }/.eslintrc.js | 0 apps/api/{apps/api => }/.gitignore | 0 apps/api/{apps/api => }/.gitkeep | 0 apps/api/{apps/api => }/.prettierignore | 0 apps/api/{apps/api => }/README.md | 0 apps/api/{apps/api => }/jest.setup.ts | 0 apps/api/{apps/api => }/lib/constants.ts | 0 apps/api/{apps/api => }/lib/helpers/addRequestid.ts | 0 apps/api/{apps/api => }/lib/helpers/captureErrors.ts | 0 apps/api/{apps/api => }/lib/helpers/customPrisma.ts | 0 apps/api/{apps/api => }/lib/helpers/extendRequest.ts | 0 apps/api/{apps/api => }/lib/helpers/httpMethods.ts | 0 apps/api/{apps/api => }/lib/helpers/safeParseJSON.ts | 0 apps/api/{apps/api => }/lib/helpers/verifyApiKey.ts | 0 apps/api/{apps/api => }/lib/helpers/withMiddleware.ts | 0 apps/api/{apps/api => }/lib/helpers/withPagination.ts | 0 apps/api/{apps/api => }/lib/types.ts | 0 apps/api/{apps/api => }/lib/utils/isAdmin.ts | 0 apps/api/{apps/api => }/lib/utils/stringifyISODate.ts | 0 apps/api/{apps/api => }/lib/validations/api-key.ts | 0 apps/api/{apps/api => }/lib/validations/attendee.ts | 0 apps/api/{apps/api => }/lib/validations/availability.ts | 0 apps/api/{apps/api => }/lib/validations/booking-reference.ts | 0 apps/api/{apps/api => }/lib/validations/booking.ts | 0 apps/api/{apps/api => }/lib/validations/destination-calendar.ts | 0 .../api/{apps/api => }/lib/validations/event-type-custom-input.ts | 0 apps/api/{apps/api => }/lib/validations/event-type.ts | 0 apps/api/{apps/api => }/lib/validations/membership.ts | 0 apps/api/{apps/api => }/lib/validations/payment.ts | 0 apps/api/{apps/api => }/lib/validations/reminder-mail.ts | 0 apps/api/{apps/api => }/lib/validations/schedule.ts | 0 apps/api/{apps/api => }/lib/validations/selected-calendar.ts | 0 apps/api/{apps/api => }/lib/validations/shared/baseApiParams.ts | 0 apps/api/{apps/api => }/lib/validations/shared/jsonSchema.ts | 0 apps/api/{apps/api => }/lib/validations/shared/queryIdString.ts | 0 .../api => }/lib/validations/shared/queryIdTransformParseInt.ts | 0 apps/api/{apps/api => }/lib/validations/shared/queryTeamId.ts | 0 apps/api/{apps/api => }/lib/validations/shared/queryUserId.ts | 0 apps/api/{apps/api => }/lib/validations/shared/timeZone.ts | 0 apps/api/{apps/api => }/lib/validations/team.ts | 0 apps/api/{apps/api => }/lib/validations/user.ts | 0 apps/api/{apps/api => }/lib/validations/webhook.ts | 0 apps/api/{apps/api => }/next-env.d.ts | 0 apps/api/{apps/api => }/next-i18next.config.js | 0 apps/api/{apps/api => }/next.config.js | 0 apps/api/{apps/api => }/next.d.ts | 0 apps/api/{apps/api => }/package.json | 0 .../{apps/api => }/pages/api/api-keys/[id]/_auth-middleware.ts | 0 apps/api/{apps/api => }/pages/api/api-keys/[id]/_delete.ts | 0 apps/api/{apps/api => }/pages/api/api-keys/[id]/_get.ts | 0 apps/api/{apps/api => }/pages/api/api-keys/[id]/_patch.ts | 0 apps/api/{apps/api => }/pages/api/api-keys/[id]/index.ts | 0 apps/api/{apps/api => }/pages/api/api-keys/_get.ts | 0 apps/api/{apps/api => }/pages/api/api-keys/_post.ts | 0 apps/api/{apps/api => }/pages/api/api-keys/index.ts | 0 .../{apps/api => }/pages/api/attendees/[id]/_auth-middleware.ts | 0 apps/api/{apps/api => }/pages/api/attendees/[id]/_delete.ts | 0 apps/api/{apps/api => }/pages/api/attendees/[id]/_get.ts | 0 apps/api/{apps/api => }/pages/api/attendees/[id]/_patch.ts | 0 apps/api/{apps/api => }/pages/api/attendees/[id]/index.ts | 0 apps/api/{apps/api => }/pages/api/attendees/_get.ts | 0 apps/api/{apps/api => }/pages/api/attendees/_post.ts | 0 apps/api/{apps/api => }/pages/api/attendees/index.ts | 0 .../api => }/pages/api/availabilities/[id]/_auth-middleware.ts | 0 apps/api/{apps/api => }/pages/api/availabilities/[id]/_delete.ts | 0 apps/api/{apps/api => }/pages/api/availabilities/[id]/_get.ts | 0 apps/api/{apps/api => }/pages/api/availabilities/[id]/_patch.ts | 0 apps/api/{apps/api => }/pages/api/availabilities/[id]/index.ts | 0 apps/api/{apps/api => }/pages/api/availabilities/_post.ts | 0 apps/api/{apps/api => }/pages/api/availabilities/index.ts | 0 apps/api/{apps/api => }/pages/api/availability/_get.ts | 0 apps/api/{apps/api => }/pages/api/availability/index.ts | 0 .../pages/api/booking-references/[id]/_auth-middleware.ts | 0 .../{apps/api => }/pages/api/booking-references/[id]/_delete.ts | 0 apps/api/{apps/api => }/pages/api/booking-references/[id]/_get.ts | 0 .../{apps/api => }/pages/api/booking-references/[id]/_patch.ts | 0 .../api/{apps/api => }/pages/api/booking-references/[id]/index.ts | 0 apps/api/{apps/api => }/pages/api/booking-references/_get.ts | 0 apps/api/{apps/api => }/pages/api/booking-references/_post.ts | 0 apps/api/{apps/api => }/pages/api/booking-references/index.ts | 0 .../{apps/api => }/pages/api/bookings/[id]/_auth-middleware.ts | 0 apps/api/{apps/api => }/pages/api/bookings/[id]/_delete.ts | 0 apps/api/{apps/api => }/pages/api/bookings/[id]/_get.ts | 0 apps/api/{apps/api => }/pages/api/bookings/[id]/_patch.ts | 0 apps/api/{apps/api => }/pages/api/bookings/[id]/cancel.ts | 0 apps/api/{apps/api => }/pages/api/bookings/[id]/index.ts | 0 apps/api/{apps/api => }/pages/api/bookings/_get.ts | 0 apps/api/{apps/api => }/pages/api/bookings/_post.ts | 0 apps/api/{apps/api => }/pages/api/bookings/index.ts | 0 .../api => }/pages/api/custom-inputs/[id]/_auth-middleware.ts | 0 apps/api/{apps/api => }/pages/api/custom-inputs/[id]/_delete.ts | 0 apps/api/{apps/api => }/pages/api/custom-inputs/[id]/_get.ts | 0 apps/api/{apps/api => }/pages/api/custom-inputs/[id]/_patch.ts | 0 apps/api/{apps/api => }/pages/api/custom-inputs/[id]/index.ts | 0 apps/api/{apps/api => }/pages/api/custom-inputs/_get.ts | 0 apps/api/{apps/api => }/pages/api/custom-inputs/_post.ts | 0 apps/api/{apps/api => }/pages/api/custom-inputs/index.ts | 0 apps/api/{apps/api => }/pages/api/destination-calendars/[id].ts | 0 apps/api/{apps/api => }/pages/api/destination-calendars/index.ts | 0 apps/api/{apps/api => }/pages/api/docs.ts | 0 .../{apps/api => }/pages/api/event-types/[id]/_auth-middleware.ts | 0 apps/api/{apps/api => }/pages/api/event-types/[id]/_delete.ts | 0 apps/api/{apps/api => }/pages/api/event-types/[id]/_get.ts | 0 apps/api/{apps/api => }/pages/api/event-types/[id]/_patch.ts | 0 apps/api/{apps/api => }/pages/api/event-types/[id]/index.ts | 0 apps/api/{apps/api => }/pages/api/event-types/_get.ts | 0 apps/api/{apps/api => }/pages/api/event-types/_post.ts | 0 .../pages/api/event-types/_utils/checkTeamEventEditPermission.ts | 0 .../pages/api/event-types/_utils/ensureOnlyMembersAsHosts.ts | 0 .../api/{apps/api => }/pages/api/event-types/_utils/getCalLink.ts | 0 apps/api/{apps/api => }/pages/api/event-types/index.ts | 0 apps/api/{apps/api => }/pages/api/index.ts | 0 apps/api/{apps/api => }/pages/api/me/_get.ts | 0 apps/api/{apps/api => }/pages/api/me/index.ts | 0 .../{apps/api => }/pages/api/memberships/[id]/_auth-middleware.ts | 0 apps/api/{apps/api => }/pages/api/memberships/[id]/_delete.ts | 0 apps/api/{apps/api => }/pages/api/memberships/[id]/_get.ts | 0 apps/api/{apps/api => }/pages/api/memberships/[id]/_patch.ts | 0 apps/api/{apps/api => }/pages/api/memberships/[id]/index.ts | 0 apps/api/{apps/api => }/pages/api/memberships/_get.ts | 0 apps/api/{apps/api => }/pages/api/memberships/_post.ts | 0 apps/api/{apps/api => }/pages/api/memberships/index.ts | 0 apps/api/{apps/api => }/pages/api/payments/[id].ts | 0 apps/api/{apps/api => }/pages/api/payments/index.ts | 0 .../{apps/api => }/pages/api/schedules/[id]/_auth-middleware.ts | 0 apps/api/{apps/api => }/pages/api/schedules/[id]/_delete.ts | 0 apps/api/{apps/api => }/pages/api/schedules/[id]/_get.ts | 0 apps/api/{apps/api => }/pages/api/schedules/[id]/_patch.ts | 0 apps/api/{apps/api => }/pages/api/schedules/[id]/index.ts | 0 apps/api/{apps/api => }/pages/api/schedules/_get.ts | 0 apps/api/{apps/api => }/pages/api/schedules/_post.ts | 0 apps/api/{apps/api => }/pages/api/schedules/index.ts | 0 .../pages/api/selected-calendars/[id]/_auth-middleware.ts | 0 .../{apps/api => }/pages/api/selected-calendars/[id]/_delete.ts | 0 apps/api/{apps/api => }/pages/api/selected-calendars/[id]/_get.ts | 0 .../{apps/api => }/pages/api/selected-calendars/[id]/_patch.ts | 0 .../api/{apps/api => }/pages/api/selected-calendars/[id]/index.ts | 0 apps/api/{apps/api => }/pages/api/selected-calendars/_get.ts | 0 apps/api/{apps/api => }/pages/api/selected-calendars/_post.ts | 0 apps/api/{apps/api => }/pages/api/selected-calendars/index.ts | 0 .../{apps/api => }/pages/api/teams/[teamId]/_auth-middleware.ts | 0 apps/api/{apps/api => }/pages/api/teams/[teamId]/_delete.ts | 0 apps/api/{apps/api => }/pages/api/teams/[teamId]/_get.ts | 0 apps/api/{apps/api => }/pages/api/teams/[teamId]/_patch.ts | 0 .../{apps/api => }/pages/api/teams/[teamId]/availability/index.ts | 0 .../{apps/api => }/pages/api/teams/[teamId]/event-types/_get.ts | 0 .../{apps/api => }/pages/api/teams/[teamId]/event-types/index.ts | 0 apps/api/{apps/api => }/pages/api/teams/[teamId]/index.ts | 0 apps/api/{apps/api => }/pages/api/teams/[teamId]/publish.ts | 0 apps/api/{apps/api => }/pages/api/teams/_get.ts | 0 apps/api/{apps/api => }/pages/api/teams/_post.ts | 0 apps/api/{apps/api => }/pages/api/teams/index.ts | 0 apps/api/{apps/api => }/pages/api/users/[userId]/_delete.ts | 0 apps/api/{apps/api => }/pages/api/users/[userId]/_get.ts | 0 apps/api/{apps/api => }/pages/api/users/[userId]/_patch.ts | 0 .../{apps/api => }/pages/api/users/[userId]/availability/index.ts | 0 apps/api/{apps/api => }/pages/api/users/[userId]/index.ts | 0 apps/api/{apps/api => }/pages/api/users/_get.ts | 0 apps/api/{apps/api => }/pages/api/users/_post.ts | 0 apps/api/{apps/api => }/pages/api/users/index.ts | 0 .../{apps/api => }/pages/api/webhooks/[id]/_auth-middleware.ts | 0 apps/api/{apps/api => }/pages/api/webhooks/[id]/_delete.ts | 0 apps/api/{apps/api => }/pages/api/webhooks/[id]/_get.ts | 0 apps/api/{apps/api => }/pages/api/webhooks/[id]/_patch.ts | 0 apps/api/{apps/api => }/pages/api/webhooks/[id]/index.ts | 0 apps/api/{apps/api => }/pages/api/webhooks/_get.ts | 0 apps/api/{apps/api => }/pages/api/webhooks/_post.ts | 0 apps/api/{apps/api => }/pages/api/webhooks/index.ts | 0 apps/api/{apps/api => }/scripts/vercel-deploy.sh | 0 apps/api/{apps/api => }/test/README.md | 0 apps/api/{apps/api => }/test/docker-compose.yml | 0 apps/api/{apps/api => }/test/jest-resolver.js | 0 apps/api/{apps/api => }/test/jest-setup.js | 0 apps/api/{apps/api => }/test/lib/bookings/_post.test.ts | 0 apps/api/{apps/api => }/tsconfig.json | 0 176 files changed, 0 insertions(+), 0 deletions(-) rename apps/api/{apps/api => }/.env.example (100%) rename apps/api/{apps/api => }/.eslintrc.js (100%) rename apps/api/{apps/api => }/.gitignore (100%) rename apps/api/{apps/api => }/.gitkeep (100%) rename apps/api/{apps/api => }/.prettierignore (100%) rename apps/api/{apps/api => }/README.md (100%) rename apps/api/{apps/api => }/jest.setup.ts (100%) rename apps/api/{apps/api => }/lib/constants.ts (100%) rename apps/api/{apps/api => }/lib/helpers/addRequestid.ts (100%) rename apps/api/{apps/api => }/lib/helpers/captureErrors.ts (100%) rename apps/api/{apps/api => }/lib/helpers/customPrisma.ts (100%) rename apps/api/{apps/api => }/lib/helpers/extendRequest.ts (100%) rename apps/api/{apps/api => }/lib/helpers/httpMethods.ts (100%) rename apps/api/{apps/api => }/lib/helpers/safeParseJSON.ts (100%) rename apps/api/{apps/api => }/lib/helpers/verifyApiKey.ts (100%) rename apps/api/{apps/api => }/lib/helpers/withMiddleware.ts (100%) rename apps/api/{apps/api => }/lib/helpers/withPagination.ts (100%) rename apps/api/{apps/api => }/lib/types.ts (100%) rename apps/api/{apps/api => }/lib/utils/isAdmin.ts (100%) rename apps/api/{apps/api => }/lib/utils/stringifyISODate.ts (100%) rename apps/api/{apps/api => }/lib/validations/api-key.ts (100%) rename apps/api/{apps/api => }/lib/validations/attendee.ts (100%) rename apps/api/{apps/api => }/lib/validations/availability.ts (100%) rename apps/api/{apps/api => }/lib/validations/booking-reference.ts (100%) rename apps/api/{apps/api => }/lib/validations/booking.ts (100%) rename apps/api/{apps/api => }/lib/validations/destination-calendar.ts (100%) rename apps/api/{apps/api => }/lib/validations/event-type-custom-input.ts (100%) rename apps/api/{apps/api => }/lib/validations/event-type.ts (100%) rename apps/api/{apps/api => }/lib/validations/membership.ts (100%) rename apps/api/{apps/api => }/lib/validations/payment.ts (100%) rename apps/api/{apps/api => }/lib/validations/reminder-mail.ts (100%) rename apps/api/{apps/api => }/lib/validations/schedule.ts (100%) rename apps/api/{apps/api => }/lib/validations/selected-calendar.ts (100%) rename apps/api/{apps/api => }/lib/validations/shared/baseApiParams.ts (100%) rename apps/api/{apps/api => }/lib/validations/shared/jsonSchema.ts (100%) rename apps/api/{apps/api => }/lib/validations/shared/queryIdString.ts (100%) rename apps/api/{apps/api => }/lib/validations/shared/queryIdTransformParseInt.ts (100%) rename apps/api/{apps/api => }/lib/validations/shared/queryTeamId.ts (100%) rename apps/api/{apps/api => }/lib/validations/shared/queryUserId.ts (100%) rename apps/api/{apps/api => }/lib/validations/shared/timeZone.ts (100%) rename apps/api/{apps/api => }/lib/validations/team.ts (100%) rename apps/api/{apps/api => }/lib/validations/user.ts (100%) rename apps/api/{apps/api => }/lib/validations/webhook.ts (100%) rename apps/api/{apps/api => }/next-env.d.ts (100%) rename apps/api/{apps/api => }/next-i18next.config.js (100%) rename apps/api/{apps/api => }/next.config.js (100%) rename apps/api/{apps/api => }/next.d.ts (100%) rename apps/api/{apps/api => }/package.json (100%) rename apps/api/{apps/api => }/pages/api/api-keys/[id]/_auth-middleware.ts (100%) rename apps/api/{apps/api => }/pages/api/api-keys/[id]/_delete.ts (100%) rename apps/api/{apps/api => }/pages/api/api-keys/[id]/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/api-keys/[id]/_patch.ts (100%) rename apps/api/{apps/api => }/pages/api/api-keys/[id]/index.ts (100%) rename apps/api/{apps/api => }/pages/api/api-keys/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/api-keys/_post.ts (100%) rename apps/api/{apps/api => }/pages/api/api-keys/index.ts (100%) rename apps/api/{apps/api => }/pages/api/attendees/[id]/_auth-middleware.ts (100%) rename apps/api/{apps/api => }/pages/api/attendees/[id]/_delete.ts (100%) rename apps/api/{apps/api => }/pages/api/attendees/[id]/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/attendees/[id]/_patch.ts (100%) rename apps/api/{apps/api => }/pages/api/attendees/[id]/index.ts (100%) rename apps/api/{apps/api => }/pages/api/attendees/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/attendees/_post.ts (100%) rename apps/api/{apps/api => }/pages/api/attendees/index.ts (100%) rename apps/api/{apps/api => }/pages/api/availabilities/[id]/_auth-middleware.ts (100%) rename apps/api/{apps/api => }/pages/api/availabilities/[id]/_delete.ts (100%) rename apps/api/{apps/api => }/pages/api/availabilities/[id]/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/availabilities/[id]/_patch.ts (100%) rename apps/api/{apps/api => }/pages/api/availabilities/[id]/index.ts (100%) rename apps/api/{apps/api => }/pages/api/availabilities/_post.ts (100%) rename apps/api/{apps/api => }/pages/api/availabilities/index.ts (100%) rename apps/api/{apps/api => }/pages/api/availability/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/availability/index.ts (100%) rename apps/api/{apps/api => }/pages/api/booking-references/[id]/_auth-middleware.ts (100%) rename apps/api/{apps/api => }/pages/api/booking-references/[id]/_delete.ts (100%) rename apps/api/{apps/api => }/pages/api/booking-references/[id]/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/booking-references/[id]/_patch.ts (100%) rename apps/api/{apps/api => }/pages/api/booking-references/[id]/index.ts (100%) rename apps/api/{apps/api => }/pages/api/booking-references/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/booking-references/_post.ts (100%) rename apps/api/{apps/api => }/pages/api/booking-references/index.ts (100%) rename apps/api/{apps/api => }/pages/api/bookings/[id]/_auth-middleware.ts (100%) rename apps/api/{apps/api => }/pages/api/bookings/[id]/_delete.ts (100%) rename apps/api/{apps/api => }/pages/api/bookings/[id]/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/bookings/[id]/_patch.ts (100%) rename apps/api/{apps/api => }/pages/api/bookings/[id]/cancel.ts (100%) rename apps/api/{apps/api => }/pages/api/bookings/[id]/index.ts (100%) rename apps/api/{apps/api => }/pages/api/bookings/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/bookings/_post.ts (100%) rename apps/api/{apps/api => }/pages/api/bookings/index.ts (100%) rename apps/api/{apps/api => }/pages/api/custom-inputs/[id]/_auth-middleware.ts (100%) rename apps/api/{apps/api => }/pages/api/custom-inputs/[id]/_delete.ts (100%) rename apps/api/{apps/api => }/pages/api/custom-inputs/[id]/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/custom-inputs/[id]/_patch.ts (100%) rename apps/api/{apps/api => }/pages/api/custom-inputs/[id]/index.ts (100%) rename apps/api/{apps/api => }/pages/api/custom-inputs/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/custom-inputs/_post.ts (100%) rename apps/api/{apps/api => }/pages/api/custom-inputs/index.ts (100%) rename apps/api/{apps/api => }/pages/api/destination-calendars/[id].ts (100%) rename apps/api/{apps/api => }/pages/api/destination-calendars/index.ts (100%) rename apps/api/{apps/api => }/pages/api/docs.ts (100%) rename apps/api/{apps/api => }/pages/api/event-types/[id]/_auth-middleware.ts (100%) rename apps/api/{apps/api => }/pages/api/event-types/[id]/_delete.ts (100%) rename apps/api/{apps/api => }/pages/api/event-types/[id]/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/event-types/[id]/_patch.ts (100%) rename apps/api/{apps/api => }/pages/api/event-types/[id]/index.ts (100%) rename apps/api/{apps/api => }/pages/api/event-types/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/event-types/_post.ts (100%) rename apps/api/{apps/api => }/pages/api/event-types/_utils/checkTeamEventEditPermission.ts (100%) rename apps/api/{apps/api => }/pages/api/event-types/_utils/ensureOnlyMembersAsHosts.ts (100%) rename apps/api/{apps/api => }/pages/api/event-types/_utils/getCalLink.ts (100%) rename apps/api/{apps/api => }/pages/api/event-types/index.ts (100%) rename apps/api/{apps/api => }/pages/api/index.ts (100%) rename apps/api/{apps/api => }/pages/api/me/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/me/index.ts (100%) rename apps/api/{apps/api => }/pages/api/memberships/[id]/_auth-middleware.ts (100%) rename apps/api/{apps/api => }/pages/api/memberships/[id]/_delete.ts (100%) rename apps/api/{apps/api => }/pages/api/memberships/[id]/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/memberships/[id]/_patch.ts (100%) rename apps/api/{apps/api => }/pages/api/memberships/[id]/index.ts (100%) rename apps/api/{apps/api => }/pages/api/memberships/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/memberships/_post.ts (100%) rename apps/api/{apps/api => }/pages/api/memberships/index.ts (100%) rename apps/api/{apps/api => }/pages/api/payments/[id].ts (100%) rename apps/api/{apps/api => }/pages/api/payments/index.ts (100%) rename apps/api/{apps/api => }/pages/api/schedules/[id]/_auth-middleware.ts (100%) rename apps/api/{apps/api => }/pages/api/schedules/[id]/_delete.ts (100%) rename apps/api/{apps/api => }/pages/api/schedules/[id]/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/schedules/[id]/_patch.ts (100%) rename apps/api/{apps/api => }/pages/api/schedules/[id]/index.ts (100%) rename apps/api/{apps/api => }/pages/api/schedules/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/schedules/_post.ts (100%) rename apps/api/{apps/api => }/pages/api/schedules/index.ts (100%) rename apps/api/{apps/api => }/pages/api/selected-calendars/[id]/_auth-middleware.ts (100%) rename apps/api/{apps/api => }/pages/api/selected-calendars/[id]/_delete.ts (100%) rename apps/api/{apps/api => }/pages/api/selected-calendars/[id]/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/selected-calendars/[id]/_patch.ts (100%) rename apps/api/{apps/api => }/pages/api/selected-calendars/[id]/index.ts (100%) rename apps/api/{apps/api => }/pages/api/selected-calendars/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/selected-calendars/_post.ts (100%) rename apps/api/{apps/api => }/pages/api/selected-calendars/index.ts (100%) rename apps/api/{apps/api => }/pages/api/teams/[teamId]/_auth-middleware.ts (100%) rename apps/api/{apps/api => }/pages/api/teams/[teamId]/_delete.ts (100%) rename apps/api/{apps/api => }/pages/api/teams/[teamId]/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/teams/[teamId]/_patch.ts (100%) rename apps/api/{apps/api => }/pages/api/teams/[teamId]/availability/index.ts (100%) rename apps/api/{apps/api => }/pages/api/teams/[teamId]/event-types/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/teams/[teamId]/event-types/index.ts (100%) rename apps/api/{apps/api => }/pages/api/teams/[teamId]/index.ts (100%) rename apps/api/{apps/api => }/pages/api/teams/[teamId]/publish.ts (100%) rename apps/api/{apps/api => }/pages/api/teams/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/teams/_post.ts (100%) rename apps/api/{apps/api => }/pages/api/teams/index.ts (100%) rename apps/api/{apps/api => }/pages/api/users/[userId]/_delete.ts (100%) rename apps/api/{apps/api => }/pages/api/users/[userId]/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/users/[userId]/_patch.ts (100%) rename apps/api/{apps/api => }/pages/api/users/[userId]/availability/index.ts (100%) rename apps/api/{apps/api => }/pages/api/users/[userId]/index.ts (100%) rename apps/api/{apps/api => }/pages/api/users/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/users/_post.ts (100%) rename apps/api/{apps/api => }/pages/api/users/index.ts (100%) rename apps/api/{apps/api => }/pages/api/webhooks/[id]/_auth-middleware.ts (100%) rename apps/api/{apps/api => }/pages/api/webhooks/[id]/_delete.ts (100%) rename apps/api/{apps/api => }/pages/api/webhooks/[id]/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/webhooks/[id]/_patch.ts (100%) rename apps/api/{apps/api => }/pages/api/webhooks/[id]/index.ts (100%) rename apps/api/{apps/api => }/pages/api/webhooks/_get.ts (100%) rename apps/api/{apps/api => }/pages/api/webhooks/_post.ts (100%) rename apps/api/{apps/api => }/pages/api/webhooks/index.ts (100%) rename apps/api/{apps/api => }/scripts/vercel-deploy.sh (100%) rename apps/api/{apps/api => }/test/README.md (100%) rename apps/api/{apps/api => }/test/docker-compose.yml (100%) rename apps/api/{apps/api => }/test/jest-resolver.js (100%) rename apps/api/{apps/api => }/test/jest-setup.js (100%) rename apps/api/{apps/api => }/test/lib/bookings/_post.test.ts (100%) rename apps/api/{apps/api => }/tsconfig.json (100%) diff --git a/apps/api/apps/api/.env.example b/apps/api/.env.example similarity index 100% rename from apps/api/apps/api/.env.example rename to apps/api/.env.example diff --git a/apps/api/apps/api/.eslintrc.js b/apps/api/.eslintrc.js similarity index 100% rename from apps/api/apps/api/.eslintrc.js rename to apps/api/.eslintrc.js diff --git a/apps/api/apps/api/.gitignore b/apps/api/.gitignore similarity index 100% rename from apps/api/apps/api/.gitignore rename to apps/api/.gitignore diff --git a/apps/api/apps/api/.gitkeep b/apps/api/.gitkeep similarity index 100% rename from apps/api/apps/api/.gitkeep rename to apps/api/.gitkeep diff --git a/apps/api/apps/api/.prettierignore b/apps/api/.prettierignore similarity index 100% rename from apps/api/apps/api/.prettierignore rename to apps/api/.prettierignore diff --git a/apps/api/apps/api/README.md b/apps/api/README.md similarity index 100% rename from apps/api/apps/api/README.md rename to apps/api/README.md diff --git a/apps/api/apps/api/jest.setup.ts b/apps/api/jest.setup.ts similarity index 100% rename from apps/api/apps/api/jest.setup.ts rename to apps/api/jest.setup.ts diff --git a/apps/api/apps/api/lib/constants.ts b/apps/api/lib/constants.ts similarity index 100% rename from apps/api/apps/api/lib/constants.ts rename to apps/api/lib/constants.ts diff --git a/apps/api/apps/api/lib/helpers/addRequestid.ts b/apps/api/lib/helpers/addRequestid.ts similarity index 100% rename from apps/api/apps/api/lib/helpers/addRequestid.ts rename to apps/api/lib/helpers/addRequestid.ts diff --git a/apps/api/apps/api/lib/helpers/captureErrors.ts b/apps/api/lib/helpers/captureErrors.ts similarity index 100% rename from apps/api/apps/api/lib/helpers/captureErrors.ts rename to apps/api/lib/helpers/captureErrors.ts diff --git a/apps/api/apps/api/lib/helpers/customPrisma.ts b/apps/api/lib/helpers/customPrisma.ts similarity index 100% rename from apps/api/apps/api/lib/helpers/customPrisma.ts rename to apps/api/lib/helpers/customPrisma.ts diff --git a/apps/api/apps/api/lib/helpers/extendRequest.ts b/apps/api/lib/helpers/extendRequest.ts similarity index 100% rename from apps/api/apps/api/lib/helpers/extendRequest.ts rename to apps/api/lib/helpers/extendRequest.ts diff --git a/apps/api/apps/api/lib/helpers/httpMethods.ts b/apps/api/lib/helpers/httpMethods.ts similarity index 100% rename from apps/api/apps/api/lib/helpers/httpMethods.ts rename to apps/api/lib/helpers/httpMethods.ts diff --git a/apps/api/apps/api/lib/helpers/safeParseJSON.ts b/apps/api/lib/helpers/safeParseJSON.ts similarity index 100% rename from apps/api/apps/api/lib/helpers/safeParseJSON.ts rename to apps/api/lib/helpers/safeParseJSON.ts diff --git a/apps/api/apps/api/lib/helpers/verifyApiKey.ts b/apps/api/lib/helpers/verifyApiKey.ts similarity index 100% rename from apps/api/apps/api/lib/helpers/verifyApiKey.ts rename to apps/api/lib/helpers/verifyApiKey.ts diff --git a/apps/api/apps/api/lib/helpers/withMiddleware.ts b/apps/api/lib/helpers/withMiddleware.ts similarity index 100% rename from apps/api/apps/api/lib/helpers/withMiddleware.ts rename to apps/api/lib/helpers/withMiddleware.ts diff --git a/apps/api/apps/api/lib/helpers/withPagination.ts b/apps/api/lib/helpers/withPagination.ts similarity index 100% rename from apps/api/apps/api/lib/helpers/withPagination.ts rename to apps/api/lib/helpers/withPagination.ts diff --git a/apps/api/apps/api/lib/types.ts b/apps/api/lib/types.ts similarity index 100% rename from apps/api/apps/api/lib/types.ts rename to apps/api/lib/types.ts diff --git a/apps/api/apps/api/lib/utils/isAdmin.ts b/apps/api/lib/utils/isAdmin.ts similarity index 100% rename from apps/api/apps/api/lib/utils/isAdmin.ts rename to apps/api/lib/utils/isAdmin.ts diff --git a/apps/api/apps/api/lib/utils/stringifyISODate.ts b/apps/api/lib/utils/stringifyISODate.ts similarity index 100% rename from apps/api/apps/api/lib/utils/stringifyISODate.ts rename to apps/api/lib/utils/stringifyISODate.ts diff --git a/apps/api/apps/api/lib/validations/api-key.ts b/apps/api/lib/validations/api-key.ts similarity index 100% rename from apps/api/apps/api/lib/validations/api-key.ts rename to apps/api/lib/validations/api-key.ts diff --git a/apps/api/apps/api/lib/validations/attendee.ts b/apps/api/lib/validations/attendee.ts similarity index 100% rename from apps/api/apps/api/lib/validations/attendee.ts rename to apps/api/lib/validations/attendee.ts diff --git a/apps/api/apps/api/lib/validations/availability.ts b/apps/api/lib/validations/availability.ts similarity index 100% rename from apps/api/apps/api/lib/validations/availability.ts rename to apps/api/lib/validations/availability.ts diff --git a/apps/api/apps/api/lib/validations/booking-reference.ts b/apps/api/lib/validations/booking-reference.ts similarity index 100% rename from apps/api/apps/api/lib/validations/booking-reference.ts rename to apps/api/lib/validations/booking-reference.ts diff --git a/apps/api/apps/api/lib/validations/booking.ts b/apps/api/lib/validations/booking.ts similarity index 100% rename from apps/api/apps/api/lib/validations/booking.ts rename to apps/api/lib/validations/booking.ts diff --git a/apps/api/apps/api/lib/validations/destination-calendar.ts b/apps/api/lib/validations/destination-calendar.ts similarity index 100% rename from apps/api/apps/api/lib/validations/destination-calendar.ts rename to apps/api/lib/validations/destination-calendar.ts diff --git a/apps/api/apps/api/lib/validations/event-type-custom-input.ts b/apps/api/lib/validations/event-type-custom-input.ts similarity index 100% rename from apps/api/apps/api/lib/validations/event-type-custom-input.ts rename to apps/api/lib/validations/event-type-custom-input.ts diff --git a/apps/api/apps/api/lib/validations/event-type.ts b/apps/api/lib/validations/event-type.ts similarity index 100% rename from apps/api/apps/api/lib/validations/event-type.ts rename to apps/api/lib/validations/event-type.ts diff --git a/apps/api/apps/api/lib/validations/membership.ts b/apps/api/lib/validations/membership.ts similarity index 100% rename from apps/api/apps/api/lib/validations/membership.ts rename to apps/api/lib/validations/membership.ts diff --git a/apps/api/apps/api/lib/validations/payment.ts b/apps/api/lib/validations/payment.ts similarity index 100% rename from apps/api/apps/api/lib/validations/payment.ts rename to apps/api/lib/validations/payment.ts diff --git a/apps/api/apps/api/lib/validations/reminder-mail.ts b/apps/api/lib/validations/reminder-mail.ts similarity index 100% rename from apps/api/apps/api/lib/validations/reminder-mail.ts rename to apps/api/lib/validations/reminder-mail.ts diff --git a/apps/api/apps/api/lib/validations/schedule.ts b/apps/api/lib/validations/schedule.ts similarity index 100% rename from apps/api/apps/api/lib/validations/schedule.ts rename to apps/api/lib/validations/schedule.ts diff --git a/apps/api/apps/api/lib/validations/selected-calendar.ts b/apps/api/lib/validations/selected-calendar.ts similarity index 100% rename from apps/api/apps/api/lib/validations/selected-calendar.ts rename to apps/api/lib/validations/selected-calendar.ts diff --git a/apps/api/apps/api/lib/validations/shared/baseApiParams.ts b/apps/api/lib/validations/shared/baseApiParams.ts similarity index 100% rename from apps/api/apps/api/lib/validations/shared/baseApiParams.ts rename to apps/api/lib/validations/shared/baseApiParams.ts diff --git a/apps/api/apps/api/lib/validations/shared/jsonSchema.ts b/apps/api/lib/validations/shared/jsonSchema.ts similarity index 100% rename from apps/api/apps/api/lib/validations/shared/jsonSchema.ts rename to apps/api/lib/validations/shared/jsonSchema.ts diff --git a/apps/api/apps/api/lib/validations/shared/queryIdString.ts b/apps/api/lib/validations/shared/queryIdString.ts similarity index 100% rename from apps/api/apps/api/lib/validations/shared/queryIdString.ts rename to apps/api/lib/validations/shared/queryIdString.ts diff --git a/apps/api/apps/api/lib/validations/shared/queryIdTransformParseInt.ts b/apps/api/lib/validations/shared/queryIdTransformParseInt.ts similarity index 100% rename from apps/api/apps/api/lib/validations/shared/queryIdTransformParseInt.ts rename to apps/api/lib/validations/shared/queryIdTransformParseInt.ts diff --git a/apps/api/apps/api/lib/validations/shared/queryTeamId.ts b/apps/api/lib/validations/shared/queryTeamId.ts similarity index 100% rename from apps/api/apps/api/lib/validations/shared/queryTeamId.ts rename to apps/api/lib/validations/shared/queryTeamId.ts diff --git a/apps/api/apps/api/lib/validations/shared/queryUserId.ts b/apps/api/lib/validations/shared/queryUserId.ts similarity index 100% rename from apps/api/apps/api/lib/validations/shared/queryUserId.ts rename to apps/api/lib/validations/shared/queryUserId.ts diff --git a/apps/api/apps/api/lib/validations/shared/timeZone.ts b/apps/api/lib/validations/shared/timeZone.ts similarity index 100% rename from apps/api/apps/api/lib/validations/shared/timeZone.ts rename to apps/api/lib/validations/shared/timeZone.ts diff --git a/apps/api/apps/api/lib/validations/team.ts b/apps/api/lib/validations/team.ts similarity index 100% rename from apps/api/apps/api/lib/validations/team.ts rename to apps/api/lib/validations/team.ts diff --git a/apps/api/apps/api/lib/validations/user.ts b/apps/api/lib/validations/user.ts similarity index 100% rename from apps/api/apps/api/lib/validations/user.ts rename to apps/api/lib/validations/user.ts diff --git a/apps/api/apps/api/lib/validations/webhook.ts b/apps/api/lib/validations/webhook.ts similarity index 100% rename from apps/api/apps/api/lib/validations/webhook.ts rename to apps/api/lib/validations/webhook.ts diff --git a/apps/api/apps/api/next-env.d.ts b/apps/api/next-env.d.ts similarity index 100% rename from apps/api/apps/api/next-env.d.ts rename to apps/api/next-env.d.ts diff --git a/apps/api/apps/api/next-i18next.config.js b/apps/api/next-i18next.config.js similarity index 100% rename from apps/api/apps/api/next-i18next.config.js rename to apps/api/next-i18next.config.js diff --git a/apps/api/apps/api/next.config.js b/apps/api/next.config.js similarity index 100% rename from apps/api/apps/api/next.config.js rename to apps/api/next.config.js diff --git a/apps/api/apps/api/next.d.ts b/apps/api/next.d.ts similarity index 100% rename from apps/api/apps/api/next.d.ts rename to apps/api/next.d.ts diff --git a/apps/api/apps/api/package.json b/apps/api/package.json similarity index 100% rename from apps/api/apps/api/package.json rename to apps/api/package.json diff --git a/apps/api/apps/api/pages/api/api-keys/[id]/_auth-middleware.ts b/apps/api/pages/api/api-keys/[id]/_auth-middleware.ts similarity index 100% rename from apps/api/apps/api/pages/api/api-keys/[id]/_auth-middleware.ts rename to apps/api/pages/api/api-keys/[id]/_auth-middleware.ts diff --git a/apps/api/apps/api/pages/api/api-keys/[id]/_delete.ts b/apps/api/pages/api/api-keys/[id]/_delete.ts similarity index 100% rename from apps/api/apps/api/pages/api/api-keys/[id]/_delete.ts rename to apps/api/pages/api/api-keys/[id]/_delete.ts diff --git a/apps/api/apps/api/pages/api/api-keys/[id]/_get.ts b/apps/api/pages/api/api-keys/[id]/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/api-keys/[id]/_get.ts rename to apps/api/pages/api/api-keys/[id]/_get.ts diff --git a/apps/api/apps/api/pages/api/api-keys/[id]/_patch.ts b/apps/api/pages/api/api-keys/[id]/_patch.ts similarity index 100% rename from apps/api/apps/api/pages/api/api-keys/[id]/_patch.ts rename to apps/api/pages/api/api-keys/[id]/_patch.ts diff --git a/apps/api/apps/api/pages/api/api-keys/[id]/index.ts b/apps/api/pages/api/api-keys/[id]/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/api-keys/[id]/index.ts rename to apps/api/pages/api/api-keys/[id]/index.ts diff --git a/apps/api/apps/api/pages/api/api-keys/_get.ts b/apps/api/pages/api/api-keys/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/api-keys/_get.ts rename to apps/api/pages/api/api-keys/_get.ts diff --git a/apps/api/apps/api/pages/api/api-keys/_post.ts b/apps/api/pages/api/api-keys/_post.ts similarity index 100% rename from apps/api/apps/api/pages/api/api-keys/_post.ts rename to apps/api/pages/api/api-keys/_post.ts diff --git a/apps/api/apps/api/pages/api/api-keys/index.ts b/apps/api/pages/api/api-keys/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/api-keys/index.ts rename to apps/api/pages/api/api-keys/index.ts diff --git a/apps/api/apps/api/pages/api/attendees/[id]/_auth-middleware.ts b/apps/api/pages/api/attendees/[id]/_auth-middleware.ts similarity index 100% rename from apps/api/apps/api/pages/api/attendees/[id]/_auth-middleware.ts rename to apps/api/pages/api/attendees/[id]/_auth-middleware.ts diff --git a/apps/api/apps/api/pages/api/attendees/[id]/_delete.ts b/apps/api/pages/api/attendees/[id]/_delete.ts similarity index 100% rename from apps/api/apps/api/pages/api/attendees/[id]/_delete.ts rename to apps/api/pages/api/attendees/[id]/_delete.ts diff --git a/apps/api/apps/api/pages/api/attendees/[id]/_get.ts b/apps/api/pages/api/attendees/[id]/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/attendees/[id]/_get.ts rename to apps/api/pages/api/attendees/[id]/_get.ts diff --git a/apps/api/apps/api/pages/api/attendees/[id]/_patch.ts b/apps/api/pages/api/attendees/[id]/_patch.ts similarity index 100% rename from apps/api/apps/api/pages/api/attendees/[id]/_patch.ts rename to apps/api/pages/api/attendees/[id]/_patch.ts diff --git a/apps/api/apps/api/pages/api/attendees/[id]/index.ts b/apps/api/pages/api/attendees/[id]/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/attendees/[id]/index.ts rename to apps/api/pages/api/attendees/[id]/index.ts diff --git a/apps/api/apps/api/pages/api/attendees/_get.ts b/apps/api/pages/api/attendees/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/attendees/_get.ts rename to apps/api/pages/api/attendees/_get.ts diff --git a/apps/api/apps/api/pages/api/attendees/_post.ts b/apps/api/pages/api/attendees/_post.ts similarity index 100% rename from apps/api/apps/api/pages/api/attendees/_post.ts rename to apps/api/pages/api/attendees/_post.ts diff --git a/apps/api/apps/api/pages/api/attendees/index.ts b/apps/api/pages/api/attendees/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/attendees/index.ts rename to apps/api/pages/api/attendees/index.ts diff --git a/apps/api/apps/api/pages/api/availabilities/[id]/_auth-middleware.ts b/apps/api/pages/api/availabilities/[id]/_auth-middleware.ts similarity index 100% rename from apps/api/apps/api/pages/api/availabilities/[id]/_auth-middleware.ts rename to apps/api/pages/api/availabilities/[id]/_auth-middleware.ts diff --git a/apps/api/apps/api/pages/api/availabilities/[id]/_delete.ts b/apps/api/pages/api/availabilities/[id]/_delete.ts similarity index 100% rename from apps/api/apps/api/pages/api/availabilities/[id]/_delete.ts rename to apps/api/pages/api/availabilities/[id]/_delete.ts diff --git a/apps/api/apps/api/pages/api/availabilities/[id]/_get.ts b/apps/api/pages/api/availabilities/[id]/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/availabilities/[id]/_get.ts rename to apps/api/pages/api/availabilities/[id]/_get.ts diff --git a/apps/api/apps/api/pages/api/availabilities/[id]/_patch.ts b/apps/api/pages/api/availabilities/[id]/_patch.ts similarity index 100% rename from apps/api/apps/api/pages/api/availabilities/[id]/_patch.ts rename to apps/api/pages/api/availabilities/[id]/_patch.ts diff --git a/apps/api/apps/api/pages/api/availabilities/[id]/index.ts b/apps/api/pages/api/availabilities/[id]/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/availabilities/[id]/index.ts rename to apps/api/pages/api/availabilities/[id]/index.ts diff --git a/apps/api/apps/api/pages/api/availabilities/_post.ts b/apps/api/pages/api/availabilities/_post.ts similarity index 100% rename from apps/api/apps/api/pages/api/availabilities/_post.ts rename to apps/api/pages/api/availabilities/_post.ts diff --git a/apps/api/apps/api/pages/api/availabilities/index.ts b/apps/api/pages/api/availabilities/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/availabilities/index.ts rename to apps/api/pages/api/availabilities/index.ts diff --git a/apps/api/apps/api/pages/api/availability/_get.ts b/apps/api/pages/api/availability/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/availability/_get.ts rename to apps/api/pages/api/availability/_get.ts diff --git a/apps/api/apps/api/pages/api/availability/index.ts b/apps/api/pages/api/availability/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/availability/index.ts rename to apps/api/pages/api/availability/index.ts diff --git a/apps/api/apps/api/pages/api/booking-references/[id]/_auth-middleware.ts b/apps/api/pages/api/booking-references/[id]/_auth-middleware.ts similarity index 100% rename from apps/api/apps/api/pages/api/booking-references/[id]/_auth-middleware.ts rename to apps/api/pages/api/booking-references/[id]/_auth-middleware.ts diff --git a/apps/api/apps/api/pages/api/booking-references/[id]/_delete.ts b/apps/api/pages/api/booking-references/[id]/_delete.ts similarity index 100% rename from apps/api/apps/api/pages/api/booking-references/[id]/_delete.ts rename to apps/api/pages/api/booking-references/[id]/_delete.ts diff --git a/apps/api/apps/api/pages/api/booking-references/[id]/_get.ts b/apps/api/pages/api/booking-references/[id]/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/booking-references/[id]/_get.ts rename to apps/api/pages/api/booking-references/[id]/_get.ts diff --git a/apps/api/apps/api/pages/api/booking-references/[id]/_patch.ts b/apps/api/pages/api/booking-references/[id]/_patch.ts similarity index 100% rename from apps/api/apps/api/pages/api/booking-references/[id]/_patch.ts rename to apps/api/pages/api/booking-references/[id]/_patch.ts diff --git a/apps/api/apps/api/pages/api/booking-references/[id]/index.ts b/apps/api/pages/api/booking-references/[id]/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/booking-references/[id]/index.ts rename to apps/api/pages/api/booking-references/[id]/index.ts diff --git a/apps/api/apps/api/pages/api/booking-references/_get.ts b/apps/api/pages/api/booking-references/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/booking-references/_get.ts rename to apps/api/pages/api/booking-references/_get.ts diff --git a/apps/api/apps/api/pages/api/booking-references/_post.ts b/apps/api/pages/api/booking-references/_post.ts similarity index 100% rename from apps/api/apps/api/pages/api/booking-references/_post.ts rename to apps/api/pages/api/booking-references/_post.ts diff --git a/apps/api/apps/api/pages/api/booking-references/index.ts b/apps/api/pages/api/booking-references/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/booking-references/index.ts rename to apps/api/pages/api/booking-references/index.ts diff --git a/apps/api/apps/api/pages/api/bookings/[id]/_auth-middleware.ts b/apps/api/pages/api/bookings/[id]/_auth-middleware.ts similarity index 100% rename from apps/api/apps/api/pages/api/bookings/[id]/_auth-middleware.ts rename to apps/api/pages/api/bookings/[id]/_auth-middleware.ts diff --git a/apps/api/apps/api/pages/api/bookings/[id]/_delete.ts b/apps/api/pages/api/bookings/[id]/_delete.ts similarity index 100% rename from apps/api/apps/api/pages/api/bookings/[id]/_delete.ts rename to apps/api/pages/api/bookings/[id]/_delete.ts diff --git a/apps/api/apps/api/pages/api/bookings/[id]/_get.ts b/apps/api/pages/api/bookings/[id]/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/bookings/[id]/_get.ts rename to apps/api/pages/api/bookings/[id]/_get.ts diff --git a/apps/api/apps/api/pages/api/bookings/[id]/_patch.ts b/apps/api/pages/api/bookings/[id]/_patch.ts similarity index 100% rename from apps/api/apps/api/pages/api/bookings/[id]/_patch.ts rename to apps/api/pages/api/bookings/[id]/_patch.ts diff --git a/apps/api/apps/api/pages/api/bookings/[id]/cancel.ts b/apps/api/pages/api/bookings/[id]/cancel.ts similarity index 100% rename from apps/api/apps/api/pages/api/bookings/[id]/cancel.ts rename to apps/api/pages/api/bookings/[id]/cancel.ts diff --git a/apps/api/apps/api/pages/api/bookings/[id]/index.ts b/apps/api/pages/api/bookings/[id]/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/bookings/[id]/index.ts rename to apps/api/pages/api/bookings/[id]/index.ts diff --git a/apps/api/apps/api/pages/api/bookings/_get.ts b/apps/api/pages/api/bookings/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/bookings/_get.ts rename to apps/api/pages/api/bookings/_get.ts diff --git a/apps/api/apps/api/pages/api/bookings/_post.ts b/apps/api/pages/api/bookings/_post.ts similarity index 100% rename from apps/api/apps/api/pages/api/bookings/_post.ts rename to apps/api/pages/api/bookings/_post.ts diff --git a/apps/api/apps/api/pages/api/bookings/index.ts b/apps/api/pages/api/bookings/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/bookings/index.ts rename to apps/api/pages/api/bookings/index.ts diff --git a/apps/api/apps/api/pages/api/custom-inputs/[id]/_auth-middleware.ts b/apps/api/pages/api/custom-inputs/[id]/_auth-middleware.ts similarity index 100% rename from apps/api/apps/api/pages/api/custom-inputs/[id]/_auth-middleware.ts rename to apps/api/pages/api/custom-inputs/[id]/_auth-middleware.ts diff --git a/apps/api/apps/api/pages/api/custom-inputs/[id]/_delete.ts b/apps/api/pages/api/custom-inputs/[id]/_delete.ts similarity index 100% rename from apps/api/apps/api/pages/api/custom-inputs/[id]/_delete.ts rename to apps/api/pages/api/custom-inputs/[id]/_delete.ts diff --git a/apps/api/apps/api/pages/api/custom-inputs/[id]/_get.ts b/apps/api/pages/api/custom-inputs/[id]/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/custom-inputs/[id]/_get.ts rename to apps/api/pages/api/custom-inputs/[id]/_get.ts diff --git a/apps/api/apps/api/pages/api/custom-inputs/[id]/_patch.ts b/apps/api/pages/api/custom-inputs/[id]/_patch.ts similarity index 100% rename from apps/api/apps/api/pages/api/custom-inputs/[id]/_patch.ts rename to apps/api/pages/api/custom-inputs/[id]/_patch.ts diff --git a/apps/api/apps/api/pages/api/custom-inputs/[id]/index.ts b/apps/api/pages/api/custom-inputs/[id]/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/custom-inputs/[id]/index.ts rename to apps/api/pages/api/custom-inputs/[id]/index.ts diff --git a/apps/api/apps/api/pages/api/custom-inputs/_get.ts b/apps/api/pages/api/custom-inputs/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/custom-inputs/_get.ts rename to apps/api/pages/api/custom-inputs/_get.ts diff --git a/apps/api/apps/api/pages/api/custom-inputs/_post.ts b/apps/api/pages/api/custom-inputs/_post.ts similarity index 100% rename from apps/api/apps/api/pages/api/custom-inputs/_post.ts rename to apps/api/pages/api/custom-inputs/_post.ts diff --git a/apps/api/apps/api/pages/api/custom-inputs/index.ts b/apps/api/pages/api/custom-inputs/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/custom-inputs/index.ts rename to apps/api/pages/api/custom-inputs/index.ts diff --git a/apps/api/apps/api/pages/api/destination-calendars/[id].ts b/apps/api/pages/api/destination-calendars/[id].ts similarity index 100% rename from apps/api/apps/api/pages/api/destination-calendars/[id].ts rename to apps/api/pages/api/destination-calendars/[id].ts diff --git a/apps/api/apps/api/pages/api/destination-calendars/index.ts b/apps/api/pages/api/destination-calendars/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/destination-calendars/index.ts rename to apps/api/pages/api/destination-calendars/index.ts diff --git a/apps/api/apps/api/pages/api/docs.ts b/apps/api/pages/api/docs.ts similarity index 100% rename from apps/api/apps/api/pages/api/docs.ts rename to apps/api/pages/api/docs.ts diff --git a/apps/api/apps/api/pages/api/event-types/[id]/_auth-middleware.ts b/apps/api/pages/api/event-types/[id]/_auth-middleware.ts similarity index 100% rename from apps/api/apps/api/pages/api/event-types/[id]/_auth-middleware.ts rename to apps/api/pages/api/event-types/[id]/_auth-middleware.ts diff --git a/apps/api/apps/api/pages/api/event-types/[id]/_delete.ts b/apps/api/pages/api/event-types/[id]/_delete.ts similarity index 100% rename from apps/api/apps/api/pages/api/event-types/[id]/_delete.ts rename to apps/api/pages/api/event-types/[id]/_delete.ts diff --git a/apps/api/apps/api/pages/api/event-types/[id]/_get.ts b/apps/api/pages/api/event-types/[id]/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/event-types/[id]/_get.ts rename to apps/api/pages/api/event-types/[id]/_get.ts diff --git a/apps/api/apps/api/pages/api/event-types/[id]/_patch.ts b/apps/api/pages/api/event-types/[id]/_patch.ts similarity index 100% rename from apps/api/apps/api/pages/api/event-types/[id]/_patch.ts rename to apps/api/pages/api/event-types/[id]/_patch.ts diff --git a/apps/api/apps/api/pages/api/event-types/[id]/index.ts b/apps/api/pages/api/event-types/[id]/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/event-types/[id]/index.ts rename to apps/api/pages/api/event-types/[id]/index.ts diff --git a/apps/api/apps/api/pages/api/event-types/_get.ts b/apps/api/pages/api/event-types/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/event-types/_get.ts rename to apps/api/pages/api/event-types/_get.ts diff --git a/apps/api/apps/api/pages/api/event-types/_post.ts b/apps/api/pages/api/event-types/_post.ts similarity index 100% rename from apps/api/apps/api/pages/api/event-types/_post.ts rename to apps/api/pages/api/event-types/_post.ts diff --git a/apps/api/apps/api/pages/api/event-types/_utils/checkTeamEventEditPermission.ts b/apps/api/pages/api/event-types/_utils/checkTeamEventEditPermission.ts similarity index 100% rename from apps/api/apps/api/pages/api/event-types/_utils/checkTeamEventEditPermission.ts rename to apps/api/pages/api/event-types/_utils/checkTeamEventEditPermission.ts diff --git a/apps/api/apps/api/pages/api/event-types/_utils/ensureOnlyMembersAsHosts.ts b/apps/api/pages/api/event-types/_utils/ensureOnlyMembersAsHosts.ts similarity index 100% rename from apps/api/apps/api/pages/api/event-types/_utils/ensureOnlyMembersAsHosts.ts rename to apps/api/pages/api/event-types/_utils/ensureOnlyMembersAsHosts.ts diff --git a/apps/api/apps/api/pages/api/event-types/_utils/getCalLink.ts b/apps/api/pages/api/event-types/_utils/getCalLink.ts similarity index 100% rename from apps/api/apps/api/pages/api/event-types/_utils/getCalLink.ts rename to apps/api/pages/api/event-types/_utils/getCalLink.ts diff --git a/apps/api/apps/api/pages/api/event-types/index.ts b/apps/api/pages/api/event-types/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/event-types/index.ts rename to apps/api/pages/api/event-types/index.ts diff --git a/apps/api/apps/api/pages/api/index.ts b/apps/api/pages/api/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/index.ts rename to apps/api/pages/api/index.ts diff --git a/apps/api/apps/api/pages/api/me/_get.ts b/apps/api/pages/api/me/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/me/_get.ts rename to apps/api/pages/api/me/_get.ts diff --git a/apps/api/apps/api/pages/api/me/index.ts b/apps/api/pages/api/me/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/me/index.ts rename to apps/api/pages/api/me/index.ts diff --git a/apps/api/apps/api/pages/api/memberships/[id]/_auth-middleware.ts b/apps/api/pages/api/memberships/[id]/_auth-middleware.ts similarity index 100% rename from apps/api/apps/api/pages/api/memberships/[id]/_auth-middleware.ts rename to apps/api/pages/api/memberships/[id]/_auth-middleware.ts diff --git a/apps/api/apps/api/pages/api/memberships/[id]/_delete.ts b/apps/api/pages/api/memberships/[id]/_delete.ts similarity index 100% rename from apps/api/apps/api/pages/api/memberships/[id]/_delete.ts rename to apps/api/pages/api/memberships/[id]/_delete.ts diff --git a/apps/api/apps/api/pages/api/memberships/[id]/_get.ts b/apps/api/pages/api/memberships/[id]/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/memberships/[id]/_get.ts rename to apps/api/pages/api/memberships/[id]/_get.ts diff --git a/apps/api/apps/api/pages/api/memberships/[id]/_patch.ts b/apps/api/pages/api/memberships/[id]/_patch.ts similarity index 100% rename from apps/api/apps/api/pages/api/memberships/[id]/_patch.ts rename to apps/api/pages/api/memberships/[id]/_patch.ts diff --git a/apps/api/apps/api/pages/api/memberships/[id]/index.ts b/apps/api/pages/api/memberships/[id]/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/memberships/[id]/index.ts rename to apps/api/pages/api/memberships/[id]/index.ts diff --git a/apps/api/apps/api/pages/api/memberships/_get.ts b/apps/api/pages/api/memberships/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/memberships/_get.ts rename to apps/api/pages/api/memberships/_get.ts diff --git a/apps/api/apps/api/pages/api/memberships/_post.ts b/apps/api/pages/api/memberships/_post.ts similarity index 100% rename from apps/api/apps/api/pages/api/memberships/_post.ts rename to apps/api/pages/api/memberships/_post.ts diff --git a/apps/api/apps/api/pages/api/memberships/index.ts b/apps/api/pages/api/memberships/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/memberships/index.ts rename to apps/api/pages/api/memberships/index.ts diff --git a/apps/api/apps/api/pages/api/payments/[id].ts b/apps/api/pages/api/payments/[id].ts similarity index 100% rename from apps/api/apps/api/pages/api/payments/[id].ts rename to apps/api/pages/api/payments/[id].ts diff --git a/apps/api/apps/api/pages/api/payments/index.ts b/apps/api/pages/api/payments/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/payments/index.ts rename to apps/api/pages/api/payments/index.ts diff --git a/apps/api/apps/api/pages/api/schedules/[id]/_auth-middleware.ts b/apps/api/pages/api/schedules/[id]/_auth-middleware.ts similarity index 100% rename from apps/api/apps/api/pages/api/schedules/[id]/_auth-middleware.ts rename to apps/api/pages/api/schedules/[id]/_auth-middleware.ts diff --git a/apps/api/apps/api/pages/api/schedules/[id]/_delete.ts b/apps/api/pages/api/schedules/[id]/_delete.ts similarity index 100% rename from apps/api/apps/api/pages/api/schedules/[id]/_delete.ts rename to apps/api/pages/api/schedules/[id]/_delete.ts diff --git a/apps/api/apps/api/pages/api/schedules/[id]/_get.ts b/apps/api/pages/api/schedules/[id]/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/schedules/[id]/_get.ts rename to apps/api/pages/api/schedules/[id]/_get.ts diff --git a/apps/api/apps/api/pages/api/schedules/[id]/_patch.ts b/apps/api/pages/api/schedules/[id]/_patch.ts similarity index 100% rename from apps/api/apps/api/pages/api/schedules/[id]/_patch.ts rename to apps/api/pages/api/schedules/[id]/_patch.ts diff --git a/apps/api/apps/api/pages/api/schedules/[id]/index.ts b/apps/api/pages/api/schedules/[id]/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/schedules/[id]/index.ts rename to apps/api/pages/api/schedules/[id]/index.ts diff --git a/apps/api/apps/api/pages/api/schedules/_get.ts b/apps/api/pages/api/schedules/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/schedules/_get.ts rename to apps/api/pages/api/schedules/_get.ts diff --git a/apps/api/apps/api/pages/api/schedules/_post.ts b/apps/api/pages/api/schedules/_post.ts similarity index 100% rename from apps/api/apps/api/pages/api/schedules/_post.ts rename to apps/api/pages/api/schedules/_post.ts diff --git a/apps/api/apps/api/pages/api/schedules/index.ts b/apps/api/pages/api/schedules/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/schedules/index.ts rename to apps/api/pages/api/schedules/index.ts diff --git a/apps/api/apps/api/pages/api/selected-calendars/[id]/_auth-middleware.ts b/apps/api/pages/api/selected-calendars/[id]/_auth-middleware.ts similarity index 100% rename from apps/api/apps/api/pages/api/selected-calendars/[id]/_auth-middleware.ts rename to apps/api/pages/api/selected-calendars/[id]/_auth-middleware.ts diff --git a/apps/api/apps/api/pages/api/selected-calendars/[id]/_delete.ts b/apps/api/pages/api/selected-calendars/[id]/_delete.ts similarity index 100% rename from apps/api/apps/api/pages/api/selected-calendars/[id]/_delete.ts rename to apps/api/pages/api/selected-calendars/[id]/_delete.ts diff --git a/apps/api/apps/api/pages/api/selected-calendars/[id]/_get.ts b/apps/api/pages/api/selected-calendars/[id]/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/selected-calendars/[id]/_get.ts rename to apps/api/pages/api/selected-calendars/[id]/_get.ts diff --git a/apps/api/apps/api/pages/api/selected-calendars/[id]/_patch.ts b/apps/api/pages/api/selected-calendars/[id]/_patch.ts similarity index 100% rename from apps/api/apps/api/pages/api/selected-calendars/[id]/_patch.ts rename to apps/api/pages/api/selected-calendars/[id]/_patch.ts diff --git a/apps/api/apps/api/pages/api/selected-calendars/[id]/index.ts b/apps/api/pages/api/selected-calendars/[id]/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/selected-calendars/[id]/index.ts rename to apps/api/pages/api/selected-calendars/[id]/index.ts diff --git a/apps/api/apps/api/pages/api/selected-calendars/_get.ts b/apps/api/pages/api/selected-calendars/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/selected-calendars/_get.ts rename to apps/api/pages/api/selected-calendars/_get.ts diff --git a/apps/api/apps/api/pages/api/selected-calendars/_post.ts b/apps/api/pages/api/selected-calendars/_post.ts similarity index 100% rename from apps/api/apps/api/pages/api/selected-calendars/_post.ts rename to apps/api/pages/api/selected-calendars/_post.ts diff --git a/apps/api/apps/api/pages/api/selected-calendars/index.ts b/apps/api/pages/api/selected-calendars/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/selected-calendars/index.ts rename to apps/api/pages/api/selected-calendars/index.ts diff --git a/apps/api/apps/api/pages/api/teams/[teamId]/_auth-middleware.ts b/apps/api/pages/api/teams/[teamId]/_auth-middleware.ts similarity index 100% rename from apps/api/apps/api/pages/api/teams/[teamId]/_auth-middleware.ts rename to apps/api/pages/api/teams/[teamId]/_auth-middleware.ts diff --git a/apps/api/apps/api/pages/api/teams/[teamId]/_delete.ts b/apps/api/pages/api/teams/[teamId]/_delete.ts similarity index 100% rename from apps/api/apps/api/pages/api/teams/[teamId]/_delete.ts rename to apps/api/pages/api/teams/[teamId]/_delete.ts diff --git a/apps/api/apps/api/pages/api/teams/[teamId]/_get.ts b/apps/api/pages/api/teams/[teamId]/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/teams/[teamId]/_get.ts rename to apps/api/pages/api/teams/[teamId]/_get.ts diff --git a/apps/api/apps/api/pages/api/teams/[teamId]/_patch.ts b/apps/api/pages/api/teams/[teamId]/_patch.ts similarity index 100% rename from apps/api/apps/api/pages/api/teams/[teamId]/_patch.ts rename to apps/api/pages/api/teams/[teamId]/_patch.ts diff --git a/apps/api/apps/api/pages/api/teams/[teamId]/availability/index.ts b/apps/api/pages/api/teams/[teamId]/availability/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/teams/[teamId]/availability/index.ts rename to apps/api/pages/api/teams/[teamId]/availability/index.ts diff --git a/apps/api/apps/api/pages/api/teams/[teamId]/event-types/_get.ts b/apps/api/pages/api/teams/[teamId]/event-types/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/teams/[teamId]/event-types/_get.ts rename to apps/api/pages/api/teams/[teamId]/event-types/_get.ts diff --git a/apps/api/apps/api/pages/api/teams/[teamId]/event-types/index.ts b/apps/api/pages/api/teams/[teamId]/event-types/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/teams/[teamId]/event-types/index.ts rename to apps/api/pages/api/teams/[teamId]/event-types/index.ts diff --git a/apps/api/apps/api/pages/api/teams/[teamId]/index.ts b/apps/api/pages/api/teams/[teamId]/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/teams/[teamId]/index.ts rename to apps/api/pages/api/teams/[teamId]/index.ts diff --git a/apps/api/apps/api/pages/api/teams/[teamId]/publish.ts b/apps/api/pages/api/teams/[teamId]/publish.ts similarity index 100% rename from apps/api/apps/api/pages/api/teams/[teamId]/publish.ts rename to apps/api/pages/api/teams/[teamId]/publish.ts diff --git a/apps/api/apps/api/pages/api/teams/_get.ts b/apps/api/pages/api/teams/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/teams/_get.ts rename to apps/api/pages/api/teams/_get.ts diff --git a/apps/api/apps/api/pages/api/teams/_post.ts b/apps/api/pages/api/teams/_post.ts similarity index 100% rename from apps/api/apps/api/pages/api/teams/_post.ts rename to apps/api/pages/api/teams/_post.ts diff --git a/apps/api/apps/api/pages/api/teams/index.ts b/apps/api/pages/api/teams/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/teams/index.ts rename to apps/api/pages/api/teams/index.ts diff --git a/apps/api/apps/api/pages/api/users/[userId]/_delete.ts b/apps/api/pages/api/users/[userId]/_delete.ts similarity index 100% rename from apps/api/apps/api/pages/api/users/[userId]/_delete.ts rename to apps/api/pages/api/users/[userId]/_delete.ts diff --git a/apps/api/apps/api/pages/api/users/[userId]/_get.ts b/apps/api/pages/api/users/[userId]/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/users/[userId]/_get.ts rename to apps/api/pages/api/users/[userId]/_get.ts diff --git a/apps/api/apps/api/pages/api/users/[userId]/_patch.ts b/apps/api/pages/api/users/[userId]/_patch.ts similarity index 100% rename from apps/api/apps/api/pages/api/users/[userId]/_patch.ts rename to apps/api/pages/api/users/[userId]/_patch.ts diff --git a/apps/api/apps/api/pages/api/users/[userId]/availability/index.ts b/apps/api/pages/api/users/[userId]/availability/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/users/[userId]/availability/index.ts rename to apps/api/pages/api/users/[userId]/availability/index.ts diff --git a/apps/api/apps/api/pages/api/users/[userId]/index.ts b/apps/api/pages/api/users/[userId]/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/users/[userId]/index.ts rename to apps/api/pages/api/users/[userId]/index.ts diff --git a/apps/api/apps/api/pages/api/users/_get.ts b/apps/api/pages/api/users/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/users/_get.ts rename to apps/api/pages/api/users/_get.ts diff --git a/apps/api/apps/api/pages/api/users/_post.ts b/apps/api/pages/api/users/_post.ts similarity index 100% rename from apps/api/apps/api/pages/api/users/_post.ts rename to apps/api/pages/api/users/_post.ts diff --git a/apps/api/apps/api/pages/api/users/index.ts b/apps/api/pages/api/users/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/users/index.ts rename to apps/api/pages/api/users/index.ts diff --git a/apps/api/apps/api/pages/api/webhooks/[id]/_auth-middleware.ts b/apps/api/pages/api/webhooks/[id]/_auth-middleware.ts similarity index 100% rename from apps/api/apps/api/pages/api/webhooks/[id]/_auth-middleware.ts rename to apps/api/pages/api/webhooks/[id]/_auth-middleware.ts diff --git a/apps/api/apps/api/pages/api/webhooks/[id]/_delete.ts b/apps/api/pages/api/webhooks/[id]/_delete.ts similarity index 100% rename from apps/api/apps/api/pages/api/webhooks/[id]/_delete.ts rename to apps/api/pages/api/webhooks/[id]/_delete.ts diff --git a/apps/api/apps/api/pages/api/webhooks/[id]/_get.ts b/apps/api/pages/api/webhooks/[id]/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/webhooks/[id]/_get.ts rename to apps/api/pages/api/webhooks/[id]/_get.ts diff --git a/apps/api/apps/api/pages/api/webhooks/[id]/_patch.ts b/apps/api/pages/api/webhooks/[id]/_patch.ts similarity index 100% rename from apps/api/apps/api/pages/api/webhooks/[id]/_patch.ts rename to apps/api/pages/api/webhooks/[id]/_patch.ts diff --git a/apps/api/apps/api/pages/api/webhooks/[id]/index.ts b/apps/api/pages/api/webhooks/[id]/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/webhooks/[id]/index.ts rename to apps/api/pages/api/webhooks/[id]/index.ts diff --git a/apps/api/apps/api/pages/api/webhooks/_get.ts b/apps/api/pages/api/webhooks/_get.ts similarity index 100% rename from apps/api/apps/api/pages/api/webhooks/_get.ts rename to apps/api/pages/api/webhooks/_get.ts diff --git a/apps/api/apps/api/pages/api/webhooks/_post.ts b/apps/api/pages/api/webhooks/_post.ts similarity index 100% rename from apps/api/apps/api/pages/api/webhooks/_post.ts rename to apps/api/pages/api/webhooks/_post.ts diff --git a/apps/api/apps/api/pages/api/webhooks/index.ts b/apps/api/pages/api/webhooks/index.ts similarity index 100% rename from apps/api/apps/api/pages/api/webhooks/index.ts rename to apps/api/pages/api/webhooks/index.ts diff --git a/apps/api/apps/api/scripts/vercel-deploy.sh b/apps/api/scripts/vercel-deploy.sh similarity index 100% rename from apps/api/apps/api/scripts/vercel-deploy.sh rename to apps/api/scripts/vercel-deploy.sh diff --git a/apps/api/apps/api/test/README.md b/apps/api/test/README.md similarity index 100% rename from apps/api/apps/api/test/README.md rename to apps/api/test/README.md diff --git a/apps/api/apps/api/test/docker-compose.yml b/apps/api/test/docker-compose.yml similarity index 100% rename from apps/api/apps/api/test/docker-compose.yml rename to apps/api/test/docker-compose.yml diff --git a/apps/api/apps/api/test/jest-resolver.js b/apps/api/test/jest-resolver.js similarity index 100% rename from apps/api/apps/api/test/jest-resolver.js rename to apps/api/test/jest-resolver.js diff --git a/apps/api/apps/api/test/jest-setup.js b/apps/api/test/jest-setup.js similarity index 100% rename from apps/api/apps/api/test/jest-setup.js rename to apps/api/test/jest-setup.js diff --git a/apps/api/apps/api/test/lib/bookings/_post.test.ts b/apps/api/test/lib/bookings/_post.test.ts similarity index 100% rename from apps/api/apps/api/test/lib/bookings/_post.test.ts rename to apps/api/test/lib/bookings/_post.test.ts diff --git a/apps/api/apps/api/tsconfig.json b/apps/api/tsconfig.json similarity index 100% rename from apps/api/apps/api/tsconfig.json rename to apps/api/tsconfig.json From a93e1b2881e685d37c992879fd2765345dc888eb Mon Sep 17 00:00:00 2001 From: Peer Richelsen Date: Thu, 25 May 2023 19:33:10 +0100 Subject: [PATCH 644/658] Update README.md --- apps/api/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/api/README.md b/apps/api/README.md index 6601764d73..bd9217ba09 100644 --- a/apps/api/README.md +++ b/apps/api/README.md @@ -4,7 +4,7 @@ Logo - Read the API docs + Read the API docs # Cal.com Public API From 8795f41b785f58c7d1d35ece393ff6c5dba6a1a9 Mon Sep 17 00:00:00 2001 From: zomars Date: Thu, 25 May 2023 11:53:47 -0700 Subject: [PATCH 645/658] Ignores API unit tests for now --- vitest.workspace.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vitest.workspace.ts b/vitest.workspace.ts index ad771f4cb8..97d8cbcce6 100644 --- a/vitest.workspace.ts +++ b/vitest.workspace.ts @@ -5,6 +5,8 @@ export default defineWorkspace([ { test: { include: ["packages/**/*.{test,spec}.{ts,js}", "apps/**/*.{test,spec}.{ts,js}"], + // TODO: Ignore the api until tests are fixed + exclude: ["apps/api/**/*", "**/node_modules/**/*"], }, }, { From 448792aafef9d7a4cfdc628a3bdf5a3f2126043e Mon Sep 17 00:00:00 2001 From: zomars Date: Thu, 25 May 2023 11:53:58 -0700 Subject: [PATCH 646/658] Update yarn.lock --- yarn.lock | 36 ++---------------------------------- 1 file changed, 2 insertions(+), 34 deletions(-) diff --git a/yarn.lock b/yarn.lock index aaf74b59d5..de6eb38b39 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4230,8 +4230,8 @@ __metadata: "@types/react": 18.0.26 "@types/react-dom": 18.0.9 eslint: ^8.34.0 - eslint-config-next: ~13.2.1 - next: ~13.2.1 + eslint-config-next: ^13.2.1 + next: ^13.2.1 next-auth: ^4.20.1 react: ^18.2.0 react-dom: ^18.2.0 @@ -8653,15 +8653,6 @@ __metadata: languageName: node linkType: hard -"@next/eslint-plugin-next@npm:13.2.4": - version: 13.2.4 - resolution: "@next/eslint-plugin-next@npm:13.2.4" - dependencies: - glob: 7.1.7 - checksum: 95f9a84922ec1c73aa51b794f9d2dc49c165a1c793db17cab4558097d31aaf65c2e5e3390d0691c056fac105562d6dc974b13b1df79981f8b7faba005f6eb3b5 - languageName: node - linkType: hard - "@next/swc-android-arm-eabi@npm:13.2.3": version: 13.2.3 resolution: "@next/swc-android-arm-eabi@npm:13.2.3" @@ -21426,29 +21417,6 @@ __metadata: languageName: node linkType: hard -"eslint-config-next@npm:~13.2.1": - version: 13.2.4 - resolution: "eslint-config-next@npm:13.2.4" - dependencies: - "@next/eslint-plugin-next": 13.2.4 - "@rushstack/eslint-patch": ^1.1.3 - "@typescript-eslint/parser": ^5.42.0 - eslint-import-resolver-node: ^0.3.6 - eslint-import-resolver-typescript: ^3.5.2 - eslint-plugin-import: ^2.26.0 - eslint-plugin-jsx-a11y: ^6.5.1 - eslint-plugin-react: ^7.31.7 - eslint-plugin-react-hooks: ^4.5.0 - peerDependencies: - eslint: ^7.23.0 || ^8.0.0 - typescript: ">=3.3.1" - peerDependenciesMeta: - typescript: - optional: true - checksum: 84c202db75ec17c8a7fcebb3364f5b66fc9e81199442cb85d9531f284be5e102935f17aec5274da9ea39752ae9fc8a6afaf5a1e06fe4c8cb8695cf9bee8ea24f - languageName: node - linkType: hard - "eslint-config-prettier@npm:^8.6.0": version: 8.6.0 resolution: "eslint-config-prettier@npm:8.6.0" From 5e13cc06a62e3eee1e0208d03245e4127ace6540 Mon Sep 17 00:00:00 2001 From: zomars Date: Thu, 25 May 2023 14:55:44 -0700 Subject: [PATCH 647/658] Prevents flooding the logs when querying custom logos --- apps/web/pages/api/logo.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/web/pages/api/logo.ts b/apps/web/pages/api/logo.ts index 6abe10e3ae..cece787251 100644 --- a/apps/web/pages/api/logo.ts +++ b/apps/web/pages/api/logo.ts @@ -2,6 +2,9 @@ import type { NextApiRequest, NextApiResponse } from "next"; import { z } from "zod"; import { IS_SELF_HOSTED, LOGO, LOGO_ICON, WEBAPP_URL } from "@calcom/lib/constants"; +import logger from "@calcom/lib/logger"; + +const log = logger.getChildLogger({ prefix: ["[api/logo]"] }); function removePort(url: string) { return url.replace(/:\d+$/, ""); @@ -51,7 +54,7 @@ async function getTeamLogos(subdomain: string) { appIconLogo: team.appIconLogo || `${WEBAPP_URL}${LOGO_ICON}`, }; } catch (error) { - if (error instanceof Error) console.error(error.message); + if (error instanceof Error) log.debug(error.message); return { appLogo: `${WEBAPP_URL}${LOGO}`, appIconLogo: `${WEBAPP_URL}${LOGO_ICON}`, From 98a6f8fc0e8126cc6d91b510e879db299b2c30fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Omar=20L=C3=B3pez?= Date: Thu, 25 May 2023 15:12:59 -0700 Subject: [PATCH 648/658] v2.9.3 --- apps/web/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/package.json b/apps/web/package.json index e0dffcc73a..43116cd3c7 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@calcom/web", - "version": "2.9.2", + "version": "2.9.3", "private": true, "scripts": { "analyze": "ANALYZE=true next build", From 8084a225e19e2714b8fb3468bf88a9486cae4ccc Mon Sep 17 00:00:00 2001 From: zomars Date: Thu, 25 May 2023 15:22:04 -0700 Subject: [PATCH 649/658] Removes jest from API --- apps/api/jest.setup.ts | 6 - apps/api/package.json | 4 +- yarn.lock | 1323 +--------------------------------------- 3 files changed, 17 insertions(+), 1316 deletions(-) delete mode 100644 apps/api/jest.setup.ts diff --git a/apps/api/jest.setup.ts b/apps/api/jest.setup.ts deleted file mode 100644 index b764cee58f..0000000000 --- a/apps/api/jest.setup.ts +++ /dev/null @@ -1,6 +0,0 @@ -import prisma from "@calcom/prisma"; - -afterEach((done) => { - prisma.$disconnect().then(); - done(); -}); diff --git a/apps/api/package.json b/apps/api/package.json index fea62daa18..6e3bb66f3a 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -14,14 +14,12 @@ "lint:report": "eslint . --format json --output-file ../../lint-results/api.json", "lint:fix": "eslint . --ext .ts,.js,.tsx,.jsx --fix", "start": "PORT=3002 next start", - "test": "jest --detectOpenHandles --passWithNoTests", + "test": "echo 'No tests yet' && exit 1", "type-check": "tsc --pretty --noEmit" }, "devDependencies": { "@calcom/tsconfig": "*", "@calcom/types": "*", - "babel-jest": "^28.1.0", - "jest": "^28.1.0", "node-mocks-http": "^1.11.0" }, "dependencies": { diff --git a/yarn.lock b/yarn.lock index de6eb38b39..242bbf36c1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1238,15 +1238,6 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.21.4": - version: 7.21.4 - resolution: "@babel/code-frame@npm:7.21.4" - dependencies: - "@babel/highlight": ^7.18.6 - checksum: e5390e6ec1ac58dcef01d4f18eaf1fd2f1325528661ff6d4a5de8979588b9f5a8e852a54a91b923846f7a5c681b217f0a45c2524eb9560553160cd963b7d592c - languageName: node - linkType: hard - "@babel/compat-data@npm:^7.13.11, @babel/compat-data@npm:^7.18.6, @babel/compat-data@npm:^7.18.8": version: 7.18.8 resolution: "@babel/compat-data@npm:7.18.8" @@ -1275,13 +1266,6 @@ __metadata: languageName: node linkType: hard -"@babel/compat-data@npm:^7.21.5": - version: 7.21.9 - resolution: "@babel/compat-data@npm:7.21.9" - checksum: df97be04955c0801f5a23846f79a100660aa98f9433cfd1fad8f53ecd9f3454538e78522e86275939aa8aa7d6f9e32f23f94bc04ae843f7246b7cd4bffe3a175 - languageName: node - linkType: hard - "@babel/core@npm:7.12.9": version: 7.12.9 resolution: "@babel/core@npm:7.12.9" @@ -1329,29 +1313,6 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.11.6": - version: 7.21.8 - resolution: "@babel/core@npm:7.21.8" - dependencies: - "@ampproject/remapping": ^2.2.0 - "@babel/code-frame": ^7.21.4 - "@babel/generator": ^7.21.5 - "@babel/helper-compilation-targets": ^7.21.5 - "@babel/helper-module-transforms": ^7.21.5 - "@babel/helpers": ^7.21.5 - "@babel/parser": ^7.21.8 - "@babel/template": ^7.20.7 - "@babel/traverse": ^7.21.5 - "@babel/types": ^7.21.5 - convert-source-map: ^1.7.0 - debug: ^4.1.0 - gensync: ^1.0.0-beta.2 - json5: ^2.2.2 - semver: ^6.3.0 - checksum: f28118447355af2a90bd340e2e60699f94c8020517eba9b71bf8ebff62fa9e00d63f076e033f9dfb97548053ad62ada45fafb0d96584b1a90e8aef5a3b8241b1 - languageName: node - linkType: hard - "@babel/core@npm:^7.12.10": version: 7.18.6 resolution: "@babel/core@npm:7.18.6" @@ -1533,18 +1494,6 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:^7.21.5, @babel/generator@npm:^7.7.2": - version: 7.21.9 - resolution: "@babel/generator@npm:7.21.9" - dependencies: - "@babel/types": ^7.21.5 - "@jridgewell/gen-mapping": ^0.3.2 - "@jridgewell/trace-mapping": ^0.3.17 - jsesc: ^2.5.1 - checksum: 5bd10334ebdf7f2a30eb4a1fd99d369a57703aa2234527784449187512c254a1174fa739c9d4c31bcbb6018732012a0664bec7c314f12b5ec2458737ddbb01c7 - languageName: node - linkType: hard - "@babel/helper-annotate-as-pure@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-annotate-as-pure@npm:7.18.6" @@ -1635,21 +1584,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.21.5": - version: 7.21.5 - resolution: "@babel/helper-compilation-targets@npm:7.21.5" - dependencies: - "@babel/compat-data": ^7.21.5 - "@babel/helper-validator-option": ^7.21.0 - browserslist: ^4.21.3 - lru-cache: ^5.1.1 - semver: ^6.3.0 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 0edecb9c970ddc22ebda1163e77a7f314121bef9e483e0e0d9a5802540eed90d5855b6bf9bce03419b35b2e07c323e62d0353b153fa1ca34f17dbba897a83c25 - languageName: node - linkType: hard - "@babel/helper-create-class-features-plugin@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-create-class-features-plugin@npm:7.18.6" @@ -1747,13 +1681,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-environment-visitor@npm:^7.21.5": - version: 7.21.5 - resolution: "@babel/helper-environment-visitor@npm:7.21.5" - checksum: e436af7b62956e919066448013a3f7e2cd0b51010c26c50f790124dcd350be81d5597b4e6ed0a4a42d098a27de1e38561cd7998a116a42e7899161192deac9a6 - languageName: node - linkType: hard - "@babel/helper-explode-assignable-expression@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-explode-assignable-expression@npm:7.18.6" @@ -1868,15 +1795,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-imports@npm:^7.21.4": - version: 7.21.4 - resolution: "@babel/helper-module-imports@npm:7.21.4" - dependencies: - "@babel/types": ^7.21.4 - checksum: bd330a2edaafeb281fbcd9357652f8d2666502567c0aad71db926e8499c773c9ea9c10dfaae30122452940326d90c8caff5c649ed8e1bf15b23f858758d3abc6 - languageName: node - linkType: hard - "@babel/helper-module-transforms@npm:^7.12.1": version: 7.20.11 resolution: "@babel/helper-module-transforms@npm:7.20.11" @@ -1973,22 +1891,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.21.5": - version: 7.21.5 - resolution: "@babel/helper-module-transforms@npm:7.21.5" - dependencies: - "@babel/helper-environment-visitor": ^7.21.5 - "@babel/helper-module-imports": ^7.21.4 - "@babel/helper-simple-access": ^7.21.5 - "@babel/helper-split-export-declaration": ^7.18.6 - "@babel/helper-validator-identifier": ^7.19.1 - "@babel/template": ^7.20.7 - "@babel/traverse": ^7.21.5 - "@babel/types": ^7.21.5 - checksum: 1ccfc88830675a5d485d198e918498f9683cdd46f973fdd4fe1c85b99648fb70f87fca07756c7a05dc201bd9b248c74ced06ea80c9991926ac889f53c3659675 - languageName: node - linkType: hard - "@babel/helper-optimise-call-expression@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-optimise-call-expression@npm:7.18.6" @@ -2096,15 +1998,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-simple-access@npm:^7.21.5": - version: 7.21.5 - resolution: "@babel/helper-simple-access@npm:7.21.5" - dependencies: - "@babel/types": ^7.21.5 - checksum: ad212beaa24be3864c8c95bee02f840222457ccf5419991e2d3e3e39b0f75b77e7e857e0bf4ed428b1cd97acefc87f3831bdb0b9696d5ad0557421f398334fc3 - languageName: node - linkType: hard - "@babel/helper-skip-transparent-expression-wrappers@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.18.6" @@ -2146,13 +2039,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.21.5": - version: 7.21.5 - resolution: "@babel/helper-string-parser@npm:7.21.5" - checksum: 36c0ded452f3858e67634b81960d4bde1d1cd2a56b82f4ba2926e97864816021c885f111a7cf81de88a0ed025f49d84a393256700e9acbca2d99462d648705d8 - languageName: node - linkType: hard - "@babel/helper-validator-identifier@npm:^7.16.7": version: 7.16.7 resolution: "@babel/helper-validator-identifier@npm:7.16.7" @@ -2188,13 +2074,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-validator-option@npm:^7.21.0": - version: 7.21.0 - resolution: "@babel/helper-validator-option@npm:7.21.0" - checksum: 8ece4c78ffa5461fd8ab6b6e57cc51afad59df08192ed5d84b475af4a7193fc1cb794b59e3e7be64f3cdc4df7ac78bf3dbb20c129d7757ae078e6279ff8c2f07 - languageName: node - linkType: hard - "@babel/helper-wrap-function@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-wrap-function@npm:7.18.6" @@ -2262,17 +2141,6 @@ __metadata: languageName: node linkType: hard -"@babel/helpers@npm:^7.21.5": - version: 7.21.5 - resolution: "@babel/helpers@npm:7.21.5" - dependencies: - "@babel/template": ^7.20.7 - "@babel/traverse": ^7.21.5 - "@babel/types": ^7.21.5 - checksum: a6f74b8579713988e7f5adf1a986d8b5255757632ba65b2552f0f609ead5476edb784044c7e4b18f3681ee4818ca9d08c41feb9bd4e828648c25a00deaa1f9e4 - languageName: node - linkType: hard - "@babel/highlight@npm:^7.16.7": version: 7.16.10 resolution: "@babel/highlight@npm:7.16.10" @@ -2295,15 +2163,6 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.21.5, @babel/parser@npm:^7.21.8, @babel/parser@npm:^7.21.9": - version: 7.21.9 - resolution: "@babel/parser@npm:7.21.9" - bin: - parser: ./bin/babel-parser.js - checksum: 985ccc311eb286a320331fd21ff54d94935df76e081abdb304cd4591ea2051a6c799c6b0d8e26d09a9dd041797d9a91ebadeb0c50699d0101bd39fc565082d5c - languageName: node - linkType: hard - "@babel/parser@npm:^7.12.11, @babel/parser@npm:^7.18.6, @babel/parser@npm:^7.18.8": version: 7.18.8 resolution: "@babel/parser@npm:7.18.8" @@ -2649,18 +2508,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-bigint@npm:^7.8.3": - version: 7.8.3 - resolution: "@babel/plugin-syntax-bigint@npm:7.8.3" - dependencies: - "@babel/helper-plugin-utils": ^7.8.0 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 3a10849d83e47aec50f367a9e56a6b22d662ddce643334b087f9828f4c3dd73bdc5909aaeabe123fed78515767f9ca43498a0e621c438d1cd2802d7fae3c9648 - languageName: node - linkType: hard - -"@babel/plugin-syntax-class-properties@npm:^7.12.13, @babel/plugin-syntax-class-properties@npm:^7.8.3": +"@babel/plugin-syntax-class-properties@npm:^7.12.13": version: 7.12.13 resolution: "@babel/plugin-syntax-class-properties@npm:7.12.13" dependencies: @@ -2748,17 +2596,6 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-import-meta@npm:^7.8.3": - version: 7.10.4 - resolution: "@babel/plugin-syntax-import-meta@npm:7.10.4" - dependencies: - "@babel/helper-plugin-utils": ^7.10.4 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 166ac1125d10b9c0c430e4156249a13858c0366d38844883d75d27389621ebe651115cb2ceb6dc011534d5055719fa1727b59f39e1ab3ca97820eef3dcab5b9b - languageName: node - linkType: hard - "@babel/plugin-syntax-json-strings@npm:^7.8.3": version: 7.8.3 resolution: "@babel/plugin-syntax-json-strings@npm:7.8.3" @@ -2803,7 +2640,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-logical-assignment-operators@npm:^7.10.4, @babel/plugin-syntax-logical-assignment-operators@npm:^7.8.3": +"@babel/plugin-syntax-logical-assignment-operators@npm:^7.10.4": version: 7.10.4 resolution: "@babel/plugin-syntax-logical-assignment-operators@npm:7.10.4" dependencies: @@ -2825,7 +2662,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-numeric-separator@npm:^7.10.4, @babel/plugin-syntax-numeric-separator@npm:^7.8.3": +"@babel/plugin-syntax-numeric-separator@npm:^7.10.4": version: 7.10.4 resolution: "@babel/plugin-syntax-numeric-separator@npm:7.10.4" dependencies: @@ -2880,7 +2717,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-top-level-await@npm:^7.14.5, @babel/plugin-syntax-top-level-await@npm:^7.8.3": +"@babel/plugin-syntax-top-level-await@npm:^7.14.5": version: 7.14.5 resolution: "@babel/plugin-syntax-top-level-await@npm:7.14.5" dependencies: @@ -2902,17 +2739,6 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-typescript@npm:^7.7.2": - version: 7.21.4 - resolution: "@babel/plugin-syntax-typescript@npm:7.21.4" - dependencies: - "@babel/helper-plugin-utils": ^7.20.2 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: a59ce2477b7ae8c8945dc37dda292fef9ce46a6507b3d76b03ce7f3a6c9451a6567438b20a78ebcb3955d04095fd1ccd767075a863f79fcc30aa34dcfa441fe0 - languageName: node - linkType: hard - "@babel/plugin-transform-arrow-functions@npm:^7.12.1, @babel/plugin-transform-arrow-functions@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-transform-arrow-functions@npm:7.18.6" @@ -3750,17 +3576,6 @@ __metadata: languageName: node linkType: hard -"@babel/template@npm:^7.3.3": - version: 7.21.9 - resolution: "@babel/template@npm:7.21.9" - dependencies: - "@babel/code-frame": ^7.21.4 - "@babel/parser": ^7.21.9 - "@babel/types": ^7.21.5 - checksum: 6ec2c60d4d53b2a9230ab82c399ba6525df87e9a4e01e4b111e071cbad283b1362e7c99a1bc50027073f44f2de36a495a89c27112c4e7efe7ef9c8d9c84de2ec - languageName: node - linkType: hard - "@babel/traverse@npm:7.17.3, @babel/traverse@npm:^7.13.0, @babel/traverse@npm:^7.17.3": version: 7.17.3 resolution: "@babel/traverse@npm:7.17.3" @@ -3905,24 +3720,6 @@ __metadata: languageName: node linkType: hard -"@babel/traverse@npm:^7.21.5, @babel/traverse@npm:^7.7.2": - version: 7.21.5 - resolution: "@babel/traverse@npm:7.21.5" - dependencies: - "@babel/code-frame": ^7.21.4 - "@babel/generator": ^7.21.5 - "@babel/helper-environment-visitor": ^7.21.5 - "@babel/helper-function-name": ^7.21.0 - "@babel/helper-hoist-variables": ^7.18.6 - "@babel/helper-split-export-declaration": ^7.18.6 - "@babel/parser": ^7.21.5 - "@babel/types": ^7.21.5 - debug: ^4.1.0 - globals: ^11.1.0 - checksum: b403733fa7d858f0c8e224f0434a6ade641bc469a4f92975363391e796629d5bf53e544761dfe85039aab92d5389ebe7721edb309d7a5bb7df2bf74f37bf9f47 - languageName: node - linkType: hard - "@babel/types@npm:7.17.0, @babel/types@npm:^7.16.7, @babel/types@npm:^7.17.0": version: 7.17.0 resolution: "@babel/types@npm:7.17.0" @@ -3933,17 +3730,6 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.21.4, @babel/types@npm:^7.21.5, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3": - version: 7.21.5 - resolution: "@babel/types@npm:7.21.5" - dependencies: - "@babel/helper-string-parser": ^7.21.5 - "@babel/helper-validator-identifier": ^7.19.1 - to-fast-properties: ^2.0.0 - checksum: 43242a99c612d13285ee4af46cc0f1066bcb6ffd38307daef7a76e8c70f36cfc3255eb9e75c8e768b40e761176c313aec4d5c0b9d97a21e494d49d5fd123a9f7 - languageName: node - linkType: hard - "@babel/types@npm:^7.12.11, @babel/types@npm:^7.18.6, @babel/types@npm:^7.18.7, @babel/types@npm:^7.18.8, @babel/types@npm:^7.2.0, @babel/types@npm:^7.4.4": version: 7.18.8 resolution: "@babel/types@npm:7.18.8" @@ -4117,9 +3903,7 @@ __metadata: "@calcom/tsconfig": "*" "@calcom/types": "*" "@sentry/nextjs": ^7.20.0 - babel-jest: ^28.1.0 bcryptjs: ^2.4.3 - jest: ^28.1.0 memory-cache: ^0.2.0 next: ~13.2.1 next-api-middleware: ^1.0.1 @@ -7333,165 +7117,6 @@ __metadata: languageName: node linkType: hard -"@jest/console@npm:^28.1.3": - version: 28.1.3 - resolution: "@jest/console@npm:28.1.3" - 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 - checksum: fe50d98d26d02ce2901c76dff4bd5429a33c13affb692c9ebf8a578ca2f38a5dd854363d40d6c394f215150791fd1f692afd8e730a4178dda24107c8dfd9750a - languageName: node - linkType: hard - -"@jest/core@npm:^28.1.3": - version: 28.1.3 - resolution: "@jest/core@npm:28.1.3" - 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 - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - checksum: cb79f34bafc4637e7130df12257f5b29075892a2be2c7f45c6d4c0420853e80b5dae11016e652530eb234f4c44c00910cdca3c2cd86275721860725073f7d9b4 - languageName: node - linkType: hard - -"@jest/environment@npm:^28.1.3": - version: 28.1.3 - resolution: "@jest/environment@npm:28.1.3" - dependencies: - "@jest/fake-timers": ^28.1.3 - "@jest/types": ^28.1.3 - "@types/node": "*" - jest-mock: ^28.1.3 - checksum: 14c496b84aef951df33128cea68988e9de43b2e9d62be9f9c4308d4ac307fa345642813679f80d0a4cedeb900cf6f0b6bb2b92ce089528e8721f72295fdc727f - languageName: node - linkType: hard - -"@jest/expect-utils@npm:^28.1.3": - version: 28.1.3 - resolution: "@jest/expect-utils@npm:28.1.3" - dependencies: - jest-get-type: ^28.0.2 - checksum: 808ea3a68292a7e0b95490fdd55605c430b4cf209ea76b5b61bfb2a1badcb41bc046810fe4e364bd5fe04663978aa2bd73d8f8465a761dd7c655aeb44cf22987 - languageName: node - linkType: hard - -"@jest/expect@npm:^28.1.3": - version: 28.1.3 - resolution: "@jest/expect@npm:28.1.3" - dependencies: - expect: ^28.1.3 - jest-snapshot: ^28.1.3 - checksum: 4197f6fdddc33dc45ba4e838f992fc61839c421d7aed0dfe665ef9c2f172bb1df8a8cac9cecee272b40e744a326da521d5e182709fe82a0b936055bfffa3b473 - languageName: node - linkType: hard - -"@jest/fake-timers@npm:^28.1.3": - version: 28.1.3 - resolution: "@jest/fake-timers@npm:28.1.3" - 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 - checksum: cec14d5b14913a54dce64a62912c5456235f5d90b509ceae19c727565073114dae1aaf960ac6be96b3eb94789a3a758b96b72c8fca7e49a6ccac415fbc0321e1 - languageName: node - linkType: hard - -"@jest/globals@npm:^28.1.3": - version: 28.1.3 - resolution: "@jest/globals@npm:28.1.3" - dependencies: - "@jest/environment": ^28.1.3 - "@jest/expect": ^28.1.3 - "@jest/types": ^28.1.3 - checksum: 3504bb23de629d466c6f2b6b75d2e1c1b10caccbbcfb7eaa82d22cc37711c8e364c243929581184846605c023b475ea6c42c2e3ea5994429a988d8d527af32cd - languageName: node - linkType: hard - -"@jest/reporters@npm:^28.1.3": - version: 28.1.3 - resolution: "@jest/reporters@npm:28.1.3" - 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 - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - checksum: a7440887ce837922cbeaa64c3232eb48aae02aa9123f29fc4280ad3e1afe4b35dcba171ba1d5fd219037c396c5152d9c2d102cff1798dd5ae3bd33ac4759ae0a - languageName: node - linkType: hard - -"@jest/schemas@npm:^28.1.3": - version: 28.1.3 - resolution: "@jest/schemas@npm:28.1.3" - dependencies: - "@sinclair/typebox": ^0.24.1 - checksum: 3cf1d4b66c9c4ffda58b246de1ddcba8e6ad085af63dccdf07922511f13b68c0cc480a7bc620cb4f3099a6f134801c747e1df7bfc7a4ef4dceefbdea3e31e1de - languageName: node - linkType: hard - "@jest/schemas@npm:^29.4.3": version: 29.4.3 resolution: "@jest/schemas@npm:29.4.3" @@ -7501,41 +7126,6 @@ __metadata: languageName: node linkType: hard -"@jest/source-map@npm:^28.1.2": - version: 28.1.2 - resolution: "@jest/source-map@npm:28.1.2" - dependencies: - "@jridgewell/trace-mapping": ^0.3.13 - callsites: ^3.0.0 - graceful-fs: ^4.2.9 - checksum: b82a5c2e93d35d86779c61a02ccb967d1b5cd2e9dd67d26d8add44958637cbbb99daeeb8129c7653389cb440dc2a2f5ae4d2183dc453c67669ff98938b775a3a - languageName: node - linkType: hard - -"@jest/test-result@npm:^28.1.3": - version: 28.1.3 - resolution: "@jest/test-result@npm:28.1.3" - dependencies: - "@jest/console": ^28.1.3 - "@jest/types": ^28.1.3 - "@types/istanbul-lib-coverage": ^2.0.0 - collect-v8-coverage: ^1.0.0 - checksum: 957a5dd2fd2e84aabe86698f93c0825e96128ccaa23abf548b159a9b08ac74e4bde7acf4bec48479243dbdb27e4ea1b68c171846d21fb64855c6b55cead9ef27 - languageName: node - linkType: hard - -"@jest/test-sequencer@npm:^28.1.3": - version: 28.1.3 - resolution: "@jest/test-sequencer@npm:28.1.3" - dependencies: - "@jest/test-result": ^28.1.3 - graceful-fs: ^4.2.9 - jest-haste-map: ^28.1.3 - slash: ^3.0.0 - checksum: 13f8905e6d1ec8286694146f7be3cf90eff801bbdea5e5c403e6881444bb390ed15494c7b9948aa94bd7e9c9a851e0d3002ed6e7371d048b478596e5b23df953 - languageName: node - linkType: hard - "@jest/transform@npm:^26.6.2": version: 26.6.2 resolution: "@jest/transform@npm:26.6.2" @@ -7559,29 +7149,6 @@ __metadata: languageName: node linkType: hard -"@jest/transform@npm:^28.1.3": - version: 28.1.3 - resolution: "@jest/transform@npm:28.1.3" - 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 - checksum: dadf618936e0aa84342f07f532801d5bed43cdf95d1417b929e4f8782c872cff1adc84096d5a287a796d0039a2691c06d8450cce5a713a8b52fbb9f872a1e760 - languageName: node - linkType: hard - "@jest/types@npm:^26.6.2": version: 26.6.2 resolution: "@jest/types@npm:26.6.2" @@ -7608,20 +7175,6 @@ __metadata: languageName: node linkType: hard -"@jest/types@npm:^28.1.3": - version: 28.1.3 - resolution: "@jest/types@npm:28.1.3" - 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 - checksum: 1e258d9c063fcf59ebc91e46d5ea5984674ac7ae6cae3e50aa780d22b4405bf2c925f40350bf30013839eb5d4b5e521d956ddf8f3b7c78debef0e75a07f57350 - languageName: node - linkType: hard - "@jimp/bmp@npm:^0.16.1": version: 0.16.1 resolution: "@jimp/bmp@npm:0.16.1" @@ -8165,16 +7718,6 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.13": - version: 0.3.18 - resolution: "@jridgewell/trace-mapping@npm:0.3.18" - dependencies: - "@jridgewell/resolve-uri": 3.1.0 - "@jridgewell/sourcemap-codec": 1.4.14 - checksum: 0572669f855260808c16fe8f78f5f1b4356463b11d3f2c7c0b5580c8ba1cbf4ae53efe9f627595830856e57dbac2325ac17eb0c3dd0ec42102e6f227cc289c02 - languageName: node - linkType: hard - "@jridgewell/trace-mapping@npm:^0.3.14, @jridgewell/trace-mapping@npm:^0.3.17": version: 0.3.17 resolution: "@jridgewell/trace-mapping@npm:0.3.17" @@ -10794,13 +10337,6 @@ __metadata: languageName: node linkType: hard -"@sinclair/typebox@npm:^0.24.1": - version: 0.24.51 - resolution: "@sinclair/typebox@npm:0.24.51" - checksum: fd0d855e748ef767eb19da1a60ed0ab928e91e0f358c1dd198d600762c0015440b15755e96d1176e2a0db7e09c6a64ed487828ee10dd0c3e22f61eb09c478cd0 - languageName: node - linkType: hard - "@sinclair/typebox@npm:^0.25.16": version: 0.25.24 resolution: "@sinclair/typebox@npm:0.25.24" @@ -10815,24 +10351,6 @@ __metadata: languageName: node linkType: hard -"@sinonjs/commons@npm:^1.7.0": - version: 1.8.6 - resolution: "@sinonjs/commons@npm:1.8.6" - dependencies: - type-detect: 4.0.8 - checksum: 7d3f8c1e85f30cd4e83594fc19b7a657f14d49eb8d95a30095631ce15e906c869e0eff96c5b93dffea7490c00418b07f54582ba49c6560feb2a8c34c0b16832d - languageName: node - linkType: hard - -"@sinonjs/fake-timers@npm:^9.1.2": - version: 9.1.2 - resolution: "@sinonjs/fake-timers@npm:9.1.2" - dependencies: - "@sinonjs/commons": ^1.7.0 - checksum: 7d3aef54e17c1073101cb64d953157c19d62a40e261a30923fa1ee337b049c5f29cc47b1f0c477880f42b5659848ba9ab897607ac8ea4acd5c30ddcfac57fca6 - languageName: node - linkType: hard - "@snaplet/copycat@npm:^0.3.0": version: 0.3.0 resolution: "@snaplet/copycat@npm:0.3.0" @@ -12966,47 +12484,6 @@ __metadata: languageName: node linkType: hard -"@types/babel__core@npm:^7.1.14": - version: 7.20.0 - resolution: "@types/babel__core@npm:7.20.0" - dependencies: - "@babel/parser": ^7.20.7 - "@babel/types": ^7.20.7 - "@types/babel__generator": "*" - "@types/babel__template": "*" - "@types/babel__traverse": "*" - checksum: 49b601a0a7637f1f387442c8156bd086cfd10ff4b82b0e1994e73a6396643b5435366fb33d6b604eade8467cca594ef97adcbc412aede90bb112ebe88d0ad6df - languageName: node - linkType: hard - -"@types/babel__generator@npm:*": - version: 7.6.4 - resolution: "@types/babel__generator@npm:7.6.4" - dependencies: - "@babel/types": ^7.0.0 - checksum: 20effbbb5f8a3a0211e95959d06ae70c097fb6191011b73b38fe86deebefad8e09ee014605e0fd3cdaedc73d158be555866810e9166e1f09e4cfd880b874dcb0 - languageName: node - linkType: hard - -"@types/babel__template@npm:*": - version: 7.4.1 - resolution: "@types/babel__template@npm:7.4.1" - dependencies: - "@babel/parser": ^7.1.0 - "@babel/types": ^7.0.0 - checksum: 649fe8b42c2876be1fd28c6ed9b276f78152d5904ec290b6c861d9ef324206e0a5c242e8305c421ac52ecf6358fa7e32ab7a692f55370484825c1df29b1596ee - languageName: node - linkType: hard - -"@types/babel__traverse@npm:*, @types/babel__traverse@npm:^7.0.6": - version: 7.18.5 - resolution: "@types/babel__traverse@npm:7.18.5" - dependencies: - "@babel/types": ^7.3.0 - checksum: b9e7f39eb84626cc8f83ebf75a621d47f04b53cb085a3ea738a9633d57cf65208e503b1830db91aa5e297bc2ba761681ac0b0cbfb7a3d56afcfb2296212668ef - languageName: node - linkType: hard - "@types/bcryptjs@npm:^2.4.2": version: 2.4.2 resolution: "@types/bcryptjs@npm:2.4.2" @@ -13305,15 +12782,6 @@ __metadata: languageName: node linkType: hard -"@types/graceful-fs@npm:^4.1.3": - version: 4.1.6 - resolution: "@types/graceful-fs@npm:4.1.6" - dependencies: - "@types/node": "*" - checksum: c3070ccdc9ca0f40df747bced1c96c71a61992d6f7c767e8fd24bb6a3c2de26e8b84135ede000b7e79db530a23e7e88dcd9db60eee6395d0f4ce1dae91369dd4 - languageName: node - linkType: hard - "@types/gtag.js@npm:^0.0.10": version: 0.0.10 resolution: "@types/gtag.js@npm:0.0.10" @@ -13646,13 +13114,6 @@ __metadata: languageName: node linkType: hard -"@types/prettier@npm:^2.1.5": - version: 2.7.2 - resolution: "@types/prettier@npm:2.7.2" - checksum: b47d76a5252265f8d25dd2fe2a5a61dc43ba0e6a96ffdd00c594cb4fd74c1982c2e346497e3472805d97915407a09423804cc2110a0b8e1b22cffcab246479b7 - languageName: node - linkType: hard - "@types/pretty-hrtime@npm:^1.0.0": version: 1.0.1 resolution: "@types/pretty-hrtime@npm:1.0.1" @@ -13844,13 +13305,6 @@ __metadata: languageName: node linkType: hard -"@types/stack-utils@npm:^2.0.0": - version: 2.0.1 - resolution: "@types/stack-utils@npm:2.0.1" - checksum: 205fdbe3326b7046d7eaf5e494d8084f2659086a266f3f9cf00bccc549c8e36e407f88168ad4383c8b07099957ad669f75f2532ed4bc70be2b037330f7bae019 - languageName: node - linkType: hard - "@types/stripe@npm:^8.0.417": version: 8.0.417 resolution: "@types/stripe@npm:8.0.417" @@ -14001,15 +13455,6 @@ __metadata: languageName: node linkType: hard -"@types/yargs@npm:^17.0.8": - version: 17.0.24 - resolution: "@types/yargs@npm:17.0.24" - dependencies: - "@types/yargs-parser": "*" - checksum: 5f3ac4dc4f6e211c1627340160fbe2fd247ceba002190da6cf9155af1798450501d628c9165a183f30a224fc68fa5e700490d740ff4c73e2cdef95bc4e8ba7bf - languageName: node - linkType: hard - "@types/yoga-layout@npm:1.9.2": version: 1.9.2 resolution: "@types/yoga-layout@npm:1.9.2" @@ -16211,23 +15656,6 @@ __metadata: languageName: node linkType: hard -"babel-jest@npm:^28.1.0, babel-jest@npm:^28.1.3": - version: 28.1.3 - resolution: "babel-jest@npm:28.1.3" - 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 - peerDependencies: - "@babel/core": ^7.8.0 - checksum: 57ccd2296e1839687b5df2fd138c3d00717e0369e385254b012ccd4ee70e75f5d5c8e6cfcdf92d155015b468cfebb847b38e69bb5805d8aaf730e20575127cc6 - languageName: node - linkType: hard - "babel-loader@npm:^8.0.0, babel-loader@npm:^8.2.5": version: 8.2.5 resolution: "babel-loader@npm:8.2.5" @@ -16280,7 +15708,7 @@ __metadata: languageName: node linkType: hard -"babel-plugin-istanbul@npm:^6.0.0, babel-plugin-istanbul@npm:^6.1.1": +"babel-plugin-istanbul@npm:^6.0.0": version: 6.1.1 resolution: "babel-plugin-istanbul@npm:6.1.1" dependencies: @@ -16293,18 +15721,6 @@ __metadata: languageName: node linkType: hard -"babel-plugin-jest-hoist@npm:^28.1.3": - version: 28.1.3 - resolution: "babel-plugin-jest-hoist@npm:28.1.3" - dependencies: - "@babel/template": ^7.3.3 - "@babel/types": ^7.3.3 - "@types/babel__core": ^7.1.14 - "@types/babel__traverse": ^7.0.6 - checksum: 648d89f9d80f6450ce7e50d0c32eb91b7f26269b47c3e37aaf2e0f2f66a980978345bd6b8c9b8c3aa6a8252ad2bc2c9fb50630e9895622c9a0972af5f70ed20e - languageName: node - linkType: hard - "babel-plugin-macros@npm:^2.6.1": version: 2.8.0 resolution: "babel-plugin-macros@npm:2.8.0" @@ -16429,40 +15845,6 @@ __metadata: languageName: node linkType: hard -"babel-preset-current-node-syntax@npm:^1.0.0": - version: 1.0.1 - resolution: "babel-preset-current-node-syntax@npm:1.0.1" - dependencies: - "@babel/plugin-syntax-async-generators": ^7.8.4 - "@babel/plugin-syntax-bigint": ^7.8.3 - "@babel/plugin-syntax-class-properties": ^7.8.3 - "@babel/plugin-syntax-import-meta": ^7.8.3 - "@babel/plugin-syntax-json-strings": ^7.8.3 - "@babel/plugin-syntax-logical-assignment-operators": ^7.8.3 - "@babel/plugin-syntax-nullish-coalescing-operator": ^7.8.3 - "@babel/plugin-syntax-numeric-separator": ^7.8.3 - "@babel/plugin-syntax-object-rest-spread": ^7.8.3 - "@babel/plugin-syntax-optional-catch-binding": ^7.8.3 - "@babel/plugin-syntax-optional-chaining": ^7.8.3 - "@babel/plugin-syntax-top-level-await": ^7.8.3 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: d118c2742498c5492c095bc8541f4076b253e705b5f1ad9a2e7d302d81a84866f0070346662355c8e25fc02caa28dc2da8d69bcd67794a0d60c4d6fab6913cc8 - languageName: node - linkType: hard - -"babel-preset-jest@npm:^28.1.3": - version: 28.1.3 - resolution: "babel-preset-jest@npm:28.1.3" - dependencies: - babel-plugin-jest-hoist: ^28.1.3 - babel-preset-current-node-syntax: ^1.0.0 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 8248a4a5ca4242cc06ad13b10b9183ad2664da8fb0da060c352223dcf286f0ce9c708fa17901dc44ecabec25e6d309e5e5b9830a61dd777c3925f187a345a47d - languageName: node - linkType: hard - "bail@npm:^1.0.0": version: 1.0.5 resolution: "bail@npm:1.0.5" @@ -17722,13 +17104,6 @@ __metadata: languageName: node linkType: hard -"char-regex@npm:^1.0.2": - version: 1.0.2 - resolution: "char-regex@npm:1.0.2" - checksum: b563e4b6039b15213114626621e7a3d12f31008bdce20f9c741d69987f62aeaace7ec30f6018890ad77b2e9b4d95324c9f5acfca58a9441e3b1dcdd1e2525d17 - languageName: node - linkType: hard - "character-entities-html4@npm:^2.0.0": version: 2.1.0 resolution: "character-entities-html4@npm:2.1.0" @@ -17922,13 +17297,6 @@ __metadata: languageName: node linkType: hard -"cjs-module-lexer@npm:^1.0.0": - version: 1.2.2 - resolution: "cjs-module-lexer@npm:1.2.2" - checksum: 977f3f042bd4f08e368c890d91eecfbc4f91da0bc009a3c557bc4dfbf32022ad1141244ac1178d44de70fc9f3dea7add7cd9a658a34b9fae98a55d8f92331ce5 - languageName: node - linkType: hard - "class-is@npm:^1.1.0": version: 1.1.0 resolution: "class-is@npm:1.1.0" @@ -18217,13 +17585,6 @@ __metadata: languageName: node linkType: hard -"co@npm:^4.6.0": - version: 4.6.0 - resolution: "co@npm:4.6.0" - checksum: 5210d9223010eb95b29df06a91116f2cf7c8e0748a9013ed853b53f362ea0e822f1e5bb054fb3cefc645239a4cf966af1f6133a3b43f40d591f3b68ed6cf0510 - languageName: node - linkType: hard - "cobe@npm:^0.4.1": version: 0.4.2 resolution: "cobe@npm:0.4.2" @@ -18268,13 +17629,6 @@ __metadata: languageName: node linkType: hard -"collect-v8-coverage@npm:^1.0.0": - version: 1.0.1 - resolution: "collect-v8-coverage@npm:1.0.1" - checksum: 4efe0a1fccd517b65478a2364b33dadd0a43fc92a56f59aaece9b6186fe5177b2de471253587de7c91516f07c7268c2f6770b6cbcffc0e0ece353b766ec87e55 - languageName: node - linkType: hard - "collection-visit@npm:^1.0.0": version: 1.0.0 resolution: "collection-visit@npm:1.0.0" @@ -19794,13 +19148,6 @@ __metadata: languageName: node linkType: hard -"detect-newline@npm:^3.0.0": - version: 3.1.0 - resolution: "detect-newline@npm:3.1.0" - checksum: ae6cd429c41ad01b164c59ea36f264a2c479598e61cba7c99da24175a7ab80ddf066420f2bec9a1c57a6bead411b4655ff15ad7d281c000a89791f48cbe939e7 - languageName: node - linkType: hard - "detect-node-es@npm:^1.1.0": version: 1.1.0 resolution: "detect-node-es@npm:1.1.0" @@ -19850,13 +19197,6 @@ __metadata: languageName: node linkType: hard -"diff-sequences@npm:^28.1.1": - version: 28.1.1 - resolution: "diff-sequences@npm:28.1.1" - checksum: e2529036505567c7ca5a2dea86b6bcd1ca0e3ae63bf8ebf529b8a99cfa915bbf194b7021dc1c57361a4017a6d95578d4ceb29fabc3232a4f4cb866a2726c7690 - languageName: node - linkType: hard - "diff-sequences@npm:^29.4.3": version: 29.4.3 resolution: "diff-sequences@npm:29.4.3" @@ -20327,13 +19667,6 @@ __metadata: languageName: node linkType: hard -"emittery@npm:^0.10.2": - version: 0.10.2 - resolution: "emittery@npm:0.10.2" - checksum: ee3e21788b043b90885b18ea756ec3105c1cedc50b29709c92b01e239c7e55345d4bb6d3aef4ddbaf528eef448a40b3bb831bad9ee0fc9c25cbf1367ab1ab5ac - languageName: node - linkType: hard - "emoji-regex@npm:^10.2.1": version: 10.2.1 resolution: "emoji-regex@npm:10.2.1" @@ -22302,7 +21635,7 @@ __metadata: languageName: node linkType: hard -"execa@npm:^5.0.0, execa@npm:^5.1.1": +"execa@npm:^5.1.1": version: 5.1.1 resolution: "execa@npm:5.1.1" dependencies: @@ -22333,13 +21666,6 @@ __metadata: languageName: node linkType: hard -"exit@npm:^0.1.2": - version: 0.1.2 - resolution: "exit@npm:0.1.2" - checksum: abc407f07a875c3961e4781dfcb743b58d6c93de9ab263f4f8c9d23bb6da5f9b7764fc773f86b43dd88030444d5ab8abcb611cb680fba8ca075362b77114bba3 - languageName: node - linkType: hard - "expand-brackets@npm:^2.1.4": version: 2.1.4 resolution: "expand-brackets@npm:2.1.4" @@ -22355,19 +21681,6 @@ __metadata: languageName: node linkType: hard -"expect@npm:^28.1.3": - version: 28.1.3 - resolution: "expect@npm:28.1.3" - 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 - checksum: 101e0090de300bcafedb7dbfd19223368a2251ce5fe0105bbb6de5720100b89fb6b64290ebfb42febc048324c76d6a4979cdc4b61eb77747857daf7a5de9b03d - languageName: node - linkType: hard - "express@npm:^4.14.0": version: 4.17.3 resolution: "express@npm:4.17.3" @@ -23402,7 +22715,7 @@ __metadata: languageName: node linkType: hard -"fsevents@npm:2.3.2, fsevents@npm:^2.1.2, fsevents@npm:^2.3.2, fsevents@npm:~2.3.2": +"fsevents@npm:2.3.2, fsevents@npm:^2.1.2, fsevents@npm:~2.3.2": version: 2.3.2 resolution: "fsevents@npm:2.3.2" dependencies: @@ -23423,7 +22736,7 @@ __metadata: languageName: node linkType: hard -"fsevents@patch:fsevents@2.3.2#~builtin, fsevents@patch:fsevents@^2.1.2#~builtin, fsevents@patch:fsevents@^2.3.2#~builtin, fsevents@patch:fsevents@~2.3.2#~builtin": +"fsevents@patch:fsevents@2.3.2#~builtin, fsevents@patch:fsevents@^2.1.2#~builtin, fsevents@patch:fsevents@~2.3.2#~builtin": version: 2.3.2 resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin::version=2.3.2&hash=df0bf1" dependencies: @@ -25168,18 +24481,6 @@ __metadata: languageName: node linkType: hard -"import-local@npm:^3.0.2": - version: 3.1.0 - resolution: "import-local@npm:3.1.0" - dependencies: - pkg-dir: ^4.2.0 - resolve-cwd: ^3.0.0 - bin: - import-local-fixture: fixtures/cli.js - checksum: bfcdb63b5e3c0e245e347f3107564035b128a414c4da1172a20dc67db2504e05ede4ac2eee1252359f78b0bfd7b19ef180aec427c2fce6493ae782d73a04cddd - languageName: node - linkType: hard - "imurmurhash@npm:^0.1.4": version: 0.1.4 resolution: "imurmurhash@npm:0.1.4" @@ -25748,13 +25049,6 @@ __metadata: languageName: node linkType: hard -"is-generator-fn@npm:^2.0.0": - version: 2.1.0 - resolution: "is-generator-fn@npm:2.1.0" - checksum: a6ad5492cf9d1746f73b6744e0c43c0020510b59d56ddcb78a91cbc173f09b5e6beff53d75c9c5a29feb618bfef2bf458e025ecf3a57ad2268e2fb2569f56215 - languageName: node - linkType: hard - "is-generator-function@npm:^1.0.7": version: 1.0.10 resolution: "is-generator-function@npm:1.0.10" @@ -26272,19 +25566,6 @@ __metadata: languageName: node linkType: hard -"istanbul-lib-instrument@npm:^5.1.0": - version: 5.2.1 - resolution: "istanbul-lib-instrument@npm:5.2.1" - 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 - checksum: bf16f1803ba5e51b28bbd49ed955a736488381e09375d830e42ddeb403855b2006f850711d95ad726f2ba3f1ae8e7366de7e51d2b9ac67dc4d80191ef7ddf272 - languageName: node - linkType: hard - "istanbul-lib-report@npm:^3.0.0": version: 3.0.0 resolution: "istanbul-lib-report@npm:3.0.0" @@ -26296,27 +25577,6 @@ __metadata: languageName: node linkType: hard -"istanbul-lib-source-maps@npm:^4.0.0": - version: 4.0.1 - resolution: "istanbul-lib-source-maps@npm:4.0.1" - dependencies: - debug: ^4.1.1 - istanbul-lib-coverage: ^3.0.0 - source-map: ^0.6.1 - checksum: 21ad3df45db4b81852b662b8d4161f6446cd250c1ddc70ef96a585e2e85c26ed7cd9c2a396a71533cfb981d1a645508bc9618cae431e55d01a0628e7dec62ef2 - languageName: node - linkType: hard - -"istanbul-reports@npm:^3.1.3": - version: 3.1.5 - resolution: "istanbul-reports@npm:3.1.5" - dependencies: - html-escaper: ^2.0.0 - istanbul-lib-report: ^3.0.0 - checksum: 7867228f83ed39477b188ea07e7ccb9b4f5320b6f73d1db93a0981b7414fa4ef72d3f80c4692c442f90fc250d9406e71d8d7ab65bb615cb334e6292b73192b89 - languageName: node - linkType: hard - "istanbul-reports@npm:^3.1.4": version: 3.1.4 resolution: "istanbul-reports@npm:3.1.4" @@ -26384,120 +25644,6 @@ __metadata: languageName: node linkType: hard -"jest-changed-files@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-changed-files@npm:28.1.3" - dependencies: - execa: ^5.0.0 - p-limit: ^3.1.0 - checksum: c78af14a68b9b19101623ae7fde15a2488f9b3dbe8cca12a05c4a223bc9bfd3bf41ee06830f20fb560c52434435d6153c9cc6cf450b1f7b03e5e7f96a953a6a6 - languageName: node - linkType: hard - -"jest-circus@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-circus@npm:28.1.3" - 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 - checksum: b635e60a9c92adaefc3f24def8eba691e7c2fdcf6c9fa640cddf2eb8c8b26ee62eab73ebb88798fd7c52a74c1495a984e39b748429b610426f02e9d3d56e09b2 - languageName: node - linkType: hard - -"jest-cli@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-cli@npm:28.1.3" - 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 - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - bin: - jest: bin/jest.js - checksum: fb424576bf38346318daddee3fcc597cd78cb8dda1759d09c529d8ba1a748f2765c17b00671072a838826e59465a810ff8a232bc6ba2395c131bf3504425a363 - languageName: node - linkType: hard - -"jest-config@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-config@npm:28.1.3" - 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 - peerDependencies: - "@types/node": "*" - ts-node: ">=9.0.0" - peerDependenciesMeta: - "@types/node": - optional: true - ts-node: - optional: true - checksum: ddabffd3a3a8cb6c2f58f06cdf3535157dbf8c70bcde3e5c3de7bee6a8d617840ffc8cffb0083e38c6814f2a08c225ca19f58898efaf4f351af94679f22ce6bc - languageName: node - linkType: hard - -"jest-diff@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-diff@npm:28.1.3" - dependencies: - chalk: ^4.0.0 - diff-sequences: ^28.1.1 - jest-get-type: ^28.0.2 - pretty-format: ^28.1.3 - checksum: fa8583e0ccbe775714ce850b009be1b0f6b17a4b6759f33ff47adef27942ebc610dbbcc8a5f7cfb7f12b3b3b05afc9fb41d5f766674616025032ff1e4f9866e0 - languageName: node - linkType: hard - "jest-diff@npm:^29.5.0": version: 29.5.0 resolution: "jest-diff@npm:29.5.0" @@ -26510,49 +25656,6 @@ __metadata: languageName: node linkType: hard -"jest-docblock@npm:^28.1.1": - version: 28.1.1 - resolution: "jest-docblock@npm:28.1.1" - dependencies: - detect-newline: ^3.0.0 - checksum: 22fca68d988ecb2933bc65f448facdca85fc71b4bd0a188ea09a5ae1b0cc3a049a2a6ec7e7eaa2542c1d5cb5e5145e420a3df4fa280f5070f486c44da1d36151 - languageName: node - linkType: hard - -"jest-each@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-each@npm:28.1.3" - 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 - checksum: 5c5b8ccb1484e58b027bea682cfa020a45e5bf5379cc7c23bdec972576c1dc3c3bf03df2b78416cefc1a58859dd33b7cf5fff54c370bc3c0f14a3e509eb87282 - languageName: node - linkType: hard - -"jest-environment-node@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-environment-node@npm:28.1.3" - 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 - checksum: 1048fe306a6a8b0880a4c66278ebb57479f29c12cff89aab3aa79ab77a8859cf17ab8aa9919fd21c329a7db90e35581b43664e694ad453d5b04e00f3c6420469 - languageName: node - linkType: hard - -"jest-get-type@npm:^28.0.2": - version: 28.0.2 - resolution: "jest-get-type@npm:28.0.2" - checksum: 5281d7c89bc8156605f6d15784f45074f4548501195c26e9b188742768f72d40948252d13230ea905b5349038865a1a8eeff0e614cc530ff289dfc41fe843abd - languageName: node - linkType: hard - "jest-get-type@npm:^29.4.3": version: 29.4.3 resolution: "jest-get-type@npm:29.4.3" @@ -26585,68 +25688,6 @@ __metadata: languageName: node linkType: hard -"jest-haste-map@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-haste-map@npm:28.1.3" - dependencies: - "@jest/types": ^28.1.3 - "@types/graceful-fs": ^4.1.3 - "@types/node": "*" - anymatch: ^3.0.3 - fb-watchman: ^2.0.0 - fsevents: ^2.3.2 - 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 - dependenciesMeta: - fsevents: - optional: true - checksum: d05fdc108645fc2b39fcd4001952cc7a8cb550e93494e98c1e9ab1fc542686f6ac67177c132e564cf94fe8f81503f3f8db8b825b9b713dc8c5748aec63ba4688 - languageName: node - linkType: hard - -"jest-leak-detector@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-leak-detector@npm:28.1.3" - dependencies: - jest-get-type: ^28.0.2 - pretty-format: ^28.1.3 - checksum: 2e976a4880cf9af11f53a19f6a3820e0f90b635a900737a5427fc42e337d5628ba446dcd7c020ecea3806cf92bc0bbf6982ed62a9cd84e5a13d8751aa30fbbb7 - languageName: node - linkType: hard - -"jest-matcher-utils@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-matcher-utils@npm:28.1.3" - dependencies: - chalk: ^4.0.0 - jest-diff: ^28.1.3 - jest-get-type: ^28.0.2 - pretty-format: ^28.1.3 - checksum: 6b34f0cf66f6781e92e3bec97bf27796bd2ba31121e5c5997218d9adba6deea38a30df5203937d6785b68023ed95cbad73663cc9aad6fb0cb59aeb5813a58daf - languageName: node - linkType: hard - -"jest-message-util@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-message-util@npm:28.1.3" - 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 - checksum: 1f266854166dcc6900d75a88b54a25225a2f3710d463063ff1c99021569045c35c7d58557b25447a17eb3a65ce763b2f9b25550248b468a9d4657db365f39e96 - languageName: node - linkType: hard - "jest-mock@npm:^27.0.6": version: 27.5.1 resolution: "jest-mock@npm:27.5.1" @@ -26657,28 +25698,6 @@ __metadata: languageName: node linkType: hard -"jest-mock@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-mock@npm:28.1.3" - dependencies: - "@jest/types": ^28.1.3 - "@types/node": "*" - checksum: a573bf8e5f12f4c29c661266c31b5c6b69a28d3195b83049983bce025b2b1a0152351567e89e63b102ef817034c2a3aa97eda4e776f3bae2aee54c5765573aa7 - languageName: node - linkType: hard - -"jest-pnp-resolver@npm:^1.2.2": - version: 1.2.3 - resolution: "jest-pnp-resolver@npm:1.2.3" - peerDependencies: - jest-resolve: "*" - peerDependenciesMeta: - jest-resolve: - optional: true - checksum: db1a8ab2cb97ca19c01b1cfa9a9c8c69a143fde833c14df1fab0766f411b1148ff0df878adea09007ac6a2085ec116ba9a996a6ad104b1e58c20adbf88eed9b2 - languageName: node - linkType: hard - "jest-regex-util@npm:^26.0.0": version: 26.0.0 resolution: "jest-regex-util@npm:26.0.0" @@ -26686,99 +25705,6 @@ __metadata: languageName: node linkType: hard -"jest-regex-util@npm:^28.0.2": - version: 28.0.2 - resolution: "jest-regex-util@npm:28.0.2" - checksum: 0ea8c5c82ec88bc85e273c0ec82e0c0f35f7a1e2d055070e50f0cc2a2177f848eec55f73e37ae0d045c3db5014c42b2f90ac62c1ab3fdb354d2abd66a9e08add - languageName: node - linkType: hard - -"jest-resolve-dependencies@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-resolve-dependencies@npm:28.1.3" - dependencies: - jest-regex-util: ^28.0.2 - jest-snapshot: ^28.1.3 - checksum: 4eea9ec33aefc1c71dc5956391efbcc7be76bda986b366ab3931d99c5f7ed01c9ebd7520e405ea2c76e1bb2c7ce504be6eca2b9831df16564d1e625500f3bfe7 - languageName: node - linkType: hard - -"jest-resolve@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-resolve@npm:28.1.3" - 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 - checksum: df61a490c93f4f4cf52135e43d6a4fcacb07b0b7d4acc6319e9289529c1d14f2d8e1638e095dbf96f156834802755e38db68caca69dba21a3261ee711d4426b6 - languageName: node - linkType: hard - -"jest-runner@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-runner@npm:28.1.3" - 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 - checksum: 32405cd970fa6b11e039192dae699fd1bcc6f61f67d50605af81d193f24dd4373b25f5fcc1c571a028ec1b02174e8a4b6d0d608772063fb06f08a5105693533b - languageName: node - linkType: hard - -"jest-runtime@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-runtime@npm:28.1.3" - 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 - checksum: b17c40af858e74dafa4f515ef3711c1e9ef3d4ad7d74534ee0745422534bc04fd166d4eceb62a3aa7dc951505d6f6d2a81d16e90bebb032be409ec0500974a36 - languageName: node - linkType: hard - "jest-serializer@npm:^26.6.2": version: 26.6.2 resolution: "jest-serializer@npm:26.6.2" @@ -26789,37 +25715,6 @@ __metadata: languageName: node linkType: hard -"jest-snapshot@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-snapshot@npm:28.1.3" - 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 - checksum: 2a46a5493f1fb50b0a236a21f25045e7f46a244f9f3ae37ef4fbcd40249d0d68bb20c950ce77439e4e2cac985b05c3061c90b34739bf6069913a1199c8c716e1 - languageName: node - linkType: hard - "jest-util@npm:^26.6.2": version: 26.6.2 resolution: "jest-util@npm:26.6.2" @@ -26834,50 +25729,6 @@ __metadata: languageName: node linkType: hard -"jest-util@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-util@npm:28.1.3" - 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 - checksum: fd6459742c941f070223f25e38a2ac0719aad92561591e9fb2a50d602a5d19d754750b79b4074327a42b00055662b95da3b006542ceb8b54309da44d4a62e721 - languageName: node - linkType: hard - -"jest-validate@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-validate@npm:28.1.3" - 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 - checksum: 95e0513b3803c3372a145cda86edbdb33d9dfeaa18818176f2d581e821548ceac9a179f065b6d4671a941de211354efd67f1fff8789a4fb89962565c85f646db - languageName: node - linkType: hard - -"jest-watcher@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-watcher@npm:28.1.3" - 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 - checksum: 8f6d674a4865e7df251f71544f1b51f06fd36b5a3a61f2ac81aeb81fa2a196be354fba51d0f97911c88f67cd254583b3a22ee124bf2c5b6ee2fadec27356c207 - languageName: node - linkType: hard - "jest-worker@npm:^26.5.0, jest-worker@npm:^26.6.2": version: 26.6.2 resolution: "jest-worker@npm:26.6.2" @@ -26900,36 +25751,6 @@ __metadata: languageName: node linkType: hard -"jest-worker@npm:^28.1.3": - version: 28.1.3 - resolution: "jest-worker@npm:28.1.3" - dependencies: - "@types/node": "*" - merge-stream: ^2.0.0 - supports-color: ^8.0.0 - checksum: e921c9a1b8f0909da9ea07dbf3592f95b653aef3a8bb0cbcd20fc7f9a795a1304adecac31eecb308992c167e8d7e75c522061fec38a5928ace0f9571c90169ca - languageName: node - linkType: hard - -"jest@npm:^28.1.0": - version: 28.1.3 - resolution: "jest@npm:28.1.3" - dependencies: - "@jest/core": ^28.1.3 - "@jest/types": ^28.1.3 - import-local: ^3.0.2 - jest-cli: ^28.1.3 - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true - bin: - jest: bin/jest.js - checksum: b9dcb542eb7c16261c281cdc2bf37155dbb3f1205bae0b567f05051db362c85ddd4b765f126591efb88f6d298eb10336d0aa6c7d5373b4d53f918137a9a70182 - languageName: node - linkType: hard - "jimp@npm:^0.16.1": version: 0.16.1 resolution: "jimp@npm:0.16.1" @@ -27756,13 +26577,6 @@ __metadata: languageName: node linkType: hard -"leven@npm:^3.1.0": - version: 3.1.0 - resolution: "leven@npm:3.1.0" - checksum: 638401d534585261b6003db9d99afd244dfe82d75ddb6db5c0df412842d5ab30b2ef18de471aaec70fe69a46f17b4ae3c7f01d8a4e6580ef7adb9f4273ad1e55 - languageName: node - linkType: hard - "levn@npm:^0.4.1": version: 0.4.1 resolution: "levn@npm:0.4.1" @@ -31251,7 +30065,7 @@ __metadata: languageName: node linkType: hard -"p-limit@npm:^3.0.2, p-limit@npm:^3.1.0": +"p-limit@npm:^3.0.2": version: 3.1.0 resolution: "p-limit@npm:3.1.0" dependencies: @@ -31506,7 +30320,7 @@ __metadata: languageName: node linkType: hard -"parse-json@npm:^5.0.0, parse-json@npm:^5.2.0": +"parse-json@npm:^5.0.0": version: 5.2.0 resolution: "parse-json@npm:5.2.0" dependencies: @@ -31863,7 +30677,7 @@ __metadata: languageName: node linkType: hard -"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.2, picomatch@npm:^2.2.3, picomatch@npm:^2.3.0, picomatch@npm:^2.3.1": +"picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.2, picomatch@npm:^2.3.0, picomatch@npm:^2.3.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" checksum: 050c865ce81119c4822c45d3c84f1ced46f93a0126febae20737bd05ca20589c564d6e9226977df859ed5e03dc73f02584a2b0faad36e896936238238b0446cf @@ -31948,7 +30762,7 @@ __metadata: languageName: node linkType: hard -"pirates@npm:^4.0.1, pirates@npm:^4.0.4, pirates@npm:^4.0.5": +"pirates@npm:^4.0.1, pirates@npm:^4.0.5": version: 4.0.5 resolution: "pirates@npm:4.0.5" checksum: c9994e61b85260bec6c4fc0307016340d9b0c4f4b6550a957afaaff0c9b1ad58fbbea5cfcf083860a25cb27a375442e2b0edf52e2e1e40e69934e08dcc52d227 @@ -32579,18 +31393,6 @@ __metadata: languageName: node linkType: hard -"pretty-format@npm:^28.1.3": - version: 28.1.3 - resolution: "pretty-format@npm:28.1.3" - dependencies: - "@jest/schemas": ^28.1.3 - ansi-regex: ^5.0.1 - ansi-styles: ^5.0.0 - react-is: ^18.0.0 - checksum: e69f857358a3e03d271252d7524bec758c35e44680287f36c1cb905187fbc82da9981a6eb07edfd8a03bc3cbeebfa6f5234c13a3d5b59f2bbdf9b4c4053e0a7f - languageName: node - linkType: hard - "pretty-format@npm:^29.5.0": version: 29.5.0 resolution: "pretty-format@npm:29.5.0" @@ -32764,7 +31566,7 @@ __metadata: languageName: node linkType: hard -"prompts@npm:^2.0.1, prompts@npm:^2.4.0": +"prompts@npm:^2.4.0": version: 2.4.2 resolution: "prompts@npm:2.4.2" dependencies: @@ -34790,15 +33592,6 @@ __metadata: languageName: node linkType: hard -"resolve-cwd@npm:^3.0.0": - version: 3.0.0 - resolution: "resolve-cwd@npm:3.0.0" - dependencies: - resolve-from: ^5.0.0 - checksum: 546e0816012d65778e580ad62b29e975a642989108d9a3c5beabfb2304192fa3c9f9146fbdfe213563c6ff51975ae41bac1d3c6e047dd9572c94863a057b4d81 - languageName: node - linkType: hard - "resolve-from@npm:^4.0.0": version: 4.0.0 resolution: "resolve-from@npm:4.0.0" @@ -34833,13 +33626,6 @@ __metadata: languageName: node linkType: hard -"resolve.exports@npm:^1.1.0": - version: 1.1.1 - resolution: "resolve.exports@npm:1.1.1" - checksum: 485aa10082eb388a569d696e17ad7b16f4186efc97dd34eadd029d95b811f21ffee13b1b733198bb4584dbb3cb296aa6f141835221fb7613b9606b84f1386655 - languageName: node - linkType: hard - "resolve@npm:^1.1.7, resolve@npm:^1.14.2, resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.22.1, resolve@npm:^1.3.2": version: 1.22.1 resolution: "resolve@npm:1.22.1" @@ -35001,7 +33787,7 @@ __metadata: languageName: node linkType: hard -"rimraf@npm:^3.0.0, rimraf@npm:^3.0.2": +"rimraf@npm:^3.0.2": version: 3.0.2 resolution: "rimraf@npm:3.0.2" dependencies: @@ -36111,16 +34897,6 @@ __metadata: languageName: node linkType: hard -"source-map-support@npm:0.5.13": - version: 0.5.13 - resolution: "source-map-support@npm:0.5.13" - dependencies: - buffer-from: ^1.0.0 - source-map: ^0.6.0 - checksum: 933550047b6c1a2328599a21d8b7666507427c0f5ef5eaadd56b5da0fd9505e239053c66fe181bf1df469a3b7af9d775778eee283cbb7ae16b902ddc09e93a97 - languageName: node - linkType: hard - "source-map-support@npm:^0.5.16, source-map-support@npm:^0.5.21, source-map-support@npm:~0.5.12, source-map-support@npm:~0.5.20": version: 0.5.21 resolution: "source-map-support@npm:0.5.21" @@ -36371,15 +35147,6 @@ __metadata: languageName: node linkType: hard -"stack-utils@npm:^2.0.3": - version: 2.0.6 - resolution: "stack-utils@npm:2.0.6" - dependencies: - escape-string-regexp: ^2.0.0 - checksum: 052bf4d25bbf5f78e06c1d5e67de2e088b06871fa04107ca8d3f0e9d9263326e2942c8bedee3545795fc77d787d443a538345eef74db2f8e35db3558c6f91ff7 - languageName: node - linkType: hard - "stackback@npm:0.0.2": version: 0.0.2 resolution: "stackback@npm:0.0.2" @@ -36658,16 +35425,6 @@ __metadata: languageName: node linkType: hard -"string-length@npm:^4.0.1": - version: 4.0.2 - resolution: "string-length@npm:4.0.2" - dependencies: - char-regex: ^1.0.2 - strip-ansi: ^6.0.0 - checksum: ce85533ef5113fcb7e522bcf9e62cb33871aa99b3729cec5595f4447f660b0cefd542ca6df4150c97a677d58b0cb727a3fe09ac1de94071d05526c73579bf505 - languageName: node - linkType: hard - "string-range@npm:~1.2, string-range@npm:~1.2.1": version: 1.2.2 resolution: "string-range@npm:1.2.2" @@ -36916,13 +35673,6 @@ __metadata: languageName: node linkType: hard -"strip-bom@npm:^4.0.0": - version: 4.0.0 - resolution: "strip-bom@npm:4.0.0" - checksum: 9dbcfbaf503c57c06af15fe2c8176fb1bf3af5ff65003851a102749f875a6dbe0ab3b30115eccf6e805e9d756830d3e40ec508b62b3f1ddf3761a20ebe29d3f3 - languageName: node - linkType: hard - "strip-eof@npm:^1.0.0": version: 1.0.0 resolution: "strip-eof@npm:1.0.0" @@ -37165,16 +35915,6 @@ __metadata: languageName: node linkType: hard -"supports-hyperlinks@npm:^2.0.0": - version: 2.3.0 - resolution: "supports-hyperlinks@npm:2.3.0" - dependencies: - has-flag: ^4.0.0 - supports-color: ^7.0.0 - checksum: 9ee0de3c8ce919d453511b2b1588a8205bd429d98af94a01df87411391010fe22ca463f268c84b2ce2abad019dfff8452aa02806eeb5c905a8d7ad5c4f4c52b8 - languageName: node - linkType: hard - "supports-preserve-symlinks-flag@npm:^1.0.0": version: 1.0.0 resolution: "supports-preserve-symlinks-flag@npm:1.0.0" @@ -37604,16 +36344,6 @@ __metadata: languageName: node linkType: hard -"terminal-link@npm:^2.0.0": - version: 2.1.1 - resolution: "terminal-link@npm:2.1.1" - dependencies: - ansi-escapes: ^4.2.1 - supports-hyperlinks: ^2.0.0 - checksum: ce3d2cd3a438c4a9453947aa664581519173ea40e77e2534d08c088ee6dda449eabdbe0a76d2a516b8b73c33262fedd10d5270ccf7576ae316e3db170ce6562f - languageName: node - linkType: hard - "terser-webpack-plugin@npm:^1.4.3": version: 1.4.5 resolution: "terser-webpack-plugin@npm:1.4.5" @@ -38533,7 +37263,7 @@ __metadata: languageName: node linkType: hard -"type-detect@npm:4.0.8, type-detect@npm:^4.0.0, type-detect@npm:^4.0.5": +"type-detect@npm:^4.0.0, type-detect@npm:^4.0.5": version: 4.0.8 resolution: "type-detect@npm:4.0.8" checksum: 62b5628bff67c0eb0b66afa371bd73e230399a8d2ad30d852716efcc4656a7516904570cd8631a49a3ce57c10225adf5d0cbdcb47f6b0255fe6557c453925a15 @@ -39624,17 +38354,6 @@ __metadata: languageName: node linkType: hard -"v8-to-istanbul@npm:^9.0.1": - version: 9.1.0 - resolution: "v8-to-istanbul@npm:9.1.0" - dependencies: - "@jridgewell/trace-mapping": ^0.3.12 - "@types/istanbul-lib-coverage": ^2.0.1 - convert-source-map: ^1.6.0 - checksum: 2069d59ee46cf8d83b4adfd8a5c1a90834caffa9f675e4360f1157ffc8578ef0f763c8f32d128334424159bb6b01f3876acd39cd13297b2769405a9da241f8d1 - languageName: node - linkType: hard - "validate-npm-package-license@npm:^3.0.1": version: 3.0.4 resolution: "validate-npm-package-license@npm:3.0.4" @@ -40047,7 +38766,7 @@ __metadata: languageName: node linkType: hard -"walker@npm:^1.0.7, walker@npm:^1.0.8, walker@npm:~1.0.5": +"walker@npm:^1.0.7, walker@npm:~1.0.5": version: 1.0.8 resolution: "walker@npm:1.0.8" dependencies: @@ -40940,16 +39659,6 @@ __metadata: languageName: node linkType: hard -"write-file-atomic@npm:^4.0.1": - version: 4.0.2 - resolution: "write-file-atomic@npm:4.0.2" - dependencies: - imurmurhash: ^0.1.4 - signal-exit: ^3.0.7 - checksum: 5da60bd4eeeb935eec97ead3df6e28e5917a6bd317478e4a85a5285e8480b8ed96032bbcc6ecd07b236142a24f3ca871c924ec4a6575e623ec1b11bf8c1c253c - languageName: node - linkType: hard - "ws@npm:7.4.6": version: 7.4.6 resolution: "ws@npm:7.4.6" From e760122db6523fb9c8582f210c514d8a7a03d560 Mon Sep 17 00:00:00 2001 From: Yatendra Date: Thu, 25 May 2023 23:20:30 +0530 Subject: [PATCH 650/658] change /ee to /commercial (#8948) Co-authored-by: ygpta <25252636+yatendraguptaofficial@gmail.com> Co-authored-by: Peer Richelsen --- packages/app-store/stripepayment/LICENSE | 4 ++-- packages/embeds/embed-core/LICENSE | 4 ++-- packages/embeds/embed-react/LICENSE | 4 ++-- packages/embeds/embed-snippet/LICENSE | 4 ++-- packages/features/ee/package.json | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/app-store/stripepayment/LICENSE b/packages/app-store/stripepayment/LICENSE index 60f0a2a1d0..86aae54b29 100644 --- a/packages/app-store/stripepayment/LICENSE +++ b/packages/app-store/stripepayment/LICENSE @@ -1,4 +1,4 @@ -The Cal.com Enterprise Edition (EE) license (the “EE License”) +The Cal.com Commercial License (EE) license (the “EE License”) Copyright (c) 2020-present Cal.com, Inc With regard to the Cal.com Software: @@ -8,7 +8,7 @@ used in production, if you (and any entity that you represent) have agreed to, and are in compliance with, the Cal.com Subscription Terms available at https://cal.com/terms (the “EE Terms”), or other agreements governing the use of the Software, as mutually agreed by you and Cal.com, Inc ("Cal.com"), -and otherwise have a valid Cal.com Enterprise Edition subscription ("EE Subscription") +and otherwise have a valid Cal.com Commercial License subscription ("EE Subscription") for the correct number of hosts as defined in the EE Terms ("Hosts"). Subject to the foregoing sentence, you are free to modify this Software and publish patches to the Software. You agree that Cal.com and/or its licensors (as applicable) retain all right, title and interest in diff --git a/packages/embeds/embed-core/LICENSE b/packages/embeds/embed-core/LICENSE index 1f8841cbc2..cedfba0c36 100644 --- a/packages/embeds/embed-core/LICENSE +++ b/packages/embeds/embed-core/LICENSE @@ -1,4 +1,4 @@ -The Cal.com Enterprise Edition (EE) license (the “EE License”) +The Cal.com Commercial License (EE) license (the “EE License”) Copyright (c) 2020-present Cal.com, Inc With regard to the Cal.com Software: @@ -8,7 +8,7 @@ used in production, if you (and any entity that you represent) have agreed to, and are in compliance with, the Cal.com Subscription Terms available at https://cal.com/terms (the “EE Terms”), or other agreements governing the use of the Software, as mutually agreed by you and Cal.com, Inc ("Cal.com"), -and otherwise have a valid Cal.com Enterprise Edition subscription ("EE Subscription") +and otherwise have a valid Cal.com Commercial License subscription ("EE Subscription") for the correct number of hosts as defined in the EE Terms ("Hosts"). Subject to the foregoing sentence, you are free to modify this Software and publish patches to the Software. You agree that Cal.com and/or its licensors (as applicable) retain all right, title and interest in diff --git a/packages/embeds/embed-react/LICENSE b/packages/embeds/embed-react/LICENSE index 1f8841cbc2..cedfba0c36 100644 --- a/packages/embeds/embed-react/LICENSE +++ b/packages/embeds/embed-react/LICENSE @@ -1,4 +1,4 @@ -The Cal.com Enterprise Edition (EE) license (the “EE License”) +The Cal.com Commercial License (EE) license (the “EE License”) Copyright (c) 2020-present Cal.com, Inc With regard to the Cal.com Software: @@ -8,7 +8,7 @@ used in production, if you (and any entity that you represent) have agreed to, and are in compliance with, the Cal.com Subscription Terms available at https://cal.com/terms (the “EE Terms”), or other agreements governing the use of the Software, as mutually agreed by you and Cal.com, Inc ("Cal.com"), -and otherwise have a valid Cal.com Enterprise Edition subscription ("EE Subscription") +and otherwise have a valid Cal.com Commercial License subscription ("EE Subscription") for the correct number of hosts as defined in the EE Terms ("Hosts"). Subject to the foregoing sentence, you are free to modify this Software and publish patches to the Software. You agree that Cal.com and/or its licensors (as applicable) retain all right, title and interest in diff --git a/packages/embeds/embed-snippet/LICENSE b/packages/embeds/embed-snippet/LICENSE index 1f8841cbc2..cedfba0c36 100644 --- a/packages/embeds/embed-snippet/LICENSE +++ b/packages/embeds/embed-snippet/LICENSE @@ -1,4 +1,4 @@ -The Cal.com Enterprise Edition (EE) license (the “EE License”) +The Cal.com Commercial License (EE) license (the “EE License”) Copyright (c) 2020-present Cal.com, Inc With regard to the Cal.com Software: @@ -8,7 +8,7 @@ used in production, if you (and any entity that you represent) have agreed to, and are in compliance with, the Cal.com Subscription Terms available at https://cal.com/terms (the “EE Terms”), or other agreements governing the use of the Software, as mutually agreed by you and Cal.com, Inc ("Cal.com"), -and otherwise have a valid Cal.com Enterprise Edition subscription ("EE Subscription") +and otherwise have a valid Cal.com Commercial License subscription ("EE Subscription") for the correct number of hosts as defined in the EE Terms ("Hosts"). Subject to the foregoing sentence, you are free to modify this Software and publish patches to the Software. You agree that Cal.com and/or its licensors (as applicable) retain all right, title and interest in diff --git a/packages/features/ee/package.json b/packages/features/ee/package.json index 18043f1a38..7244d62522 100644 --- a/packages/features/ee/package.json +++ b/packages/features/ee/package.json @@ -1,6 +1,6 @@ { "name": "@calcom/ee", - "description": "Cal.com Enterprise Edition features", + "description": "Cal.com Commercial License features", "version": "0.0.0", "private": true, "license": "See license in LICENSE", From 6f338b6fc7ea0d32a4ed13ca5189fe0ac8fdead7 Mon Sep 17 00:00:00 2001 From: Hariom Balhara Date: Fri, 26 May 2023 15:32:02 +0530 Subject: [PATCH 651/658] fix: Broken 2 Factor Authentication (#9139) * Fix 2 Factor Auth * Update apps/web/pages/auth/login.tsx --- apps/web/pages/auth/login.tsx | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/apps/web/pages/auth/login.tsx b/apps/web/pages/auth/login.tsx index 1e6ea5a74f..575b4ce213 100644 --- a/apps/web/pages/auth/login.tsx +++ b/apps/web/pages/auth/login.tsx @@ -51,15 +51,17 @@ export default function Login({ }: inferSSRProps & WithNonceProps) { const { t } = useLocale(); const router = useRouter(); - const formSchema = z.object({ - email: z - .string() - .min(1, `${t("error_required_field")}`) - .email(`${t("enter_valid_email")}`), - password: z.string().min(1, `${t("error_required_field")}`), - }); + const formSchema = z + .object({ + email: z + .string() + .min(1, `${t("error_required_field")}`) + .email(`${t("enter_valid_email")}`), + password: z.string().min(1, `${t("error_required_field")}`), + }) + // Passthrough other fields like totpCode + .passthrough(); const methods = useForm({ resolver: zodResolver(formSchema) }); - const { register, formState } = methods; const [twoFactorRequired, setTwoFactorRequired] = useState(!!totpEmail || false); const [errorMessage, setErrorMessage] = useState(null); From 77904e0c55a14a3b5f36ac7023b6330a88fb86b7 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Fri, 26 May 2023 10:38:07 +0000 Subject: [PATCH 652/658] New Crowdin translations by Github Action --- apps/web/public/static/locales/ro/common.json | 36 +++++++++---------- apps/web/public/static/locales/tr/common.json | 18 +++++----- apps/web/public/static/locales/uk/common.json | 32 ++++++++--------- 3 files changed, 43 insertions(+), 43 deletions(-) diff --git a/apps/web/public/static/locales/ro/common.json b/apps/web/public/static/locales/ro/common.json index 91fcf55e5f..bca838c91c 100644 --- a/apps/web/public/static/locales/ro/common.json +++ b/apps/web/public/static/locales/ro/common.json @@ -594,13 +594,13 @@ "managed_event_description": "Creați și distribuiți membrilor echipei tipuri de evenimente în masă", "managed": "Configurat", "managed_event_url_clarification": "Câmpul „username” va fi completat cu numele de utilizator ale membrilor desemnați", - "assign_to": "Atribuiți către", + "assign_to": "Alocați la", "add_members": "Adăugare membri...", "count_members_one": "{{count}} membru", "count_members_other": "{{count}} (de) membri", - "no_assigned_members": "Niciun membru desemnat", - "assigned_to": "Atribuit către", - "start_assigning_members_above": "Începeți să desemnați membri mai sus", + "no_assigned_members": "Niciun membru alocat", + "assigned_to": "Alocat la", + "start_assigning_members_above": "Începeți să alocați membri mai sus", "locked_fields_admin_description": "Membrii nu vor putea modifica acest câmp", "locked_fields_member_description": "Această opțiune a fost blocată de administratorul echipei", "url": "URL", @@ -757,7 +757,7 @@ "delete_event_type": "Ștergeți tipul de eveniment?", "delete_managed_event_type": "Ștergeți tipul de eveniment gestionat?", "delete_event_type_description": "Nicio persoană căreia i-ați transmis acest link nu va mai putea efectua rezervări prin intermediul lui.", - "delete_managed_event_type_description": "
  • Membrii alocați acestui tip de eveniment își vor vedea și tipurile de evenimente șterse.
  • Nicio persoană căreia i-au transmis linkul nu va mai putea efectua rezervări prin intermediul lui.
", + "delete_managed_event_type_description": "
  • Pentru membrii alocați la acest tip de eveniment vor fi șterse și tipurile de evenimente.
  • Nicio persoană căreia i-au transmis linkul nu va mai putea efectua rezervări prin intermediul lui.
", "confirm_delete_event_type": "Da, șterge", "delete_account": "Ștergeți contul", "confirm_delete_account": "Da, ștergeți contul", @@ -1326,7 +1326,7 @@ "exchange_version_2013_SP1": "2013 SP1", "exchange_version_2015": "2015", "exchange_version_2016": "2016", - "routing_forms_description": "Puteți vedea aici toate formularele și parcursurile pe care le-ați creat.", + "routing_forms_description": "Creați formulare pentru a direcționa participanții către destinațiile corecte", "routing_forms_send_email_owner": "Trimiteți un e-mail către proprietar", "routing_forms_send_email_owner_description": "Trimite un e-mail către proprietar atunci când este trimis formularul", "add_new_form": "Adăugați un formular nou", @@ -1395,7 +1395,7 @@ "billing_help_title": "Aveți nevoie de altceva?", "billing_help_description": "Dacă aveți nevoie de ajutor suplimentar pentru facturare, echipa noastră de asistență este aici pentru a vă ajuta.", "billing_help_cta": "Contactați serviciul de asistență", - "ignore_special_characters_booking_questions": "Ignorați caracterele speciale din identificatorul de întrebări despre rezervare. Utilizați doar litere și cifre", + "ignore_special_characters_booking_questions": "Ignorați caracterele speciale în identificatorul întrebării despre rezervare. Utilizați doar litere și cifre", "retry": "Reîncercați", "fetching_calendars_error": "A survenit o problemă legată de recuperarea calendarelor dvs. <1>Încercați din nou sau contactați serviciul de asistență pentru clienți.", "calendar_connection_fail": "Conexiune calendar nereușită", @@ -1486,8 +1486,8 @@ "disabled_app_affects_event_type": "Un administrator a dezactivat {{appName}} care afectează tipul tău de eveniment {{eventType}}", "event_replaced_notice": "Un administrator a înlocuit unul dintre tipurile dvs. de evenimente", "email_subject_slug_replacement": "Un administrator al echipei v-a înlocuit evenimentul /{{slug}}", - "email_body_slug_replacement_notice": "Un administrator din echipa {{teamName}} v-a înlocuit tipul de eveniment /{{slug}} cu un tip de eveniment gestionat pe care îl controlează.", - "email_body_slug_replacement_info": "Linkul dvs. va funcționa în continuare, dar este posibil ca unele setări să se fi schimbat. Îl puteți examina în tipurile de evenimente.", + "email_body_slug_replacement_notice": "Un administrator din echipa {{teamName}} v-a înlocuit tipul de eveniment /{{slug}} cu un tip de eveniment configurat pe care îl controlează.", + "email_body_slug_replacement_info": "Linkul dvs. va funcționa în continuare, dar este posibil ca unele setări să se fi schimbat. Îl puteți consulta în tipurile de evenimente.", "email_body_slug_replacement_suggestion": "Dacă aveți întrebări despre tipul de eveniment, luați legătura cu administratorul dvs.

Programări cu spor,
Echipa Cal.com", "disable_payment_app": "Administratorul a dezactivat {{appName}} care afectează tipul tău de eveniment {{title}}. Participanții încă pot să facă rezervări pentru acest tip de eveniment, dar nu li se va solicita să plătească. Poți ascunde tipul de eveniment pentru a preveni acest lucru până când administratorul tău reactivează metoda ta de plată.", "payment_disabled_still_able_to_book": "Participanții încă pot să facă rezervări pentru acest tip de eveniment, dar nu li se va solicita să plătească. Poți ascunde tipul de eveniment pentru a preveni acest lucru până când administratorul tău reactivează metoda ta de plată.", @@ -1685,14 +1685,14 @@ "add_1_option_per_line": "Adăugați o opțiune pe linie", "select_a_router": "Selectați un parcurs", "add_a_new_route": "Adăugați un parcurs nou", - "make_informed_decisions": "Ia decizii informate cu Insights", - "make_informed_decisions_description": "Tabloul de bord Insights prezintă toate activitățile din echipa ta și îți arată tendințele care te ajută să îți programezi mai bine echipa și să iei decizii mai bune.", - "view_bookings_across": "Vezi rezervările tuturor membrilor", - "view_bookings_across_description": "Vezi cine primește cele mai multe rezervări și asigură cea mai bună distribuție în echipa ta", - "identify_booking_trends": "Identifică tendințele legate de rezervare", - "identify_booking_trends_description": "Vezi ce zile din săptămână și ore din timpul zilei sunt populare pentru persoanele care fac rezervări", - "spot_popular_event_types": "Identifică tipuri de evenimente populare", - "spot_popular_event_types_description": "Vezi care dintre tipurile de evenimente primesc cele mai multe clicuri și rezervări", + "make_informed_decisions": "Luați decizii informate cu Insights", + "make_informed_decisions_description": "Tabloul de bord Insights prezintă toate activitățile din echipa dvs. și vă arată tendințele care vă ajută să faceți programări mai bune pentru echipă și să luați decizii mai bune.", + "view_bookings_across": "Vizualizați rezervările tuturor membrilor", + "view_bookings_across_description": "Vedeți cine primește cele mai multe rezervări și asigurați cea mai bună distribuție în echipa dvs.", + "identify_booking_trends": "Identificați tendințele legate de rezervări", + "identify_booking_trends_description": "Vedeți ce zile din săptămână și ore din timpul zilei sunt populare pentru persoanele care fac rezervări", + "spot_popular_event_types": "Identificați tipurile de evenimente populare", + "spot_popular_event_types_description": "Vedeți care dintre tipurile de evenimente primesc cele mai multe clicuri și rezervări", "no_responses_yet": "Nu există încă răspunsuri", "this_will_be_the_placeholder": "Acesta va fi substituentul", "this_meeting_has_not_started_yet": "Această întâlnire nu a început încă", @@ -1716,7 +1716,7 @@ "default_conferencing_bulk_title": "Actualizare în masă tipuri de evenimente existente", "members_default_schedule": "Programul implicit al membrului", "set_by_admin": "Setat de administratorul echipei", - "members_default_location": "Localizarea implicită a membrului", + "members_default_location": "Locația implicită a membrului", "members_default_schedule_description": "Vom utiliza programul implicit de disponibilitate al fiecărui membru. Aceștia îl vor putea edita sau schimba.", "requires_at_least_one_schedule": "Este necesar să aveți cel puțin un program", "default_conferencing_bulk_description": "Actualizați locațiile pentru tipurile de evenimente selectate", diff --git a/apps/web/public/static/locales/tr/common.json b/apps/web/public/static/locales/tr/common.json index b3d91b918c..1de3b1816e 100644 --- a/apps/web/public/static/locales/tr/common.json +++ b/apps/web/public/static/locales/tr/common.json @@ -593,7 +593,7 @@ "username_placeholder": "kullanıcı adı", "managed_event_description": "Etkinlik türlerini toplu olarak oluşturun ve ekip üyelerine dağıtın", "managed": "Yönetildi", - "managed_event_url_clarification": "\"username\" alanı, atanan üyelerin kullanıcı adı ile doldurulacaktır", + "managed_event_url_clarification": "\"username\" alanı, atanan üyelerin kullanıcı adı ile doldurulur", "assign_to": "Şuraya ata:", "add_members": "Üye ekle...", "count_members_one": "{{count}} üye", @@ -1200,7 +1200,7 @@ "start_of_week": "Haftanın başlangıcı", "recordings_title": "Kayıtlar", "recording": "Kayıt", - "happy_scheduling": "Mutlu Planlama", + "happy_scheduling": "İyi Planlamalar", "select_calendars": "Çifte rezervasyonu önlemek için çakışmaları kontrol etmek istediğiniz takvimleri seçin.", "check_for_conflicts": "Çakışmaları kontrol edin", "view_recordings": "Kayıtları görüntüle", @@ -1280,7 +1280,7 @@ "download_responses_description": "Formunuza gelen tüm yanıtları CSV formatında indirin.", "download": "İndir", "download_recording": "Kaydı İndir", - "recording_from_your_recent_call": "Cal.com'daki son görüşmenize ait bir kayıt indirilmeye hazır", + "recording_from_your_recent_call": "Cal.com'daki son aramanızın kaydı indirilmeye hazır", "create_your_first_form": "İlk formunuzu oluşturun", "create_your_first_form_description": "Yönlendirme Formları ile yeterlik soruları sorabilir ve bunları doğru kişiye veya etkinlik türüne yönlendirebilirsiniz.", "create_your_first_webhook": "İlk Web kancanızı oluşturun", @@ -1380,7 +1380,7 @@ "add_limit": "Kısıtlama Ekleyin", "team_name_required": "Ekip adı gereklidir", "show_attendees": "Katılımcı bilgilerini misafirler arasında paylaşın", - "how_booking_questions_as_variables": "Rezervasyonla ilgili sorular değişken olarak nasıl kullanılır?", + "how_booking_questions_as_variables": "Rezervasyon soruları değişken olarak nasıl kullanılır?", "format": "Biçim", "uppercase_for_letters": "Tüm harfleri büyük harf olarak kullanın", "replace_whitespaces_underscores": "Boşlukları alt çizgi ile değiştir", @@ -1395,7 +1395,7 @@ "billing_help_title": "Başka bir şeye ihtiyacınız var mı?", "billing_help_description": "Faturalandırma konusunda daha fazla yardıma ihtiyacınız olursa destek ekibimiz size yardımcı olmaya hazır.", "billing_help_cta": "Destek ekibimize ulaşın", - "ignore_special_characters_booking_questions": "Rezervasyon sorusu tanımlayıcınızdaki özel karakterleri kullanmayın. Yalnızca harfler ve sayılar kullanın", + "ignore_special_characters_booking_questions": "Rezervasyon sorusu tanımlayıcınızdaki özel karakterleri yok sayın. Yalnızca harf ve sayıları kullanın", "retry": "Yeniden dene", "fetching_calendars_error": "Takvimleriniz alınırken bir sorun oluştu. Lütfen <1>tekrar deneyin veya müşteri destek ekibiyle iletişme geçin.", "calendar_connection_fail": "Takvim bağlantısı yapılamadı", @@ -1485,10 +1485,10 @@ "admin_has_disabled": "Bir yönetici {{appName}} adlı uygulamayı devre dışı bıraktı", "disabled_app_affects_event_type": "Bir yönetici {{eventType}} etkinlik türünüzü etkileyen {{appName}} adlı uygulamayı devre dışı bıraktı", "event_replaced_notice": "Bir yönetici, etkinlik türlerinizden birini değiştirdi", - "email_subject_slug_replacement": "Bir ekip yöneticisi etkinliğinizi /{{slug}} değiştirdi", + "email_subject_slug_replacement": "Bir ekip yöneticisi, etkinliğinizi /{{slug}} değiştirdi", "email_body_slug_replacement_notice": "{{teamName}} ekibindeki bir yönetici, /{{slug}} etkinlik türünüzü kontrol ettiği yönetilen bir etkinlik türüyle değiştirdi.", "email_body_slug_replacement_info": "Bağlantınız çalışmaya devam edecek, ancak bazı ayarları değişmiş olabilir. Bağlantıyı etkinlik kategorilerinde inceleyebilirsiniz.", - "email_body_slug_replacement_suggestion": "Etkinlik türüyle ilgili herhangi bir sorunuz varsa lütfen yöneticinizle iletişime geçin.

Mutlu planlama,
Cal.com ekibi", + "email_body_slug_replacement_suggestion": "Etkinlik türüyle ilgili herhangi bir sorunuz varsa lütfen yöneticinizle iletişime geçin.

İyi planlamalar,
Cal.com ekibi", "disable_payment_app": "Yönetici, {{title}} etkinlik türünüzü etkileyebilecek {{appName}} uygulamasını devre dışı bıraktı. Katılımcılar yine de bu tür bir etkinlik için rezervasyon yaptırabilirler ancak herhangi bir ödeme yapmalarına gerek yoktur. Bu durumu önlemek için yöneticiniz ödeme yönteminizi yeniden etkinleştirene kadar etkinlik türünü gizleyebilirsiniz.", "payment_disabled_still_able_to_book": "Katılımcılar yine de bu tür bir etkinlik için rezervasyon yaptırabilirler, ancak herhangi bir ödeme yapmalarına gerek yoktur. Bu durumu önlemek için yöneticiniz ödeme yönteminizi yeniden etkinleştirene kadar etkinlik türünü gizleyebilirsiniz.", "app_disabled_with_event_type": "Yönetici, etkinlik {{title}} türünüzü etkileyen {{appName}} uygulamasını devre dışı bıraktı.", @@ -1686,7 +1686,7 @@ "select_a_router": "Yönlendirici seçin", "add_a_new_route": "Yeni bir Yönlendirme ekle", "make_informed_decisions": "Insights ile bilinçli kararlar verin", - "make_informed_decisions_description": "lnsights panomuz, ekibinizdeki tüm etkinlikleri analiz eder ve size daha iyi ekip planlaması yapma ve karar verme imkanı sağlayan eğilimleri gösterir.", + "make_informed_decisions_description": "lnsights panomuz, ekibinizdeki tüm etkinlikleri analiz eder ve size daha iyi ekip planlaması yapma ve karar verme imkanı sağlayan trendleri gösterir.", "view_bookings_across": "Tüm üyelerin rezervasyonlarını görüntüleyin", "view_bookings_across_description": "En çok rezervasyonu kimin aldığını görün ve tüm ekibiniz için en iyi dağılımı sağlayın", "identify_booking_trends": "Rezervasyon trendlerini belirleyin", @@ -1750,7 +1750,7 @@ "events_cancelled": "İptal Edilen Etkinlikler", "events_rescheduled": "Yeniden Planlanan Etkinlikler", "from_last_period": "son dönemden itibaren", - "from_to_date_period": "İlk tarih: {{startDate}} Son tarih: {{endDate}}", + "from_to_date_period": "Başlangıç: {{startDate}} Bitiş: {{endDate}}", "analytics_for_organisation": "Insights", "subtitle_analytics": "Ekibinizin aktivitesi hakkında daha fazla bilgi edinin", "redirect_url_warning": "Yönlendirme eklemek başarı sayfasını devre dışı bırakır. Özel başarı sayfanızda \"Rezervasyon Onaylandı\" ifadesinden bahsetmeyi unutmayın.", diff --git a/apps/web/public/static/locales/uk/common.json b/apps/web/public/static/locales/uk/common.json index 608f273117..31a1750875 100644 --- a/apps/web/public/static/locales/uk/common.json +++ b/apps/web/public/static/locales/uk/common.json @@ -408,7 +408,7 @@ "add_time_availability": "Додати нове часове вікно", "add_an_extra_layer_of_security": "Підвищте рівень захисту свого облікового запису на випадок, якщо у вас викрадуть пароль.", "2fa": "Двоетапна автентифікація", - "2fa_disabled": "Двоетапну автентифікацію можна ввімкнути лише для автентифікації за допомогою ел. пошти й пароля", + "2fa_disabled": "Двоетапну автентифікацію можна ввімкнути лише для входу за допомогою електронної пошти й пароля", "enable_2fa": "Увімкнути двоетапну автентифікацію", "disable_2fa": "Вимкнути двоетапну автентифікацію", "disable_2fa_recommendation": "Якщо вам потрібно вимкнути двоетапну перевірку, рекомендуємо потім увімкнути її якомога швидше.", @@ -597,12 +597,12 @@ "assign_to": "Призначити", "add_members": "Додати учасників…", "count_members_one": "{{count}} учасник", - "count_members_other": "{{count}} учасники(-ів)", + "count_members_other": "Учасників: {{count}}", "no_assigned_members": "Немає призначених учасників", - "assigned_to": "Призначено", + "assigned_to": "Кому призначено:", "start_assigning_members_above": "Почніть призначати учасників вище", - "locked_fields_admin_description": "Учасники не зможуть редагувати це", - "locked_fields_member_description": "Адміністратор команди заблокував цю опцію", + "locked_fields_admin_description": "Учасники не зможуть змінити це", + "locked_fields_member_description": "Адміністратор команди заблокував цей варіант", "url": "URL", "hidden": "Приховано", "readonly": "Тільки читання", @@ -756,8 +756,8 @@ "slot_interval_default": "Використовувати тривалість заходу (за замовчуванням)", "delete_event_type": "Видалити тип заходу?", "delete_managed_event_type": "Видалити захід керованого типу?", - "delete_event_type_description": "Користувачі, з якими ви поділилися цим посиланням, більше не зможуть здійснити бронювання з його допомогою.", - "delete_managed_event_type_description": "
  • В учасників, призначених для цього типу заходу, також буде видалено їхні типи заходів.
  • Користувачі, з якими вони поділилися своїм посиланням, більше не зможуть здійснити бронювання з його допомогою.
", + "delete_event_type_description": "Користувачі, з якими ви поділилися цим посиланням, більше не зможуть скористатися ним, щоб створити бронювання.", + "delete_managed_event_type_description": "
  • Типи заходів учасників, призначених для цього типу заходу, також буде видалено.
  • Користувачі, з якими вони поділилися своїм посиланням, більше не зможуть скористатися ним, щоб створити бронювання.
", "confirm_delete_event_type": "Так, видалити", "delete_account": "Видалити обліковий запис", "confirm_delete_account": "Так, видалити обліковий запис", @@ -1148,13 +1148,13 @@ "current_username": "Поточне ім’я користувача", "example_1": "Приклад 1", "example_2": "Приклад 2", - "booking_question_identifier": "Ідентифікатор запитання щодо бронювання", + "booking_question_identifier": "Ідентифікатор запитання про бронювання", "company_size": "Розмір компанії", "what_help_needed": "З чим саме потрібна допомога?", "variable_format": "Формат змінної", "webhook_subscriber_url_reserved": "URL-адресу для абонента у вебгуку вже визначено", "custom_input_as_variable_info": "Усі спеціальні символи в додатковому введеному підписі пропускаються (використовуються тільки літери та цифри), використовуються лише великі літери, пробіли замінюються на підкреслення.", - "using_booking_questions_as_variables": "Як використовувати запитання щодо бронювання як змінні?", + "using_booking_questions_as_variables": "Як використовувати запитання про бронювання як змінні?", "download_desktop_app": "Завантажити додаток для ПК", "set_ping_link": "Установити Ping-посилання", "rate_limit_exceeded": "Перевищено ліміт кількості запитів", @@ -1177,7 +1177,7 @@ "event_advanced_tab_title": "Додатково", "event_setup_multiple_duration_error": "Налаштування заходу: якщо мають бути доступні різні варіанти, потрібно вказати принаймні один.", "event_setup_multiple_duration_default_error": "Налаштування заходу: виберіть припустиму тривалість за замовчуванням.", - "event_setup_booking_limits_error": "Ліміти на бронювання мають бути впорядковані за зростанням. [день,тиждень,місяць,рік]", + "event_setup_booking_limits_error": "Ліміти бронювання має бути впорядковано за зростанням. [день, тиждень, місяць, рік]", "event_setup_duration_limits_error": "Ліміти тривалості мають бути впорядковані за зростанням. [день, тиждень, місяць, рік]", "select_which_cal": "Виберіть календар, у який додаватимуться бронювання", "custom_event_name": "Користувацька назва події", @@ -1200,7 +1200,7 @@ "start_of_week": "Початок тижня", "recordings_title": "Записи", "recording": "Запис", - "happy_scheduling": "Щасливого планування", + "happy_scheduling": "Вдалого планування", "select_calendars": "Виберіть, які календарі потрібно перевірити на наявність конфліктів, щоб уникнути подвійних бронювань.", "check_for_conflicts": "Перевірка конфліктів", "view_recordings": "Переглянути записи", @@ -1326,7 +1326,7 @@ "exchange_version_2013_SP1": "2013 SP1", "exchange_version_2015": "2015", "exchange_version_2016": "2016", - "routing_forms_description": "Тут можна переглянути всі створені вами форми й переспрямування.", + "routing_forms_description": "Створюйте форми, щоб правильно скеровувати відвідувачів", "routing_forms_send_email_owner": "Надіслати власнику електронний лист", "routing_forms_send_email_owner_description": "Коли надсилається форма, власник отримує електронний лист", "add_new_form": "Додати нову форму", @@ -1380,7 +1380,7 @@ "add_limit": "Додати ліміт", "team_name_required": "Назва команди обов’язкова", "show_attendees": "Поширювати інформацію про учасників серед гостей", - "how_booking_questions_as_variables": "Як використовувати запитання щодо бронювання як змінні?", + "how_booking_questions_as_variables": "Як використовувати запитання про бронювання як змінні?", "format": "Формат", "uppercase_for_letters": "Використовувати всі великі літери", "replace_whitespaces_underscores": "Заміняти пробіли підкресленнями", @@ -1395,7 +1395,7 @@ "billing_help_title": "Потрібно щось інше?", "billing_help_description": "Якщо вам потрібна додаткова допомога з виставленням рахунків, наша служба підтримки готова її надати.", "billing_help_cta": "Звернутися в службу підтримки", - "ignore_special_characters_booking_questions": "Пропускайте спеціальні символи в ідентифікаторі запитання щодо бронювання. Використовуйте лише літери й цифри.", + "ignore_special_characters_booking_questions": "Пропускайте спеціальні символи в ідентифікаторі запитання про бронювання та використовуйте лише літери й цифри", "retry": "Повторити", "fetching_calendars_error": "Під час отримання календарів виникла проблема. <1>Повторіть спробу або зверніться в службу підтримки.", "calendar_connection_fail": "Не вдалося підключитися до календаря", @@ -1487,8 +1487,8 @@ "event_replaced_notice": "Адміністратор замінив один із типів ваших заходів", "email_subject_slug_replacement": "Адміністратор команди замінив ваш захід /{{slug}}", "email_body_slug_replacement_notice": "Адміністратор команди {{teamName}} замінив ваш тип заходу/{{slug}} на керований тип заходу, який він контролює.", - "email_body_slug_replacement_info": "Ваше посилання продовжуватиме працювати, але деякі параметри можуть бути змінені. Дізнайтеся більше в типах подій.", - "email_body_slug_replacement_suggestion": "Якщо у вас виникли запитання щодо типу заходу, зверніться до свого адміністратора.

Щасливого планування!
Команда Cal.com", + "email_body_slug_replacement_info": "Ваше посилання й надалі працювати, але деякі параметри можуть змінитися. Перегляньте їх у типах подій.", + "email_body_slug_replacement_suggestion": "Якщо у вас є запитання про тип заходу, зверніться до свого адміністратора.

Вдалого планування!
Команда Cal.com", "disable_payment_app": "Адміністратор вимкнув додаток {{appName}}, що впливає на ваш тип заходу «{{title}}». Учасники все одно можуть бронювати події такого типу, але від них не вимагатиметься оплата. Ви можете приховати цей тип заходу, щоб уникнути цього, і дочекатись активації способу оплати адміністратором.", "payment_disabled_still_able_to_book": "Учасники все одно можуть бронювати події такого типу, але від них не вимагатиметься оплата. Ви можете приховати цей тип заходу, щоб уникнути цього, і дочекатись активації способу оплати адміністратором.", "app_disabled_with_event_type": "Адміністратор вимкнув додаток {{appName}}, що впливає на ваш тип заходу «{{title}}».", From 85caa247f82fd6a3e88cca3c661f6213c03b79a2 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Fri, 26 May 2023 10:38:53 +0000 Subject: [PATCH 653/658] New Crowdin translations by Github Action --- apps/web/public/static/locales/ro/common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/public/static/locales/ro/common.json b/apps/web/public/static/locales/ro/common.json index bca838c91c..6836cb0451 100644 --- a/apps/web/public/static/locales/ro/common.json +++ b/apps/web/public/static/locales/ro/common.json @@ -1733,7 +1733,7 @@ "managed_event_dialog_information_one": "{{names}} folosește deja URL-ul /{{slug}}.", "managed_event_dialog_information_other": "{{names}} folosesc deja URL-ul /{{slug}}.", "managed_event_dialog_clarification": "Îi vom anunța dacă alegeți să îl înlocuiți. Reveniți și ștergeți-i dacă nu doriți să îl suprascrieți.", - "review_event_type": "Evaluați tipul de eveniment", + "review_event_type": "Revizuiți tipul de eveniment", "looking_for_more_analytics": "Cauți mai multe analize?", "looking_for_more_insights": "Căutați mai multe perspective?", "add_filter": "Adaugă filtru", From 084f56d052183f3c250634c6d24240c741eba197 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Fri, 26 May 2023 10:39:48 +0000 Subject: [PATCH 654/658] New Crowdin translations by Github Action --- apps/web/public/static/locales/ro/common.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/public/static/locales/ro/common.json b/apps/web/public/static/locales/ro/common.json index 6836cb0451..1063b6add4 100644 --- a/apps/web/public/static/locales/ro/common.json +++ b/apps/web/public/static/locales/ro/common.json @@ -1734,7 +1734,7 @@ "managed_event_dialog_information_other": "{{names}} folosesc deja URL-ul /{{slug}}.", "managed_event_dialog_clarification": "Îi vom anunța dacă alegeți să îl înlocuiți. Reveniți și ștergeți-i dacă nu doriți să îl suprascrieți.", "review_event_type": "Revizuiți tipul de eveniment", - "looking_for_more_analytics": "Cauți mai multe analize?", + "looking_for_more_analytics": "Căutați mai multe analize?", "looking_for_more_insights": "Căutați mai multe perspective?", "add_filter": "Adaugă filtru", "select_user": "Selectează utilizatorul", From 1b68cc139f212ab2d3fc2490844561b1a587ad5b Mon Sep 17 00:00:00 2001 From: Alex van Andel Date: Fri, 26 May 2023 12:48:01 +0200 Subject: [PATCH 655/658] v2.9.4 --- apps/web/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/package.json b/apps/web/package.json index 43116cd3c7..003d767777 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@calcom/web", - "version": "2.9.3", + "version": "2.9.4", "private": true, "scripts": { "analyze": "ANALYZE=true next build", From 75ba35c73214d535d00f3f20c7f9fed68b5a53a2 Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 26 May 2023 13:58:31 -0700 Subject: [PATCH 656/658] Possible fix to stuck CI --- apps/api/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/api/package.json b/apps/api/package.json index 6e3bb66f3a..af678fe46b 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -14,7 +14,7 @@ "lint:report": "eslint . --format json --output-file ../../lint-results/api.json", "lint:fix": "eslint . --ext .ts,.js,.tsx,.jsx --fix", "start": "PORT=3002 next start", - "test": "echo 'No tests yet' && exit 1", + "test": "echo 'No tests yet' && exit 0", "type-check": "tsc --pretty --noEmit" }, "devDependencies": { From fcb06f82d90cfcc6a48cfd3c397e1cfb829954e9 Mon Sep 17 00:00:00 2001 From: Crowdin Bot Date: Fri, 26 May 2023 20:59:30 +0000 Subject: [PATCH 657/658] New Crowdin translations by Github Action --- apps/web/public/static/locales/ro/common.json | 14 ++-- apps/web/public/static/locales/sv/common.json | 22 ++--- apps/web/public/static/locales/uk/common.json | 80 +++++++++---------- 3 files changed, 58 insertions(+), 58 deletions(-) diff --git a/apps/web/public/static/locales/ro/common.json b/apps/web/public/static/locales/ro/common.json index 1063b6add4..d3a3097b55 100644 --- a/apps/web/public/static/locales/ro/common.json +++ b/apps/web/public/static/locales/ro/common.json @@ -1736,10 +1736,10 @@ "review_event_type": "Revizuiți tipul de eveniment", "looking_for_more_analytics": "Căutați mai multe analize?", "looking_for_more_insights": "Căutați mai multe perspective?", - "add_filter": "Adaugă filtru", - "select_user": "Selectează utilizatorul", - "select_event_type": "Selectează tipul de eveniment", - "select_date_range": "Selectează intervalul de date", + "add_filter": "Adăugare filtru", + "select_user": "Selectare utilizator", + "select_event_type": "Selectare tip eveniment", + "select_date_range": "Selectare interval de date", "popular_events": "Evenimente populare", "no_event_types_found": "Nu s-a găsit niciun tip de eveniment", "average_event_duration": "Durata medie a evenimentului", @@ -1764,8 +1764,8 @@ "card_charged": "Card debitat", "no_show_fee_amount": "Taxă de neprezentare în valoare de {{amount, currency}}", "no_show_fee": "Taxă de neprezentare", - "submit_card": "Trimiteți cardul", - "submit_payment_information": "Trimiteți informațiile de plată", + "submit_card": "Trimitere card", + "submit_payment_information": "Trimitere informații de plată", "meeting_awaiting_payment_method": "Ședința va începe după efectuarea plății", "no_show_fee_charged_email_subject": "Taxă de neprezentare în valoare de {{amount, currency}}, percepută pentru {{title}}, pe {{date}}", "no_show_fee_charged_text_body": "Taxa de neprezentare a fost percepută", @@ -1774,7 +1774,7 @@ "collect_no_show_fee": "Colectare taxă de neprezentare", "no_show_fee_charged": "Taxă de neprezentare percepută", "insights": "Insights", - "testing_workflow_info_message": "La testarea acestui flux de lucru, țineți cont de faptul că e-mailurile și SMS-urile pot fi programate cu cel puțin o oră în prealabil", + "testing_workflow_info_message": "La testarea acestui flux de lucru, țineți cont de faptul că e-mailurile și SMS-urile pot fi programate doar cu cel puțin o oră în prealabil", "insights_no_data_found_for_filter": "Nu s-au găsit date pentru filtrul selectat sau pentru datele selectate.", "acknowledge_booking_no_show_fee": "Dacă nu particip la acest eveniment, accept să mi se perceapă de pe card o taxă de neprezentare în valoare de {{amount, currency}}.", "card_details": "Detalii card", diff --git a/apps/web/public/static/locales/sv/common.json b/apps/web/public/static/locales/sv/common.json index 06f6308874..0ca6cb7df5 100644 --- a/apps/web/public/static/locales/sv/common.json +++ b/apps/web/public/static/locales/sv/common.json @@ -70,8 +70,8 @@ "event_awaiting_approval_subject": "Inväntar godkännande: {{title}} den {{date}}", "event_still_awaiting_approval": "En bokning väntar fortfarande på ditt godkännande", "booking_submitted_subject": "Bokning skickad: {{title}} {{date}}", - "download_recording_subject": "Ladda ner inspelning: {{title}} {{date}}", - "download_your_recording": "Ladda ner din inspelning", + "download_recording_subject": "Ladda ned inspelning: {{title}} {{date}}", + "download_your_recording": "Ladda ned din inspelning", "your_meeting_has_been_booked": "Ditt möte har bokats", "event_type_has_been_rescheduled_on_time_date": "Din {{title}} har ändrats till {{date}}.", "event_has_been_rescheduled": "Uppdatering - Din bokning har blivit omplanerad", @@ -595,7 +595,7 @@ "managed": "Hanterad", "managed_event_url_clarification": "\"användarnamn\" kommer att fyllas i med användarnamnet för de medlemmar som tilldelats", "assign_to": "Tilldela till", - "add_members": "Lägg till medlemmar...", + "add_members": "Lägg till medlemmar ...", "count_members_one": "{{count}} medlem", "count_members_other": "{{count}} medlemmar", "no_assigned_members": "Inga tilldelade medlemmar", @@ -1279,7 +1279,7 @@ "download_responses": "Ladda ned svar", "download_responses_description": "Ladda ned alla svar till ditt formulär i CSV-format.", "download": "Ladda ned", - "download_recording": "Ladda ner inspelning", + "download_recording": "Ladda ned inspelning", "recording_from_your_recent_call": "En inspelning från ditt senaste samtal på Cal.com är redo för nedladdning", "create_your_first_form": "Skapa ditt första formulär", "create_your_first_form_description": "Med omdirigeringsformulär kan du ställa kvalificerade frågor och dirigera till rätt person eller händelsetyp.", @@ -1584,7 +1584,7 @@ "ee_enterprise_license": "\"/ee\" Enterprise-licens", "enterprise_booking_fee": "Från {{enterprise_booking_fee}}/månad", "enterprise_license_includes": "Allt för ett kommersiellt användningsfall", - "no_need_to_keep_your_code_open_source": "Inget behov av att behålla din kod som öppen källkod", + "no_need_to_keep_your_code_open_source": "Behöver inte behålla din kod som öppen källkod", "repackage_rebrand_resell": "Lätt att ompaketera, omprofilera och sälja vidare", "a_vast_suite_of_enterprise_features": "En omfattande uppsättning Enterprise-funktioner", "free_license_fee": "0,00 USD/månad", @@ -1704,18 +1704,18 @@ "can_you_try_again": "Kan du försöka igen med en annan tid?", "verify": "Verifiera", "timezone_variable": "Tidszon", - "timezone_info": "Tidszonen för den person som tar emot", + "timezone_info": "Tidszon för mottagande person", "event_end_time_variable": "Händelsens sluttid", "event_end_time_info": "Händelsens sluttid", "cancel_url_variable": "URL för att avbryta", - "cancel_url_info": "Webbadressen fö ratt avbryta bokningen", + "cancel_url_info": "URL för att avbryta bokningen", "reschedule_url_variable": "URL för ombokning", - "reschedule_url_info": "Webbadressen för att ändra bokningen", + "reschedule_url_info": "URL för att ändra bokningen", "invalid_event_name_variables": "Det finns en ogiltig variabel i ditt händelsenamn", "select_all": "Välj alla", "default_conferencing_bulk_title": "Massuppdatering av befintliga händelsetyper", "members_default_schedule": "Medlemmens standardschema", - "set_by_admin": "Ställ in av teamadministratör", + "set_by_admin": "Ställs in av teamadministratör", "members_default_location": "Medlemmens förvalda plats", "members_default_schedule_description": "Vi kommer att använda varje medlems standardschema för tillgänglighet. De kommer att kunna redigera eller ändra det.", "requires_at_least_one_schedule": "Du måste ha minst ett schema", @@ -1741,8 +1741,8 @@ "select_event_type": "Välj händelsetyp", "select_date_range": "Välj datumintervall", "popular_events": "Populära händelser", - "no_event_types_found": "Inga händelsetyper hittade", - "average_event_duration": "Genomsnittlig händelselängd", + "no_event_types_found": "Inga händelsetyper hittades", + "average_event_duration": "Genomsnittlig varaktighet för händelse", "most_booked_members": "Mest bokade medlemmar", "least_booked_members": "Minst bokade medlemmar", "events_created": "Skapade händelser", diff --git a/apps/web/public/static/locales/uk/common.json b/apps/web/public/static/locales/uk/common.json index 31a1750875..770f29bf04 100644 --- a/apps/web/public/static/locales/uk/common.json +++ b/apps/web/public/static/locales/uk/common.json @@ -70,7 +70,7 @@ "event_awaiting_approval_subject": "Очікування на схвалення: {{title}}, {{date}}", "event_still_awaiting_approval": "Захід досі чекає на ваше схвалення", "booking_submitted_subject": "Бронювання надіслано: {{title}}, {{date}}", - "download_recording_subject": "Завантажити запис: {{title}} о {{date}}", + "download_recording_subject": "Завантажити запис: {{title}} від {{date}}", "download_your_recording": "Завантажте запис", "your_meeting_has_been_booked": "Вашу нараду заброньовано", "event_type_has_been_rescheduled_on_time_date": "Ваш {{title}} перенесено на {{date}}.", @@ -593,8 +593,8 @@ "username_placeholder": "ім’я користувача", "managed_event_description": "Створюйте й надсилайте типи заходів усім учасникам команди пакетом", "managed": "Керований", - "managed_event_url_clarification": "у полі «username» буде вказано імена користувачів призначених учасників", - "assign_to": "Призначити", + "managed_event_url_clarification": "Поле «username» буде заповнено іменами користувачів призначених учасників", + "assign_to": "Кому призначити:", "add_members": "Додати учасників…", "count_members_one": "{{count}} учасник", "count_members_other": "Учасників: {{count}}", @@ -1177,7 +1177,7 @@ "event_advanced_tab_title": "Додатково", "event_setup_multiple_duration_error": "Налаштування заходу: якщо мають бути доступні різні варіанти, потрібно вказати принаймні один.", "event_setup_multiple_duration_default_error": "Налаштування заходу: виберіть припустиму тривалість за замовчуванням.", - "event_setup_booking_limits_error": "Ліміти бронювання має бути впорядковано за зростанням. [день, тиждень, місяць, рік]", + "event_setup_booking_limits_error": "Ліміти бронювань має бути впорядковано за зростанням. [день, тиждень, місяць, рік]", "event_setup_duration_limits_error": "Ліміти тривалості мають бути впорядковані за зростанням. [день, тиждень, місяць, рік]", "select_which_cal": "Виберіть календар, у який додаватимуться бронювання", "custom_event_name": "Користувацька назва події", @@ -1661,7 +1661,7 @@ "not_enough_seats": "Недостатньо місць", "form_builder_field_already_exists": "Поле з такою назвою вже існує", "form_builder_field_add_subtitle": "Налаштуйте запитання, відповіді на які потрібно буде надати на сторінці бронювання", - "show_on_booking_page": "Показати на сторінці бронювання", + "show_on_booking_page": "Показувати на сторінці бронювання", "get_started_zapier_templates": "Розпочніть роботу із шаблонами Zapier", "team_is_unpublished": "Публікацію команди «{{team}}» скасовано", "team_is_unpublished_description": "Посилання на команду зараз недоступне. Зверніться до власника команди або попросіть його опублікувати команду.", @@ -1685,14 +1685,14 @@ "add_1_option_per_line": "Додати 1 варіант на рядок", "select_a_router": "Вибрати форму переспрямування", "add_a_new_route": "Додати нове переспрямування", - "make_informed_decisions": "Приймайте обґрунтовані рішення за допомогою Insights", - "make_informed_decisions_description": "У розділі Insights показано всю діяльність вашої команди й тенденції, які дають змогу краще планувати час команди й приймати рішення.", + "make_informed_decisions": "Ухвалюйте обґрунтовані рішення за допомогою Insights", + "make_informed_decisions_description": "На інформаційній панелі Insights можна відстежувати всю роботу своєї команди й тенденції, які дають змогу ефективніше планувати час і ухвалювати рішення.", "view_bookings_across": "Переглядайте бронювання всіх учасників", - "view_bookings_across_description": "Дізнайтеся, хто отримує найбільше бронювань і забезпечте найкращий розподіл у команді", - "identify_booking_trends": "Визначте тенденції бронювання", - "identify_booking_trends_description": "Дізнайтесь, які дні тижня і який час популярні в користувачів, які здійснюють бронювання", - "spot_popular_event_types": "Визначте популярні типи заходів", - "spot_popular_event_types_description": "Дізнайтеся, які типи заходів отримують найбільшу кількість переходів і бронювань", + "view_bookings_across_description": "Дізнайтеся, у кого найбільше бронювань, і забезпечте оптимальний розподіл часу в команді", + "identify_booking_trends": "Визначайте тенденції бронювання", + "identify_booking_trends_description": "Дізнайтеся, які дні тижня і години дня найчастіше вибирають користувачі, які створюють бронювання", + "spot_popular_event_types": "Визначайте популярні типи заходів", + "spot_popular_event_types_description": "Дізнайтеся, які типи заходів мають найбільшу кількість переходів і бронювань", "no_responses_yet": "Поки немає відповідей", "this_will_be_the_placeholder": "Це заповнювач", "this_meeting_has_not_started_yet": "Ця нарада ще не почалася", @@ -1715,13 +1715,13 @@ "select_all": "Вибрати все", "default_conferencing_bulk_title": "Масове оновлення наявних типів заходів", "members_default_schedule": "Розклад учасника за замовчуванням", - "set_by_admin": "Встановлено адміністратором команди", + "set_by_admin": "Визначено адміністратором команди", "members_default_location": "Розташування учасника за замовчуванням", "members_default_schedule_description": "Ми використовуватимемо розклад кожного учасника за замовчуванням. Вони зможуть редагувати або змінювати його.", "requires_at_least_one_schedule": "У вас має бути принаймні один розклад", "default_conferencing_bulk_description": "Оновіть розташування для вибраних типів заходів", "locked_for_members": "Заблоковано для учасників", - "locked_apps_description": "Учасники зможуть бачити активні додатки, але не зможуть редагувати налаштування додатка", + "locked_apps_description": "Учасники бачитимуть активні додатки, але не зможуть змінювати їх налаштування", "locked_webhooks_description": "Учасники бачитимуть активні вебгуки, але не зможуть змінювати їх налаштування", "locked_workflows_description": "Учасники бачитимуть активні робочі процеси, але не зможуть змінювати їх налаштування", "app_not_connected": "Ви не під’єднали обліковий запис {{appName}}.", @@ -1732,14 +1732,14 @@ "managed_event_dialog_title_other": "URL-адреса /{{slug}} вже існує для кількох учасників ({{count}}). Хочете замінити її?", "managed_event_dialog_information_one": "{{names}} вже використовує URL-адресу /{{slug}}.", "managed_event_dialog_information_other": "{{names}} вже використовують URL-адресу /{{slug}}.", - "managed_event_dialog_clarification": "Якщо ви захочете замінити її, ми повідомимо їм. Поверніться і вилучіть їх, якщо ви не хочете перезаписувати її.", + "managed_event_dialog_clarification": "Якщо ви захочете замінити її, ми повідомимо учасників. Поверніться і вилучіть їх, замість того щоб перезаписувати.", "review_event_type": "Переглянути тип заходу", - "looking_for_more_analytics": "Вам потрібно більше аналітичних даних?", - "looking_for_more_insights": "Вам потрібно більше аналітики?", + "looking_for_more_analytics": "Потрібно більше аналітичних даних?", + "looking_for_more_insights": "Потрібно більше аналітики?", "add_filter": "Додати фільтр", - "select_user": "Виберіть користувача", - "select_event_type": "Виберіть тип заходу", - "select_date_range": "Виберіть діапазон дат", + "select_user": "Вибрати користувача", + "select_event_type": "Вибрати тип заходу", + "select_date_range": "Вибрати діапазон дат", "popular_events": "Популярні заходи", "no_event_types_found": "Типи заходів не знайдено", "average_event_duration": "Середня тривалість заходу", @@ -1752,34 +1752,34 @@ "from_last_period": "після останнього періоду", "from_to_date_period": "З: {{startDate}} До: {{endDate}}", "analytics_for_organisation": "Insights", - "subtitle_analytics": "Дізнайтеся більше про активність вашої команди", - "redirect_url_warning": "Додавання переспрямування вимкне сторінку з результатом бронювання. Переконайтеся, що ви додали текст «Бронювання підтверджено» на свою сторінку з результатом бронювання.", + "subtitle_analytics": "Дізнайтеся більше про активність своєї команди", + "redirect_url_warning": "Якщо додати переспрямування, сторінка з результатом бронювання не з’являтиметься. Переконайтеся, що ви додали текст «Бронювання підтверджено» на свою сторінку з результатом бронювання.", "event_trends": "Тенденції заходів", "clear_filters": "Очистити фільтри", - "hold": "Утримати", - "on_booking_option": "Отримуйте оплату за бронювання", - "hold_option": "Стягнути плату за відсутність", - "card_held": "Здійснено попередню авторизацію", + "hold": "Блокування", + "on_booking_option": "Отримувати плату за бронювання", + "hold_option": "Стягувати плату за відсутність", + "card_held": "Кошти на картці заблоковано", "charge_card": "Списати з картки", - "card_charged": "Списано кошти з картки", + "card_charged": "Кошти списано з картки", "no_show_fee_amount": "Плата за відсутність у розмірі {{amount, currency}}", "no_show_fee": "Плата за відсутність", - "submit_card": "Надіслати картку", - "submit_payment_information": "Надіслати платіжну інформацію", - "meeting_awaiting_payment_method": "Потрібно вказати спосіб оплати для вашої наради", - "no_show_fee_charged_email_subject": "Стягнуто плату за відсутність на заході «{{title}}» у розмірі {{amount, currency}} о {{date}}", - "no_show_fee_charged_text_body": "Стягнуто плату за відсутність", - "no_show_fee_charged_subtitle": "За нижчезазначений захід було стягнуто плату за відсутність у розмірі {{amount, currency}}", - "error_charging_card": "Сталася помилка під час стягнення плати за відсутність. Спробуйте ще раз пізніше.", + "submit_card": "Додати картку", + "submit_payment_information": "Зберегти платіжну інформацію", + "meeting_awaiting_payment_method": "Виберіть спосіб оплати для своєї наради", + "no_show_fee_charged_email_subject": "Плату за відсутність на заході «{{title}}» у розмірі {{amount, currency}} стягнуто {{date}}", + "no_show_fee_charged_text_body": "Плату за відсутність стягнуто", + "no_show_fee_charged_subtitle": "Плату за відсутність у розмірі {{amount, currency}} стягнуто для вказаного нижче заходу", + "error_charging_card": "Сталася помилка під час стягнення плати за відсутність. Спробуйте пізніше.", "collect_no_show_fee": "Стягнути плату за відсутність", "no_show_fee_charged": "Стягнуто плату за відсутність", "insights": "Insights", - "testing_workflow_info_message": "Тестуючи цей робочий процес, зважайте на те, що надсилання електронних листів і SMS-повідомлень можна запланувати мінімум за 1 годину", - "insights_no_data_found_for_filter": "Не знайдено жодних даних для вибраного фільтру або вибраних дат.", - "acknowledge_booking_no_show_fee": "Я підтверджую, що в разі моєї відсутності на цьому заході з моєї картки буде стягнуто плату за відсутність у розмірі {{amount, currency}}.", - "card_details": "Інформація про картку", - "seats_and_no_show_fee_error": "Наразі неможливо ввімкнути місця і стягнути плату за відсутність", + "testing_workflow_info_message": "Тестуючи цей робочий процес, зважайте на те, що надсилання електронних листів і SMS-повідомлень можна запланувати щонайменше за 1 годину", + "insights_no_data_found_for_filter": "Не знайдено жодних даних для вибраного фільтра або вибраних дат.", + "acknowledge_booking_no_show_fee": "Я усвідомлюю, що в разі моєї відсутності на цьому заході з моєї картки буде стягнуто плату в розмірі {{amount, currency}}.", + "card_details": "Карткові реквізити", + "seats_and_no_show_fee_error": "Зараз неможливо активувати місця і стягнути плату за відсутність", "complete_your_booking": "Завершіть бронювання", - "complete_your_booking_subject": "Завершіть бронювання: {{title}} {{date}}", + "complete_your_booking_subject": "Завершіть бронювання: {{title}} від {{date}}", "email_invite_team": "{{email}} запрошено" } From fcb0fce7997851e5359b31ea689fcb17a8e4852b Mon Sep 17 00:00:00 2001 From: zomars Date: Fri, 26 May 2023 14:14:49 -0700 Subject: [PATCH 658/658] Migrates missing jest test to vitest --- apps/api/test/lib/bookings/_post.test.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/apps/api/test/lib/bookings/_post.test.ts b/apps/api/test/lib/bookings/_post.test.ts index 95bf7a73d5..5e4b17f23d 100644 --- a/apps/api/test/lib/bookings/_post.test.ts +++ b/apps/api/test/lib/bookings/_post.test.ts @@ -1,19 +1,20 @@ import type { Request, Response } from "express"; import type { NextApiRequest, NextApiResponse } from "next"; import { createMocks } from "node-mocks-http"; +import { describe, expect, test, vi } from "vitest"; import dayjs from "@calcom/dayjs"; import sendPayload from "@calcom/features/webhooks/lib/sendPayload"; import { buildBooking, buildEventType, buildWebhook } from "@calcom/lib/test/builder"; import prisma from "@calcom/prisma"; -import { prismaMock } from "../../../../../tests/config/singleton"; +import prismaMock from "../../../../../tests/libs/__mocks__/prisma"; import handler from "../../../pages/api/bookings/_post"; type CustomNextApiRequest = NextApiRequest & Request; type CustomNextApiResponse = NextApiResponse & Response; -jest.mock("@calcom/features/webhooks/lib/sendPayload"); -jest.mock("@calcom/lib/server/i18n", () => { +vi.mock("@calcom/features/webhooks/lib/sendPayload"); +vi.mock("@calcom/lib/server/i18n", () => { return { getTranslation: (key: string) => key, }; @@ -151,7 +152,7 @@ describe("POST /api/bookings", () => { }); }); - xdescribe("Success", () => { + describe("Success", () => { describe("Regular event-type", () => { test("Creates one single booking", async () => { const { req, res } = createMocks({