diff --git a/.vscode/launch.json b/.vscode/launch.json index 8f325ad..363c83f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,7 @@ "request": "launch", "runtimeArgs": [ "run", - "dev", + "app:dev", ], "runtimeExecutable": "yarn", "skipFiles": [ diff --git a/components/Intro.tsx b/components/Intro.tsx deleted file mode 100644 index 7638435..0000000 --- a/components/Intro.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { Trans, useTranslation } from "next-i18next" -import { LoginContext } from "../contexts/login" -import { useDefinedContext } from "../utils/definedContext" -import { InputSlug } from "./InputEventSlug" -import { LoginButton } from "./LoginButton" -import { LogoutLink } from "./LogoutLink" -import { TelegramUser } from "./TelegramUser" - - -export function Intro() { - const {t} = useTranslation("common") - const [login, _] = useDefinedContext(LoginContext) - - const loginMessage = login ? <> - - introTelegramLoggedIn(1: ) - -
- - : <> - {t("introTelegramLogin")} - - - const input = login ? <> -

- {t("introCreateEvent")} -

-
- {window.location.protocol}// - {window.location.host}/events/ - - - - : <> - - - - return <> -

- {loginMessage} -

- {input} - -} \ No newline at end of file diff --git a/components/LoginButton.tsx b/components/LoginButton.tsx deleted file mode 100644 index 54f1ee5..0000000 --- a/components/LoginButton.tsx +++ /dev/null @@ -1,18 +0,0 @@ -import * as React from 'react'; -import {LoginContext} from "../contexts/login" -import OriginalTelegramLoginButton from 'react-telegram-login' -import { useDefinedContext } from '../utils/definedContext'; - -export function LoginButton(props: any) { - const [login, setLogin] = useDefinedContext(LoginContext) - - return ( -
- -
- ) -} \ No newline at end of file diff --git a/components/LogoutLink.tsx b/components/LogoutLink.tsx index 46f5269..eb39009 100644 --- a/components/LogoutLink.tsx +++ b/components/LogoutLink.tsx @@ -8,9 +8,11 @@ export function LogoutLink() { return ( + ( setLogin(null)}> {t("introTelegramLogout")} + ) ) } \ No newline at end of file diff --git a/components/TelegramLoginButton.tsx b/components/TelegramLoginButton.tsx new file mode 100644 index 0000000..1ec9dfb --- /dev/null +++ b/components/TelegramLoginButton.tsx @@ -0,0 +1,14 @@ +import * as React from 'react'; +import { default as OriginalTelegramLoginButton } from 'react-telegram-login' + + +export function TelegramLoginButton(props: any) { + return ( +
+ +
+ ) +} \ No newline at end of file diff --git a/components/TutorialTelegramLogin.tsx b/components/TutorialTelegramLogin.tsx new file mode 100644 index 0000000..635fbb8 --- /dev/null +++ b/components/TutorialTelegramLogin.tsx @@ -0,0 +1,41 @@ +import { useTranslation } from "next-i18next" +import { useCallback } from "react" +import { LoginContext } from "../contexts/login" +import { useDefinedContext } from "../utils/definedContext" +import { TelegramLoginButton } from "./TelegramLoginButton" +import * as Telegram from "../utils/telegram" +import axios from "axios" + + +export function TutorialTelegramLogin() { + const { t } = useTranslation("common") + const [login, setLogin] = useDefinedContext(LoginContext) + + const onLogin = useCallback( + async (data: Telegram.LoginData) => { + console.debug("[Telegram] Logged in successfully, now forwarding to the server...") + const response = await axios.post("/api/login/telegram", data) + console.info(response) + }, + [] + ) + + if (!login) { + return <> +
+ {t("introTelegramLogin")} +
+ + + } + else { + return <> +
+ +
+ + } +} \ No newline at end of file diff --git a/package.json b/package.json index 304bfd6..fd4c8e1 100644 --- a/package.json +++ b/package.json @@ -3,26 +3,33 @@ "version": "0.1.0", "private": true, "scripts": { - "dev": "next dev", - "build": "next build", - "start": "next start", - "lint": "next lint" + "app:dev": "next dev", + "app:build": "next build", + "app:start": "next start", + "app:lint": "next lint", + "db:dev": "dotenv -e .env.local prisma db push --force-reset", + "db:generate": "dotenv -e .env.local prisma generate" }, "dependencies": { "@prisma/client": "3.14.0", + "axios": "^0.27.2", "classnames": "^2.3.1", + "cors": "^2.8.5", + "crypto-random-string": "^5.0.0", "next": "12.1.6", "next-i18next": "^11.0.0", "prisma": "^3.14.0", "react": "18.1.0", "react-dom": "18.1.0", "react-storage-hooks": "^4.0.1", - "react-telegram-login": "^1.1.2" + "react-telegram-login": "^1.1.2", + "swr": "^1.3.0" }, "devDependencies": { "@types/node": "17.0.35", "@types/react": "18.0.9", "@types/react-dom": "18.0.4", + "dotenv-cli": "^5.1.0", "eslint": "8.15.0", "eslint-config-next": "12.1.6", "typescript": "4.6.4" diff --git a/pages/_app.tsx b/pages/_app.tsx index 1baa3a8..290d36b 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -1,7 +1,4 @@ import '../styles/globals.css' -import '../styles/telegram.css' -import '../styles/postcard.css' -import "../styles/index.css" import type { AppProps } from 'next/app' import { LoginContext } from '../contexts/login' import { useEffect, useState } from 'react' diff --git a/pages/api/.gitignore b/pages/api/.gitignore deleted file mode 100644 index e69de29..0000000 diff --git a/pages/api/login/telegram.ts b/pages/api/login/telegram.ts new file mode 100644 index 0000000..d1f4d0e --- /dev/null +++ b/pages/api/login/telegram.ts @@ -0,0 +1,79 @@ +import { NextApiRequest, NextApiResponse } from "next" +import { prisma } from "../../../utils/prismaClient" +import * as Telegram from "../../../utils/telegram" +import {default as cryptoRandomString} from "crypto-random-string" + + + +export default function handler(req: NextApiRequest, res: NextApiResponse) { + switch(req.method) { + case "POST": + const token = process.env.TELEGRAM_TOKEN + const validity_ms = parseInt(process.env.FESTA_TOKEN_VALIDITY_MS!) // Wrong typing? + const now = new Date() + + if(!token) { + return res.status(503).json({error: "`TELEGRAM_TOKEN` was not set up"}) + } + if(!validity_ms) { + return res.status(503).json({error: "`FESTA_TOKEN_VALIDITY_MS` was not set up"}) + } + + try { + var lr: Telegram.LoginResponse = new Telegram.LoginResponse(req.body) + } + catch(_) { + return res.status(422).json({error: "Malformed data"}) + } + + if(!lr.isRecent()) { + // Not sure? + return res.status(408).json({error: "Telegram login data is not recent"}) + } + + if(!lr.isValid(token)) { + return res.status(401).json({error: "Telegram login data has been tampered"}) + } + + prisma.user.upsert({ + where: { + id: lr.id, + }, + update: { + id: lr.id, + firstName: lr.first_name, + lastName: lr.last_name, + username: lr.username, + photoUrl: lr.photo_url, + lastAuthDate: now, + }, + create: { + id: lr.id, + firstName: lr.first_name, + lastName: lr.last_name, + username: lr.username, + photoUrl: lr.photo_url, + lastAuthDate: now, + } + }) + + const tokenString = cryptoRandomString({length: 16, type: "base64"}) + const tokenExpiration = new Date(+ now + validity_ms) + + prisma.token.create({ + data: { + userId: lr.id, + token: tokenString, + expiresAt: tokenExpiration, + } + }) + + return res.status(200).json({ + token: tokenString, + expiresAt: tokenExpiration.toISOString(), + }) + + default: + return res.status(405).json({error: "Invalid method"}) + } +} \ No newline at end of file diff --git a/pages/index.tsx b/pages/index.tsx index 9c6c345..18a83d7 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -2,19 +2,42 @@ import type { NextPage, NextPageContext } from 'next' import { useTranslation } from 'next-i18next' import { serverSideTranslations } from 'next-i18next/serverSideTranslations'; import { Intro } from '../components/Intro'; -import { LoginButton } from '../components/LoginButton'; +import { TutorialTelegramLogin } from '../components/TutorialTelegramLogin'; +import { LoginContext } from '../contexts/login'; +import { useDefinedContext } from '../utils/definedContext'; export async function getStaticProps(context: NextPageContext) { - return {props: { - ...(await serverSideTranslations(context.locale ?? "it-IT", ["common"])) - }} + return { + props: { + ...(await serverSideTranslations(context.locale ?? "it-IT", ["common"])) + } + } } const Page: NextPage = () => { - const {t} = useTranslation("common") + const { t } = useTranslation("common") + const [login, setLogin] = useDefinedContext(LoginContext) + + if (!login) { + return ( +
+
+

+ {t("siteTitle")} +

+

+ {t("siteSubtitle")} +

+
+
+ +
+
+ ) + } return ( -
+

{t("siteTitle")} @@ -23,10 +46,7 @@ const Page: NextPage = () => { {t("siteSubtitle")}

-
- -
-
+ ) } diff --git a/prisma/schema.prisma b/prisma/schema.prisma index ee9d092..b70584f 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -40,7 +40,14 @@ model User { username String? photoUrl String? lastAuthDate DateTime - hash String + tokens Token[] +} + +model Token { + userId BigInt + user User @relation(fields: [userId], references: [id]) + token String @id + expiresAt DateTime } /// A partecipant is a person who may or may not partecipate to the event. diff --git a/public/locales/it-IT/common.json b/public/locales/it-IT/common.json index 9e26dfe..a8ed247 100644 --- a/public/locales/it-IT/common.json +++ b/public/locales/it-IT/common.json @@ -1 +1,9 @@ -{} \ No newline at end of file +{ + "siteTitle": "Festa", + "siteSubtitle": "Organizza con facilità il tuo evento!", + "introTelegramLogin": "Per prima cosa, effettua il login con Telegram.", + "introTelegramLoggedIn": "Sei connesso come <1/>!", + "introTelegramLogout": "Non sei tu?", + "introCreateEvent": "Dai un nome al tuo primo evento:", + "introCreateEventSlugPlaceholder": "nome-evento-2022" +} diff --git a/public/locales/it-IT/common.json.disabled b/public/locales/it-IT/common.json.disabled deleted file mode 100644 index f1e29c3..0000000 --- a/public/locales/it-IT/common.json.disabled +++ /dev/null @@ -1,8 +0,0 @@ -{ - "siteTitle": "Festa", - "siteSubtitle": "Organizza il tuo evento ora!", - "introTelegramLogin": "Effettua il login con Telegram per iniziare a creare il tuo evento.", - "introTelegramLoggedIn": "Sei connesso come <1/>!", - "introTelegramLogout": "Non sei tu?", - "introCreateEvent": "" -} \ No newline at end of file diff --git a/styles/globals.css b/styles/globals.css index 2606d1a..0647813 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -1,49 +1,24 @@ -@media (prefers-color-scheme: light) { - body { - --background: #fafafa; - --foreground: black; - --border: darkgray; - - --anchor: #4444ff; - --anchor-visited: #aa44ff; - --anchor-active: #ff4444; - - --positive: #008800; - --negative: #880000; - } +* { + box-sizing: border-box; } -@media (prefers-color-scheme: dark) { - body { - --background: #050505; - --foreground: white; - --border: darkgray; - - --anchor: #8888ff; - --anchor-visited: #aa88ff; - --anchor-active: #ff8888; - - --positive: #88ff88; - --negative: #ff8888; - } +*::selection { + background-color: var(--selection); + color: var(--foreground); + text-shadow: none; } - body { padding: 0; margin: 0; background-color: var(--background); - font-family: sans-serif; color: var(--foreground); + font-family: sans-serif; text-shadow: 1px 1px 1px var(--background); } -* { - box-sizing: border-box; -} - h1, h2, h3, h4, h5, h6 { margin: 0; text-shadow: 2px 2px 2px var(--background); @@ -66,7 +41,7 @@ input, button { margin: 2px 4px; color: var(--foreground); - background-color: var(--background); + background-color: var(--interactable); border-width: 2px; border-color: var(--border); @@ -103,4 +78,9 @@ input[type="submit"]:active, button:active { .input-negative { border-color: var(--negative); color: var(--negative); -} \ No newline at end of file +} + +@import "index.css"; +@import "postcard.css"; +@import "telegram.css"; +@import "variables.css"; \ No newline at end of file diff --git a/styles/index.css b/styles/index.css index acad757..da15a28 100644 --- a/styles/index.css +++ b/styles/index.css @@ -1,4 +1,4 @@ -.index { +.page-index { display: flex; flex-direction: column; @@ -10,21 +10,21 @@ } @media only screen and (max-width: 639px) { - .index h1 { + .page-index h1 { font-size: 5rem; } - .index h2 { + .page-index h2 { font-size: 1.5rem; } } @media only screen and (min-width: 640px) { - .index h1 { + .page-index h1 { font-size: 10rem; } - .index h2 { + .page-index h2 { font-size: 2.5rem; } } \ No newline at end of file diff --git a/styles/telegram.css b/styles/telegram.css index 44f91bc..0baa5fe 100644 --- a/styles/telegram.css +++ b/styles/telegram.css @@ -1,28 +1,3 @@ -/* Taken from the Telegram widget button */ .container-btn-telegram > div { height: 40px; } - -.btn-telegram { - display: inline-block; - vertical-align: top; - font-weight: 500; - background-color: #54a9eb; - text-overflow: ellipsis; - overflow: hidden; - margin: 0; - border: none; - color: #fff; - cursor: pointer; - - font-size: 16px; - line-height: 20px; - padding: 9px 21px 11px; - border-radius: 20px; -} - -.avatar-telegram-inline { - height: 1em; - border-radius: 20px; - margin-right: 3px; -} diff --git a/styles/variables.css b/styles/variables.css new file mode 100644 index 0000000..6145ef1 --- /dev/null +++ b/styles/variables.css @@ -0,0 +1,33 @@ +/* Light theme / unsupported */ + body { + --background: #fafafa; + --foreground: black; + --border: gray; + --interactable: #fafafab5; + --selection: #7777ff; + + --anchor: #4444ff; + --anchor-visited: #aa44ff; + --anchor-active: #ff4444; + + --positive: #008800; + --negative: #880000; + } + +/* Dark theme */ +@media (prefers-color-scheme: dark) { + body { + --background: #050505; + --foreground: white; + --border: gray; + --interactable: #050505b5; + --selection: #3333dd; + + --anchor: #8888ff; + --anchor-visited: #aa88ff; + --anchor-active: #ff8888; + + --positive: #88ff88; + --negative: #ff8888; + } +} diff --git a/utils/definedContext.tsx b/utils/definedContext.ts similarity index 100% rename from utils/definedContext.tsx rename to utils/definedContext.ts diff --git a/utils/prismaClient.ts b/utils/prismaClient.ts new file mode 100644 index 0000000..47a110b --- /dev/null +++ b/utils/prismaClient.ts @@ -0,0 +1,3 @@ +import { PrismaClient } from "@prisma/client"; + +export const prisma = new PrismaClient() diff --git a/utils/stateContext.tsx b/utils/stateContext.ts similarity index 100% rename from utils/stateContext.tsx rename to utils/stateContext.ts diff --git a/utils/telegram.ts b/utils/telegram.ts index 3436082..d0aad04 100644 --- a/utils/telegram.ts +++ b/utils/telegram.ts @@ -74,6 +74,11 @@ export class LoginResponse implements LoginData { * @param queryObj The query string object, from `context.query`. */ constructor(ld: LoginData) { + if(!ld.id) throw new Error("Missing `id`") + if(!ld.first_name) throw new Error("Missing `first_name`") + if(!ld.auth_date) throw new Error("Missing `auth_date`") + if(!ld.hash) throw new Error("Missing `hash`") + this.id = ld.id this.first_name = ld.first_name this.last_name = ld.last_name diff --git a/yarn.lock b/yarn.lock index 016377b..c381969 100644 --- a/yarn.lock +++ b/yarn.lock @@ -335,11 +335,24 @@ ast-types-flow@^0.0.7: resolved "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz#f70b735c6bca1a5c9c22d982c3e39e7feba3bdad" integrity sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag== +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + axe-core@^4.3.5: version "4.4.2" resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.4.2.tgz#dcf7fb6dea866166c3eab33d68208afe4d5f670c" integrity sha512-LVAaGp/wkkgYJcjmHsoKx4juT1aQvJyPcW09MLCjVTh3V2cc6PnyempiLMNH5iMdfIX/zdbjUx2KDjMLCTdPeA== +axios@^0.27.2: + version "0.27.2" + resolved "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972" + integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== + dependencies: + follow-redirects "^1.14.9" + form-data "^4.0.0" + axobject-query@^2.2.0: version "2.2.0" resolved "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be" @@ -408,6 +421,13 @@ color-name@~1.1.4: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -423,7 +443,15 @@ core-js@^3: resolved "https://registry.npmjs.org/core-js/-/core-js-3.22.7.tgz#8d6c37f630f6139b8732d10f2c114c3f1d00024f" integrity sha512-Jt8SReuDKVNZnZEzyEQT5eK6T2RRCXkfTq7Lo09kpm+fHjgGewSbNjV+Wt4yZMhPDdzz2x1ulI5z/w4nxpBseg== -cross-spawn@^7.0.2: +cors@^2.8.5: + version "2.8.5" + resolved "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -432,6 +460,13 @@ cross-spawn@^7.0.2: shebang-command "^2.0.0" which "^2.0.1" +crypto-random-string@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-5.0.0.tgz#12b4ca8ba936c36d757b65b71a7d85a69a02c18a" + integrity sha512-KWjTXWwxFd6a94m5CdRGW/t82Tr8DoBc9dNnPCAbFI1EBweN6v1tv8y4Y1m7ndkp/nkIBRxUxAzpaBnR2k3bcQ== + dependencies: + type-fest "^2.12.2" + csstype@^3.0.2: version "3.1.0" resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2" @@ -476,6 +511,11 @@ define-properties@^1.1.3, define-properties@^1.1.4: has-property-descriptors "^1.0.0" object-keys "^1.1.1" +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + dir-glob@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" @@ -497,6 +537,26 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" +dotenv-cli@^5.1.0: + version "5.1.0" + resolved "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-5.1.0.tgz#0d2942b089082da0157f9b26bd6c5c4dd51ef48e" + integrity sha512-NoEZAlKo9WVrG0b3i9mBxdD6INdDuGqdgR74t68t8084QcI077/1MnPerRW1odl+9uULhcdnQp2U0pYVppKHOA== + dependencies: + cross-spawn "^7.0.3" + dotenv "^16.0.0" + dotenv-expand "^8.0.1" + minimist "^1.2.5" + +dotenv-expand@^8.0.1: + version "8.0.3" + resolved "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-8.0.3.tgz#29016757455bcc748469c83a19b36aaf2b83dd6e" + integrity sha512-SErOMvge0ZUyWd5B0NXMQlDkN+8r+HhVUsxgOO7IoPDOdDRD2JjExpN6y3KnFR66jsJMwSn1pqIivhU5rcJiNg== + +dotenv@^16.0.0: + version "16.0.1" + resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.0.1.tgz#8f8f9d94876c35dac989876a5d3a82a267fdce1d" + integrity sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ== + emoji-regex@^9.2.2: version "9.2.2" resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" @@ -822,6 +882,20 @@ flatted@^3.1.0: resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz#76c8584f4fc843db64702a6bd04ab7a8bd666da3" integrity sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg== +follow-redirects@^1.14.9: + version "1.15.1" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5" + integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA== + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -1234,6 +1308,18 @@ micromatch@^4.0.4: braces "^3.0.2" picomatch "^2.3.1" +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -1241,7 +1327,7 @@ minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" -minimist@^1.2.0, minimist@^1.2.6: +minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: version "1.2.6" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== @@ -1307,7 +1393,7 @@ next@12.1.6: "@next/swc-win32-ia32-msvc" "12.1.6" "@next/swc-win32-x64-msvc" "12.1.6" -object-assign@^4.1.1: +object-assign@^4, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= @@ -1713,6 +1799,11 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +swr@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/swr/-/swr-1.3.0.tgz#c6531866a35b4db37b38b72c45a63171faf9f4e8" + integrity sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw== + text-table@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -1759,6 +1850,11 @@ type-fest@^0.20.2: resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== +type-fest@^2.12.2: + version "2.13.0" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-2.13.0.tgz#d1ecee38af29eb2e863b22299a3d68ef30d2abfb" + integrity sha512-lPfAm42MxE4/456+QyIaaVBAwgpJb6xZ8PRu09utnhPdWwcyj9vgy6Sq0Z5yNbJ21EdxB5dRU/Qg8bsyAMtlcw== + typescript@4.6.4: version "4.6.4" resolved "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz#caa78bbc3a59e6a5c510d35703f6a09877ce45e9" @@ -1786,6 +1882,11 @@ v8-compile-cache@^2.0.3: resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== +vary@^1: + version "1.1.2" + resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + void-elements@3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09"