Using next-auth
This commit is contained in:
parent
b9e72b2a32
commit
dab3abdda2
50 changed files with 656 additions and 1525 deletions
|
@ -28,15 +28,15 @@ function LobbyFrame({ openSettings }: { openSettings: () => void }) {
|
||||||
<div className="flex items-center justify-around">
|
<div className="flex items-center justify-around">
|
||||||
<Player
|
<Player
|
||||||
src="player_blue.png"
|
src="player_blue.png"
|
||||||
text={gameProps.player?.username ?? "Spieler 1 (Du)"}
|
text={gameProps.player?.name ?? "Spieler 1 (Du)"}
|
||||||
primary={true}
|
primary={true}
|
||||||
edit={true}
|
edit={true}
|
||||||
/>
|
/>
|
||||||
<p className="font-farro m-4 text-6xl font-semibold">VS</p>
|
<p className="font-farro m-4 text-6xl font-semibold">VS</p>
|
||||||
{enemy ? (
|
{enemy ? (
|
||||||
<Player src="player_red.png" text={enemy.username ?? "Spieler 2"} />
|
<Player src="player_red.png" text={enemy.name ?? "Spieler 2"} />
|
||||||
) : (
|
) : (
|
||||||
<p className="font-farro w-96 text-center text-5xl font-medium">
|
<p className="font-farro w-96 text-center text-4xl font-medium">
|
||||||
Warte auf Spieler 2 {Array.from(Array(dots), () => ".").join("")}
|
Warte auf Spieler 2 {Array.from(Array(dots), () => ".").join("")}
|
||||||
{Array.from(Array(3 - dots), (_, i) => (
|
{Array.from(Array(3 - dots), (_, i) => (
|
||||||
<Fragment key={i}> </Fragment>
|
<Fragment key={i}> </Fragment>
|
||||||
|
|
|
@ -2,21 +2,32 @@ import {
|
||||||
FontAwesomeIcon,
|
FontAwesomeIcon,
|
||||||
FontAwesomeIconProps,
|
FontAwesomeIconProps,
|
||||||
} from "@fortawesome/react-fontawesome"
|
} from "@fortawesome/react-fontawesome"
|
||||||
|
import classNames from "classnames"
|
||||||
import { ReactNode } from "react"
|
import { ReactNode } from "react"
|
||||||
|
|
||||||
function OptionButton({
|
function OptionButton({
|
||||||
icon,
|
icon,
|
||||||
action,
|
action,
|
||||||
children,
|
children,
|
||||||
|
disabled,
|
||||||
}: {
|
}: {
|
||||||
icon: FontAwesomeIconProps["icon"]
|
icon: FontAwesomeIconProps["icon"]
|
||||||
action?: () => void
|
action?: () => void
|
||||||
children: ReactNode
|
children: ReactNode
|
||||||
|
disabled?: boolean
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
className="flex w-full flex-row items-center justify-between rounded-xl border-b-4 border-shield-gray bg-voidDark py-2 pl-8 pr-4 text-lg text-grayish duration-100 first:mt-4 last:mt-4 active:border-b-0 active:border-t-4 sm:py-4 sm:pl-16 sm:pr-8 sm:text-4xl sm:first:mt-8 sm:last:mt-8"
|
className={classNames(
|
||||||
|
"flex w-full flex-row items-center justify-between rounded-xl py-2 pl-8 pr-4 text-lg text-grayish duration-100 first:mt-4 last:mt-4 sm:py-4 sm:pl-16 sm:pr-8 sm:text-4xl sm:first:mt-8 sm:last:mt-8",
|
||||||
|
{
|
||||||
|
"bg-voidDark border-shield-gray border-b-4 active:border-b-0 active:border-t-4":
|
||||||
|
!disabled,
|
||||||
|
"bg-red-950 border-slate-600 border-4 border-dashed": disabled,
|
||||||
|
}
|
||||||
|
)}
|
||||||
onClick={() => action && setTimeout(action, 200)}
|
onClick={() => action && setTimeout(action, 200)}
|
||||||
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
<span className="mx-auto">{children}</span>
|
<span className="mx-auto">{children}</span>
|
||||||
<FontAwesomeIcon
|
<FontAwesomeIcon
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
import { rejectionErrors } from "../errors"
|
|
||||||
import sendError, { API } from "./sendError"
|
|
||||||
import type { Player } from "@prisma/client"
|
|
||||||
import bcrypt from "bcrypt"
|
|
||||||
|
|
||||||
export default async function checkPasswordIsValid<T>(
|
|
||||||
context: API<T>,
|
|
||||||
player: Player,
|
|
||||||
password: string
|
|
||||||
) {
|
|
||||||
// Validate for correct password
|
|
||||||
const result = await bcrypt.compare(password, player.passwordHash ?? "")
|
|
||||||
if (!result) throw sendError(context, rejectionErrors.wrongPassword)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
import { rejectionErrorFns } from "../errors"
|
|
||||||
import jwtVerifyCatch from "../jwtVerifyCatch"
|
|
||||||
import type { IdToken, RawToken } from "./createTokenDB"
|
|
||||||
import sendError, { API } from "./sendError"
|
|
||||||
import jwt from "jsonwebtoken"
|
|
||||||
|
|
||||||
async function checkTokenIsValid<T>(context: API<T>, rawToken: RawToken) {
|
|
||||||
const { value, type } = rawToken
|
|
||||||
|
|
||||||
// Verify the token and get the payload
|
|
||||||
let data: string | jwt.JwtPayload
|
|
||||||
try {
|
|
||||||
data = jwt.verify(value, process.env.TOKEN_SECRET as string)
|
|
||||||
} catch (err: any) {
|
|
||||||
// Deal with the problem in more detail
|
|
||||||
throw sendError(context, jwtVerifyCatch(type, err))
|
|
||||||
}
|
|
||||||
// Making sure the token data is not a string (because it should be an object)
|
|
||||||
if (typeof data === "string")
|
|
||||||
throw sendError(context, rejectionErrorFns.tokenWasString(type, value))
|
|
||||||
|
|
||||||
return { id: data.id, type }
|
|
||||||
}
|
|
||||||
|
|
||||||
export default checkTokenIsValid
|
|
|
@ -1,12 +0,0 @@
|
||||||
import prisma from "../../prisma"
|
|
||||||
import logging from "../logging"
|
|
||||||
import type { Player } from "@prisma/client"
|
|
||||||
|
|
||||||
async function createPlayerDB() {
|
|
||||||
const player = await prisma.player.create({ data: {} })
|
|
||||||
logging("Anonymous player created: " + player.id, ["debug"])
|
|
||||||
|
|
||||||
return player
|
|
||||||
}
|
|
||||||
|
|
||||||
export default createPlayerDB
|
|
|
@ -1,44 +0,0 @@
|
||||||
import prisma from "../../prisma"
|
|
||||||
import type { Player, Token, TokenType } from "@prisma/client"
|
|
||||||
import jwt from "jsonwebtoken"
|
|
||||||
|
|
||||||
export interface RawToken {
|
|
||||||
value: string
|
|
||||||
type: TokenType
|
|
||||||
}
|
|
||||||
export interface IdToken {
|
|
||||||
id: string
|
|
||||||
type: TokenType
|
|
||||||
}
|
|
||||||
|
|
||||||
export const tokenLifetime = {
|
|
||||||
REFRESH: 172800,
|
|
||||||
ACCESS: 15,
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function createTokenDB(
|
|
||||||
player: Player,
|
|
||||||
newTokenType: TokenType
|
|
||||||
) {
|
|
||||||
// Create token entry in DB
|
|
||||||
const newTokenDB = await prisma.token.create({
|
|
||||||
data: {
|
|
||||||
type: newTokenType,
|
|
||||||
// expires: new Date(Date.now() + tokenLifetime[newTokenType] + "000"),
|
|
||||||
owner: {
|
|
||||||
connect: {
|
|
||||||
id: player.id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
// Sign a new access token
|
|
||||||
const newToken = jwt.sign(
|
|
||||||
{ id: newTokenDB.id },
|
|
||||||
process.env.TOKEN_SECRET as string,
|
|
||||||
{ expiresIn: tokenLifetime[newTokenType] }
|
|
||||||
)
|
|
||||||
|
|
||||||
return { newToken: { value: newToken, type: newTokenType }, newTokenDB }
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
import { rejectionErrorFns } from "../errors"
|
|
||||||
import jwtVerifyCatch from "../jwtVerifyCatch"
|
|
||||||
import logging from "../logging"
|
|
||||||
import type { IdToken, RawToken } from "./createTokenDB"
|
|
||||||
import sendError, { API } from "./sendError"
|
|
||||||
import jwt from "jsonwebtoken"
|
|
||||||
|
|
||||||
async function decodeToken<T>(context: API<T>, rawToken: RawToken) {
|
|
||||||
const { value, type } = rawToken
|
|
||||||
|
|
||||||
// Verify the token and get the payload
|
|
||||||
let data: string | jwt.JwtPayload
|
|
||||||
try {
|
|
||||||
data = jwt.verify(value, process.env.TOKEN_SECRET as string)
|
|
||||||
} catch (err: any) {
|
|
||||||
// Deal with the problem in more detail
|
|
||||||
logging(jwtVerifyCatch(type, err).message, ["error"])
|
|
||||||
const fallbackData = jwt.decode(value)
|
|
||||||
// Making sure the token data is not a string (because it should be an object)
|
|
||||||
if (typeof fallbackData === "string")
|
|
||||||
throw sendError(context, rejectionErrorFns.tokenWasString(type, value))
|
|
||||||
return { id: fallbackData?.id, type }
|
|
||||||
}
|
|
||||||
// Making sure the token data is not a string (because it should be an object)
|
|
||||||
if (typeof data === "string")
|
|
||||||
throw sendError(context, rejectionErrorFns.tokenWasString(type, value))
|
|
||||||
|
|
||||||
return { id: data.id, type }
|
|
||||||
}
|
|
||||||
|
|
||||||
export default decodeToken
|
|
|
@ -1,15 +0,0 @@
|
||||||
import checkTokenIsValid from "./checkTokenIsValid"
|
|
||||||
import getPlayerByIdDB from "./getPlayerByIdDB"
|
|
||||||
import getTokenDB from "./getTokenDB"
|
|
||||||
import getTokenFromBody from "./getTokenFromBody"
|
|
||||||
import { API } from "./sendError"
|
|
||||||
|
|
||||||
async function getPlayer<T>(context: API<T>) {
|
|
||||||
const accessToken = await getTokenFromBody(context)
|
|
||||||
const token = await checkTokenIsValid(context, accessToken)
|
|
||||||
const tokenDB = await getTokenDB(context, token)
|
|
||||||
const player = await getPlayerByIdDB(context, tokenDB)
|
|
||||||
return { player, tokenDB }
|
|
||||||
}
|
|
||||||
|
|
||||||
export default getPlayer
|
|
|
@ -1,21 +0,0 @@
|
||||||
import prisma from "../../prisma"
|
|
||||||
import { rejectionErrors } from "../errors"
|
|
||||||
import sendError, { API } from "./sendError"
|
|
||||||
import type { Player, Token } from "@prisma/client"
|
|
||||||
|
|
||||||
export default async function getPlayerByIdDB<T>(
|
|
||||||
context: API<T>,
|
|
||||||
tokenDB: Token
|
|
||||||
) {
|
|
||||||
// Find Host in DB if it still exists (just to make sure)
|
|
||||||
const player = await prisma.player.findUnique({
|
|
||||||
where: {
|
|
||||||
id: tokenDB.ownerId,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if (!player) {
|
|
||||||
throw sendError(context, rejectionErrors.playerNotFound)
|
|
||||||
}
|
|
||||||
|
|
||||||
return player
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
import prisma from "../../prisma"
|
|
||||||
import { rejectionErrors } from "../errors"
|
|
||||||
import sendError, { API } from "./sendError"
|
|
||||||
import type { Player } from "@prisma/client"
|
|
||||||
|
|
||||||
export default async function getPlayerByNameDB<T>(
|
|
||||||
context: API<T>,
|
|
||||||
username: string
|
|
||||||
) {
|
|
||||||
// Find Player in DB if it still exists (just to make sure)
|
|
||||||
const player = await Promise.any([
|
|
||||||
prisma.player.findUniqueOrThrow({
|
|
||||||
where: {
|
|
||||||
username: username,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
prisma.player.findUniqueOrThrow({
|
|
||||||
where: {
|
|
||||||
email: username,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
]).catch(() => null)
|
|
||||||
if (player === null) throw sendError(context, rejectionErrors.playerNotFound)
|
|
||||||
|
|
||||||
return player
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
import prisma from "../../prisma"
|
|
||||||
import { rejectionErrorFns, rejectionErrors } from "../errors"
|
|
||||||
import type { IdToken } from "./createTokenDB"
|
|
||||||
import sendError, { API } from "./sendError"
|
|
||||||
import { deleteCookie } from "cookies-next"
|
|
||||||
|
|
||||||
async function getTokenDB<T>(
|
|
||||||
context: API<T>,
|
|
||||||
token: IdToken,
|
|
||||||
|
|
||||||
ignoreChecks?: boolean
|
|
||||||
) {
|
|
||||||
const { id, type } = token
|
|
||||||
// Find refresh token in DB
|
|
||||||
const tokenDB = await prisma.token.findUnique({
|
|
||||||
where: {
|
|
||||||
id,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if (!tokenDB) {
|
|
||||||
deleteCookie("token", { ...context, path: "/api" })
|
|
||||||
throw sendError(context, rejectionErrorFns.tokenNotFound(type))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tokenDB.used && !ignoreChecks)
|
|
||||||
throw sendError(context, rejectionErrors.tokenUsed)
|
|
||||||
|
|
||||||
await prisma.token.update({
|
|
||||||
where: {
|
|
||||||
id,
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
used: type === "ACCESS",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
// await logging('Old token has been invalidated.', ['debug'], req)
|
|
||||||
|
|
||||||
return tokenDB
|
|
||||||
}
|
|
||||||
|
|
||||||
export default getTokenDB
|
|
|
@ -1,23 +0,0 @@
|
||||||
import { rejectionErrorFns } from "../errors"
|
|
||||||
import type { RawToken } from "./createTokenDB"
|
|
||||||
import sendError, { API } from "./sendError"
|
|
||||||
|
|
||||||
async function getTokenFromBody<T>(context: API<T>): Promise<RawToken> {
|
|
||||||
const type = "ACCESS"
|
|
||||||
const body = JSON.parse(context.req.body)
|
|
||||||
// Checking for cookie presens, because it is necessary
|
|
||||||
if (
|
|
||||||
typeof body === "object" &&
|
|
||||||
body &&
|
|
||||||
"token" in body &&
|
|
||||||
typeof body.token === "string"
|
|
||||||
) {
|
|
||||||
const value = body.token
|
|
||||||
return { value, type }
|
|
||||||
}
|
|
||||||
console.log(body)
|
|
||||||
|
|
||||||
throw sendError(context, rejectionErrorFns.noToken(type))
|
|
||||||
}
|
|
||||||
|
|
||||||
export default getTokenFromBody
|
|
|
@ -1,31 +0,0 @@
|
||||||
import createPlayerDB from "./createPlayerDB"
|
|
||||||
import createTokenDB, { RawToken } from "./createTokenDB"
|
|
||||||
import type { API } from "./sendError"
|
|
||||||
import { Player, Token } from "@prisma/client"
|
|
||||||
|
|
||||||
interface Returning {
|
|
||||||
refreshToken: RawToken
|
|
||||||
newPlayer?: { player: Player; newToken: RawToken; newTokenDB: Token }
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getTokenFromCookie<T>(context: API<T>): Promise<Returning> {
|
|
||||||
const type = "REFRESH"
|
|
||||||
const value = context.req.cookies.token
|
|
||||||
|
|
||||||
// Checking for cookie presens, because it is necessary
|
|
||||||
if (!value) {
|
|
||||||
const player = await createPlayerDB()
|
|
||||||
const { newToken, newTokenDB } = await createTokenDB(player, type)
|
|
||||||
return {
|
|
||||||
refreshToken: newToken,
|
|
||||||
newPlayer: {
|
|
||||||
player,
|
|
||||||
newToken,
|
|
||||||
newTokenDB,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return { refreshToken: { value, type } }
|
|
||||||
}
|
|
||||||
|
|
||||||
export default getTokenFromCookie
|
|
|
@ -1,21 +0,0 @@
|
||||||
import { rejectionErrors } from "../errors"
|
|
||||||
import sendError, { API } from "./sendError"
|
|
||||||
|
|
||||||
async function getUserFromBody<T>(context: API<T>) {
|
|
||||||
const body = JSON.parse(context.req.body)
|
|
||||||
if (
|
|
||||||
typeof body !== "object" ||
|
|
||||||
!body ||
|
|
||||||
!("username" in body) ||
|
|
||||||
typeof body.username !== "string"
|
|
||||||
)
|
|
||||||
throw sendError(context, rejectionErrors.noUsername)
|
|
||||||
const { username } = body
|
|
||||||
if (!("password" in body) || typeof body.password !== "string")
|
|
||||||
throw sendError(context, rejectionErrors.noPassword)
|
|
||||||
const { password } = body
|
|
||||||
|
|
||||||
return { username, password }
|
|
||||||
}
|
|
||||||
|
|
||||||
export default getUserFromBody
|
|
|
@ -1,41 +0,0 @@
|
||||||
import logging, { Logging } from "../logging"
|
|
||||||
import { RawToken, tokenLifetime } from "./createTokenDB"
|
|
||||||
import type { API } from "./sendError"
|
|
||||||
import { deleteCookie, setCookie } from "cookies-next"
|
|
||||||
|
|
||||||
export interface Result<T> {
|
|
||||||
message: string
|
|
||||||
statusCode?: number
|
|
||||||
body?: T
|
|
||||||
type?: Logging[]
|
|
||||||
cookie?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function sendResponse<T>(context: API<T>, result: Result<T>) {
|
|
||||||
const { req, res } = context
|
|
||||||
if (typeof result.cookie === "string") {
|
|
||||||
if (result.cookie) {
|
|
||||||
console.log(1)
|
|
||||||
setCookie("token", result.cookie, {
|
|
||||||
req,
|
|
||||||
res,
|
|
||||||
maxAge: tokenLifetime.REFRESH,
|
|
||||||
httpOnly: true,
|
|
||||||
sameSite: true,
|
|
||||||
secure: true,
|
|
||||||
path: "/api",
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
console.log(2)
|
|
||||||
deleteCookie("token", {
|
|
||||||
req,
|
|
||||||
res,
|
|
||||||
path: "/api",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res.status(result.statusCode ?? 200)
|
|
||||||
result.body ? res.json(result.body) : res.end()
|
|
||||||
logging(result.message, result.type ?? ["debug"], req)
|
|
||||||
return "done" as const
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
import prisma from "../../prisma"
|
|
||||||
import { rejectionErrors } from "../errors"
|
|
||||||
import sendError, { API } from "./sendError"
|
|
||||||
import type { Player, Prisma } from "@prisma/client"
|
|
||||||
|
|
||||||
async function updatePlayerDB<T>(
|
|
||||||
context: API<T>,
|
|
||||||
player: Player,
|
|
||||||
data: Prisma.PlayerUpdateInput
|
|
||||||
) {
|
|
||||||
if (!player.anonymous) throw sendError(context, rejectionErrors.registered)
|
|
||||||
const updatedPlayer = await prisma.player.update({
|
|
||||||
where: { id: player.id },
|
|
||||||
data,
|
|
||||||
})
|
|
||||||
|
|
||||||
return updatedPlayer
|
|
||||||
}
|
|
||||||
|
|
||||||
export default updatePlayerDB
|
|
|
@ -1,106 +1,71 @@
|
||||||
import { Logging } from "./logging"
|
import { Logging } from "./logging"
|
||||||
import { TokenType } from "@prisma/client"
|
|
||||||
|
|
||||||
export interface rejectionError {
|
export interface rejectionError {
|
||||||
rejected?: boolean
|
|
||||||
message: string
|
message: string
|
||||||
statusCode: number
|
statusCode: number
|
||||||
solved: boolean
|
solved: boolean
|
||||||
type?: Logging
|
type?: Logging[]
|
||||||
}
|
}
|
||||||
interface rejectionErrors {
|
interface rejectionErrors {
|
||||||
[key: string]: rejectionError
|
[key: string]: rejectionError
|
||||||
}
|
}
|
||||||
interface rejectionErrorFns {
|
|
||||||
[key: string]: (...args: any[]) => rejectionError
|
|
||||||
}
|
|
||||||
|
|
||||||
export const rejectionErrors: rejectionErrors = {
|
export const rejectionErrors: rejectionErrors = {
|
||||||
noCookie: {
|
noCookie: {
|
||||||
rejected: true,
|
|
||||||
message: "Unauthorized. No cookie.",
|
message: "Unauthorized. No cookie.",
|
||||||
statusCode: 401,
|
statusCode: 401,
|
||||||
solved: true,
|
solved: true,
|
||||||
},
|
},
|
||||||
noBody: {
|
noBody: {
|
||||||
rejected: true,
|
|
||||||
message: "Unauthorized. No Body.",
|
message: "Unauthorized. No Body.",
|
||||||
statusCode: 401,
|
statusCode: 401,
|
||||||
solved: true,
|
solved: true,
|
||||||
type: "warn",
|
type: ["warn"],
|
||||||
},
|
},
|
||||||
noUsername: {
|
noUsername: {
|
||||||
rejected: true,
|
|
||||||
message: "No username in request body!",
|
message: "No username in request body!",
|
||||||
statusCode: 401,
|
statusCode: 401,
|
||||||
solved: true,
|
solved: true,
|
||||||
type: "warn",
|
type: ["warn"],
|
||||||
},
|
},
|
||||||
noPassword: {
|
noPassword: {
|
||||||
rejected: true,
|
|
||||||
message: "No password in request body!",
|
message: "No password in request body!",
|
||||||
statusCode: 401,
|
statusCode: 401,
|
||||||
solved: true,
|
solved: true,
|
||||||
type: "warn",
|
type: ["warn"],
|
||||||
},
|
},
|
||||||
wrongPassword: {
|
wrongPassword: {
|
||||||
message: "Passwords do not match!",
|
message: "Passwords do not match!",
|
||||||
statusCode: 401,
|
statusCode: 401,
|
||||||
solved: true,
|
solved: true,
|
||||||
type: "warn",
|
type: ["warn"],
|
||||||
},
|
},
|
||||||
playerNotFound: {
|
playerNotFound: {
|
||||||
message: "Player name not found in DB!",
|
message: "Player name not found in DB!",
|
||||||
statusCode: 401,
|
statusCode: 401,
|
||||||
solved: false,
|
solved: false,
|
||||||
type: "warn",
|
type: ["warn"],
|
||||||
},
|
},
|
||||||
tokenUsed: {
|
tokenUsed: {
|
||||||
rejected: true,
|
|
||||||
message: "DBToken was already used!",
|
message: "DBToken was already used!",
|
||||||
statusCode: 401,
|
statusCode: 401,
|
||||||
solved: true,
|
solved: true,
|
||||||
type: "warn",
|
type: ["warn"],
|
||||||
},
|
},
|
||||||
registered: {
|
registered: {
|
||||||
rejected: true,
|
|
||||||
message: "Player is already registered!",
|
message: "Player is already registered!",
|
||||||
statusCode: 403,
|
statusCode: 403,
|
||||||
solved: true,
|
solved: true,
|
||||||
type: "warn",
|
type: ["warn"],
|
||||||
},
|
},
|
||||||
gameNotFound: {
|
gameNotFound: {
|
||||||
rejected: true,
|
|
||||||
message: "Game not found!",
|
message: "Game not found!",
|
||||||
statusCode: 403,
|
statusCode: 403,
|
||||||
solved: true,
|
solved: true,
|
||||||
},
|
},
|
||||||
}
|
unauthorized: {
|
||||||
|
message: "Unauthorized",
|
||||||
export const rejectionErrorFns: rejectionErrorFns = {
|
statusCode: 401,
|
||||||
tokenWasString(tokenType: TokenType, tokenValue: string) {
|
solved: true,
|
||||||
return {
|
|
||||||
rejected: true,
|
|
||||||
message: `${tokenType}-Token data was a string. Token: ${tokenValue}`,
|
|
||||||
statusCode: 401,
|
|
||||||
solved: false,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
tokenNotFound(tokenType: TokenType) {
|
|
||||||
return {
|
|
||||||
rejected: true,
|
|
||||||
message: `${tokenType}-Token not found in DB!`,
|
|
||||||
statusCode: 401,
|
|
||||||
solved: true,
|
|
||||||
type: "warn",
|
|
||||||
}
|
|
||||||
},
|
|
||||||
noToken(tokenType: TokenType) {
|
|
||||||
return {
|
|
||||||
rejected: true,
|
|
||||||
message: `Unauthorized. No ${tokenType}-Token.`,
|
|
||||||
statusCode: 401,
|
|
||||||
solved: true,
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,15 @@
|
||||||
import sendError, { API } from "./sendError"
|
import sendError from "./sendError"
|
||||||
|
import { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
|
||||||
async function getPinFromBody<T>(context: API<T>) {
|
async function getPinFromBody<T>(req: NextApiRequest, res: NextApiResponse<T>) {
|
||||||
const body = JSON.parse(context.req.body)
|
const body = JSON.parse(req.body)
|
||||||
if (
|
if (
|
||||||
typeof body !== "object" ||
|
typeof body !== "object" ||
|
||||||
!body ||
|
!body ||
|
||||||
!("pin" in body) ||
|
!("pin" in body) ||
|
||||||
typeof body.pin !== "string"
|
typeof body.pin !== "string"
|
||||||
)
|
)
|
||||||
throw sendError(context, {
|
throw sendError(req, res, {
|
||||||
rejected: true,
|
rejected: true,
|
||||||
message: "No pin in request body!",
|
message: "No pin in request body!",
|
||||||
statusCode: 401,
|
statusCode: 401,
|
|
@ -2,16 +2,11 @@ import type { rejectionError } from "../errors"
|
||||||
import logging from "../logging"
|
import logging from "../logging"
|
||||||
import type { NextApiRequest, NextApiResponse } from "next"
|
import type { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
|
||||||
export interface API<T> {
|
|
||||||
req: NextApiRequest
|
|
||||||
res: NextApiResponse<T>
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function sendError<T>(
|
export default function sendError<T>(
|
||||||
context: API<T>,
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse<T>,
|
||||||
err: rejectionError | Error
|
err: rejectionError | Error
|
||||||
) {
|
) {
|
||||||
const { res, req } = context
|
|
||||||
// If something went wrong, let the client know with status 500
|
// If something went wrong, let the client know with status 500
|
||||||
res.status("statusCode" in err ? err.statusCode : 500).end()
|
res.status("statusCode" in err ? err.statusCode : 500).end()
|
||||||
logging(
|
logging(
|
20
leaky-ships/lib/backend/sendResponse.ts
Normal file
20
leaky-ships/lib/backend/sendResponse.ts
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
import logging, { Logging } from "../logging"
|
||||||
|
import { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
|
||||||
|
export interface Result<T> {
|
||||||
|
message: string
|
||||||
|
statusCode?: number
|
||||||
|
body?: T
|
||||||
|
type?: Logging[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function sendResponse<T>(
|
||||||
|
req: NextApiRequest,
|
||||||
|
res: NextApiResponse<T>,
|
||||||
|
result: Result<T>
|
||||||
|
) {
|
||||||
|
res.status(result.statusCode ?? 200)
|
||||||
|
result.body ? res.json(result.body) : res.end()
|
||||||
|
logging(result.message, result.type ?? ["debug"], req)
|
||||||
|
return "done" as const
|
||||||
|
}
|
|
@ -1,42 +0,0 @@
|
||||||
import status from "http-status"
|
|
||||||
import { toast } from "react-toastify"
|
|
||||||
import { ZodError, z } from "zod"
|
|
||||||
|
|
||||||
const tokenSchema = z.object({
|
|
||||||
token: z.string(),
|
|
||||||
})
|
|
||||||
|
|
||||||
export function successfulResponse(res: Response) {
|
|
||||||
if (status[`${res.status}_CLASS`] === status.classes.SUCCESSFUL)
|
|
||||||
return res.json()
|
|
||||||
|
|
||||||
const resStatus = status[`${res.status}_CLASS`]
|
|
||||||
if (typeof resStatus !== "string") return
|
|
||||||
|
|
||||||
toast(status.classes[resStatus] + ": " + status[res.status], {
|
|
||||||
position: "top-center",
|
|
||||||
type: "error",
|
|
||||||
theme: "colored",
|
|
||||||
})
|
|
||||||
return Promise.reject()
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getAccessToken() {
|
|
||||||
return fetch("/api/user/auth", {
|
|
||||||
method: "GET",
|
|
||||||
})
|
|
||||||
.then(successfulResponse)
|
|
||||||
.then((response) => {
|
|
||||||
try {
|
|
||||||
const { token } = tokenSchema.parse(response)
|
|
||||||
|
|
||||||
return token
|
|
||||||
} catch (err: any) {
|
|
||||||
const error = err as ZodError
|
|
||||||
toast(JSON.stringify(error))
|
|
||||||
return Promise.reject()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export default getAccessToken
|
|
30
leaky-ships/lib/hooks/useGameState.tsx
Normal file
30
leaky-ships/lib/hooks/useGameState.tsx
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import { gameContext } from "../../pages/_app"
|
||||||
|
import { useSession } from "next-auth/react"
|
||||||
|
import { useContext, useEffect } from "react"
|
||||||
|
import { toast } from "react-toastify"
|
||||||
|
|
||||||
|
function useGameState() {
|
||||||
|
const [gameProps, setGameProps] = useContext(gameContext)
|
||||||
|
const { data: session, status } = useSession()
|
||||||
|
useEffect(() => {
|
||||||
|
if (!session) return
|
||||||
|
toast(session.user.email, {
|
||||||
|
toastId: "user",
|
||||||
|
position: "top-center",
|
||||||
|
icon: session.user.image ? (
|
||||||
|
<img
|
||||||
|
style={{ transform: "scale(1.5)", borderRadius: "100%" }}
|
||||||
|
src={session.user.image}
|
||||||
|
/>
|
||||||
|
) : undefined,
|
||||||
|
})
|
||||||
|
}, [session])
|
||||||
|
return {
|
||||||
|
gameProps,
|
||||||
|
setGameProps,
|
||||||
|
session,
|
||||||
|
status,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default useGameState
|
23
leaky-ships/lib/zodSchemas.ts
Normal file
23
leaky-ships/lib/zodSchemas.ts
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import { z } from "zod"
|
||||||
|
|
||||||
|
export const createSchema = z.object({
|
||||||
|
game: z.object({
|
||||||
|
id: z.string(),
|
||||||
|
createdAt: z.date(),
|
||||||
|
updatedAt: z.date(),
|
||||||
|
running: z.boolean(),
|
||||||
|
}),
|
||||||
|
pin: z.string().optional(),
|
||||||
|
player: z.object({
|
||||||
|
id: z.string(),
|
||||||
|
name: z.string().optional(),
|
||||||
|
isOwner: z.boolean().optional(),
|
||||||
|
}),
|
||||||
|
enemy: z
|
||||||
|
.object({
|
||||||
|
id: z.string(),
|
||||||
|
username: z.string().optional(),
|
||||||
|
isOwner: z.boolean().optional(),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
|
})
|
|
@ -17,17 +17,17 @@
|
||||||
"@fortawesome/pro-thin-svg-icons": "^6.4.0",
|
"@fortawesome/pro-thin-svg-icons": "^6.4.0",
|
||||||
"@fortawesome/react-fontawesome": "^0.2.0",
|
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||||
"@fortawesome/sharp-solid-svg-icons": "^6.4.0",
|
"@fortawesome/sharp-solid-svg-icons": "^6.4.0",
|
||||||
|
"@next-auth/prisma-adapter": "^1.0.6",
|
||||||
"@next/font": "13.1.1",
|
"@next/font": "13.1.1",
|
||||||
"@prisma/client": "^4.12.0",
|
"@prisma/client": "^4.12.0",
|
||||||
"bcrypt": "^5.1.0",
|
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
"colors": "^1.4.0",
|
"colors": "^1.4.0",
|
||||||
"cookies-next": "^2.1.1",
|
|
||||||
"eslint": "8.31.0",
|
"eslint": "8.31.0",
|
||||||
"eslint-config-next": "13.1.1",
|
"eslint-config-next": "13.1.1",
|
||||||
"http-status": "^1.6.2",
|
"http-status": "^1.6.2",
|
||||||
"jsonwebtoken": "^9.0.0",
|
|
||||||
"next": "13.1.1",
|
"next": "13.1.1",
|
||||||
|
"next-auth": "^4.22.1",
|
||||||
|
"nodemailer": "^6.9.1",
|
||||||
"prisma": "^4.12.0",
|
"prisma": "^4.12.0",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
|
@ -36,13 +36,12 @@
|
||||||
"socket.io": "^4.6.1",
|
"socket.io": "^4.6.1",
|
||||||
"socket.io-client": "^4.6.1",
|
"socket.io-client": "^4.6.1",
|
||||||
"typescript": "4.9.4",
|
"typescript": "4.9.4",
|
||||||
|
"unique-names-generator": "^4.7.1",
|
||||||
"zod": "^3.21.4"
|
"zod": "^3.21.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@total-typescript/ts-reset": "^0.3.7",
|
"@total-typescript/ts-reset": "^0.3.7",
|
||||||
"@trivago/prettier-plugin-sort-imports": "^4.1.1",
|
"@trivago/prettier-plugin-sort-imports": "^4.1.1",
|
||||||
"@types/bcrypt": "^5.0.0",
|
|
||||||
"@types/jsonwebtoken": "^9.0.1",
|
|
||||||
"@types/node": "^18.15.11",
|
"@types/node": "^18.15.11",
|
||||||
"@types/react": "^18.0.33",
|
"@types/react": "^18.0.33",
|
||||||
"@types/react-dom": "^18.0.11",
|
"@types/react-dom": "^18.0.11",
|
||||||
|
|
|
@ -2,6 +2,7 @@ import "../styles/App.scss"
|
||||||
import "../styles/globals.css"
|
import "../styles/globals.css"
|
||||||
import "../styles/grid2.scss"
|
import "../styles/grid2.scss"
|
||||||
import "../styles/grid.scss"
|
import "../styles/grid.scss"
|
||||||
|
import { SessionProvider } from "next-auth/react"
|
||||||
import type { AppProps } from "next/app"
|
import type { AppProps } from "next/app"
|
||||||
import { Dispatch, SetStateAction, createContext, useState } from "react"
|
import { Dispatch, SetStateAction, createContext, useState } from "react"
|
||||||
import { ToastContainer } from "react-toastify"
|
import { ToastContainer } from "react-toastify"
|
||||||
|
@ -14,12 +15,12 @@ interface gameContext {
|
||||||
}
|
}
|
||||||
player?: {
|
player?: {
|
||||||
id: string
|
id: string
|
||||||
username?: string
|
name?: string
|
||||||
isOwner?: boolean
|
isOwner?: boolean
|
||||||
}
|
}
|
||||||
enemy?: {
|
enemy?: {
|
||||||
id: string
|
id: string
|
||||||
username?: string
|
name?: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,12 +28,17 @@ export const gameContext = createContext<
|
||||||
[gameContext, Dispatch<SetStateAction<gameContext>>]
|
[gameContext, Dispatch<SetStateAction<gameContext>>]
|
||||||
>([{}, () => {}])
|
>([{}, () => {}])
|
||||||
|
|
||||||
export default function App({ Component, pageProps }: AppProps) {
|
export default function App({
|
||||||
|
Component,
|
||||||
|
pageProps: { session, ...pageProps },
|
||||||
|
}: AppProps) {
|
||||||
const gameProps = useState<gameContext>({})
|
const gameProps = useState<gameContext>({})
|
||||||
return (
|
return (
|
||||||
<gameContext.Provider value={gameProps}>
|
<SessionProvider session={session}>
|
||||||
<Component {...pageProps} />
|
<gameContext.Provider value={gameProps}>
|
||||||
<ToastContainer />
|
<Component {...pageProps} />
|
||||||
</gameContext.Provider>
|
<ToastContainer />
|
||||||
|
</gameContext.Provider>
|
||||||
|
</SessionProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
59
leaky-ships/pages/api/auth/[...nextauth].ts
Normal file
59
leaky-ships/pages/api/auth/[...nextauth].ts
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import prisma from "@lib/prisma"
|
||||||
|
import { PrismaAdapter } from "@next-auth/prisma-adapter"
|
||||||
|
import { NextApiHandler } from "next"
|
||||||
|
import NextAuth, { NextAuthOptions } from "next-auth"
|
||||||
|
import AzureADProvider from "next-auth/providers/azure-ad"
|
||||||
|
import EmailProvider from "next-auth/providers/email"
|
||||||
|
import {
|
||||||
|
uniqueNamesGenerator,
|
||||||
|
Config,
|
||||||
|
adjectives,
|
||||||
|
colors,
|
||||||
|
animals,
|
||||||
|
NumberDictionary,
|
||||||
|
} from "unique-names-generator"
|
||||||
|
|
||||||
|
const numberDictionary = NumberDictionary.generate({ min: 0, max: 999 })
|
||||||
|
const customConfig: Config = {
|
||||||
|
dictionaries: [adjectives, animals, numberDictionary],
|
||||||
|
separator: " ",
|
||||||
|
style: "capital",
|
||||||
|
length: 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
const options: NextAuthOptions = {
|
||||||
|
debug: true,
|
||||||
|
providers: [
|
||||||
|
EmailProvider({
|
||||||
|
server: process.env.EMAIL_SERVER,
|
||||||
|
from: process.env.EMAIL_FROM,
|
||||||
|
}),
|
||||||
|
AzureADProvider({
|
||||||
|
clientId: process.env.AZURE_AD_CLIENT_ID ?? "",
|
||||||
|
clientSecret: process.env.AZURE_AD_CLIENT_SECRET ?? "",
|
||||||
|
tenantId: process.env.AZURE_AD_TENANT_ID,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
adapter: PrismaAdapter(prisma),
|
||||||
|
secret: process.env.SECRET,
|
||||||
|
callbacks: {
|
||||||
|
signIn: ({ user, account }) => {
|
||||||
|
// Custom signIn callback to add username to email provider
|
||||||
|
if (account && account.provider === "email") {
|
||||||
|
user.name = uniqueNamesGenerator(customConfig) // Replace with your desired username
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
session: ({ session, user }) => {
|
||||||
|
if (session?.user) {
|
||||||
|
session.user.id = user.id
|
||||||
|
}
|
||||||
|
return session
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export { options as authOptions }
|
||||||
|
|
||||||
|
const authHandler: NextApiHandler = (req, res) => NextAuth(req, res, options)
|
||||||
|
export default authHandler
|
|
@ -1,40 +1,36 @@
|
||||||
import sendResponse from "@backend/components/sendResponse"
|
import { authOptions } from "../auth/[...nextauth]"
|
||||||
import getPlayer from "@lib/backend/components/getPlayer"
|
import sendResponse from "@backend/sendResponse"
|
||||||
import prisma from "@lib/prisma"
|
import prisma from "@lib/prisma"
|
||||||
|
import { createSchema } from "@lib/zodSchemas"
|
||||||
import type { NextApiRequest, NextApiResponse } from "next"
|
import type { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
import { getServerSession } from "next-auth"
|
||||||
import { z } from "zod"
|
import { z } from "zod"
|
||||||
|
|
||||||
export const createSchema = z.object({
|
|
||||||
game: z.object({
|
|
||||||
id: z.string(),
|
|
||||||
createdAt: z.date(),
|
|
||||||
updatedAt: z.date(),
|
|
||||||
running: z.boolean(),
|
|
||||||
}),
|
|
||||||
pin: z.string().optional(),
|
|
||||||
player: z.object({
|
|
||||||
id: z.string(),
|
|
||||||
username: z.string().optional(),
|
|
||||||
isOwner: z.boolean().optional(),
|
|
||||||
}),
|
|
||||||
enemy: z
|
|
||||||
.object({
|
|
||||||
id: z.string(),
|
|
||||||
username: z.string().optional(),
|
|
||||||
isOwner: z.boolean().optional(),
|
|
||||||
})
|
|
||||||
.optional(),
|
|
||||||
})
|
|
||||||
|
|
||||||
type Data = z.infer<typeof createSchema>
|
type Data = z.infer<typeof createSchema>
|
||||||
|
|
||||||
export default async function create(
|
export default async function create(
|
||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
res: NextApiResponse<Data>
|
res: NextApiResponse<Data>
|
||||||
) {
|
) {
|
||||||
const context = { req, res }
|
const session = await getServerSession(req, res, authOptions)
|
||||||
|
|
||||||
|
if (!session) {
|
||||||
|
return sendResponse(req, res, {
|
||||||
|
message: "Unauthorized",
|
||||||
|
statusCode: 401,
|
||||||
|
type: ["error"],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!session.user) {
|
||||||
|
return sendResponse(req, res, {
|
||||||
|
message: "Unauthorized - No User",
|
||||||
|
statusCode: 401,
|
||||||
|
type: ["error"],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const { email, id, name } = session.user
|
||||||
|
|
||||||
const { player } = await getPlayer(context)
|
|
||||||
// Generate a random 4-digit code
|
// Generate a random 4-digit code
|
||||||
const pin = Math.floor(Math.random() * 10000)
|
const pin = Math.floor(Math.random() * 10000)
|
||||||
.toString()
|
.toString()
|
||||||
|
@ -45,49 +41,49 @@ export default async function create(
|
||||||
let game = await prisma.game.findFirst({
|
let game = await prisma.game.findFirst({
|
||||||
where: {
|
where: {
|
||||||
running: true,
|
running: true,
|
||||||
players: {
|
users: {
|
||||||
some: {
|
some: {
|
||||||
playerId: player.id,
|
userId: id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
pin: true,
|
gamePin: true,
|
||||||
players: true,
|
users: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if (!game) {
|
if (!game) {
|
||||||
created = true
|
created = true
|
||||||
game = await prisma.game.create({
|
game = await prisma.game.create({
|
||||||
data: {
|
data: {
|
||||||
pin: {
|
gamePin: {
|
||||||
create: {
|
create: {
|
||||||
pin,
|
pin,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
players: {
|
users: {
|
||||||
create: {
|
create: {
|
||||||
isOwner: true,
|
isOwner: true,
|
||||||
playerId: player.id,
|
userId: id,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
pin: true,
|
gamePin: true,
|
||||||
players: true,
|
users: true,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return sendResponse(context, {
|
return sendResponse(req, res, {
|
||||||
message: `Player: ${player.id} created game: ${game.id}`,
|
message: `User <${email}> created game: ${game.id}`,
|
||||||
statusCode: created ? 201 : 200,
|
statusCode: created ? 201 : 200,
|
||||||
body: {
|
body: {
|
||||||
game,
|
game,
|
||||||
pin: game.pin?.pin,
|
pin: game.gamePin?.pin,
|
||||||
player: {
|
player: {
|
||||||
id: player.id,
|
id,
|
||||||
username: player.username ?? undefined,
|
name: name ?? undefined,
|
||||||
isOwner: true,
|
isOwner: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
import sendError from "@backend/components/sendError"
|
import { authOptions } from "../auth/[...nextauth]"
|
||||||
import sendResponse from "@backend/components/sendResponse"
|
import sendError from "@backend/sendError"
|
||||||
import getPinFromBody from "@lib/backend/components/getPinFromBody"
|
import sendResponse from "@backend/sendResponse"
|
||||||
import getPlayer from "@lib/backend/components/getPlayer"
|
|
||||||
import { rejectionErrors } from "@lib/backend/errors"
|
import { rejectionErrors } from "@lib/backend/errors"
|
||||||
|
import getPinFromBody from "@lib/backend/getPinFromBody"
|
||||||
import prisma from "@lib/prisma"
|
import prisma from "@lib/prisma"
|
||||||
import type { Game } from "@prisma/client"
|
import type { Game } from "@prisma/client"
|
||||||
import type { NextApiRequest, NextApiResponse } from "next"
|
import type { NextApiRequest, NextApiResponse } from "next"
|
||||||
|
import { getServerSession } from "next-auth"
|
||||||
|
|
||||||
interface Data {
|
interface Data {
|
||||||
game: Game
|
game: Game
|
||||||
|
@ -15,56 +16,64 @@ export default async function join(
|
||||||
req: NextApiRequest,
|
req: NextApiRequest,
|
||||||
res: NextApiResponse<Data>
|
res: NextApiResponse<Data>
|
||||||
) {
|
) {
|
||||||
const context = { req, res }
|
const session = await getServerSession(req, res, authOptions)
|
||||||
|
const pin = await getPinFromBody(req, res)
|
||||||
|
|
||||||
|
if (!session?.user) {
|
||||||
|
return sendResponse(req, res, rejectionErrors.unauthorized)
|
||||||
|
}
|
||||||
|
|
||||||
|
const { name, email, id } = session.user
|
||||||
|
|
||||||
const pin = await getPinFromBody(context)
|
|
||||||
const { player } = await getPlayer(context)
|
|
||||||
try {
|
try {
|
||||||
const pinDB = await prisma.gamepin.update({
|
const game = await prisma.game.findFirst({
|
||||||
where: {
|
where: {
|
||||||
pin,
|
gamePin: {
|
||||||
},
|
pin,
|
||||||
data: {
|
|
||||||
game: {
|
|
||||||
update: {
|
|
||||||
players: {
|
|
||||||
create: {
|
|
||||||
isOwner: false,
|
|
||||||
playerId: player.id,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
include: {
|
include: {
|
||||||
game: {
|
users: {
|
||||||
include: {
|
include: {
|
||||||
players: {
|
user: true,
|
||||||
include: {
|
|
||||||
player: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
if (!game) {
|
||||||
|
return sendResponse(req, res, {
|
||||||
|
message: "Spiel existiert nicht",
|
||||||
|
statusCode: 404,
|
||||||
|
type: ["infoCyan"],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const enemy = pinDB.game.players.find(
|
const player = game.users.find(({ user }) => user.id === id)?.user
|
||||||
(enemy) => enemy.player.id !== player.id
|
const enemy = game.users.find(({ user }) => user.id !== id)?.user
|
||||||
)
|
|
||||||
return sendResponse(context, {
|
if (!player) {
|
||||||
message: `Player: ${player.id} joined game: ${pinDB.game.id}`,
|
await prisma.user_Game.create({
|
||||||
|
data: {
|
||||||
|
isOwner: false,
|
||||||
|
gameId: game.id,
|
||||||
|
userId: id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return sendResponse(req, res, {
|
||||||
|
message: `User <${email}> joined game: ${game.id}`,
|
||||||
body: {
|
body: {
|
||||||
game: pinDB.game,
|
game,
|
||||||
pin: pinDB.pin,
|
pin,
|
||||||
player: {
|
player: {
|
||||||
id: player.id,
|
id,
|
||||||
username: player.username ?? undefined,
|
name,
|
||||||
isOwner: true,
|
isOwner: true,
|
||||||
},
|
},
|
||||||
enemy: {
|
enemy: {
|
||||||
id: enemy?.player.id,
|
id: enemy?.id,
|
||||||
username: enemy?.player.username ?? undefined,
|
name: enemy?.name,
|
||||||
isOwner: false,
|
isOwner: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -72,6 +81,6 @@ export default async function join(
|
||||||
})
|
})
|
||||||
} catch (err: any) {
|
} catch (err: any) {
|
||||||
console.log("HERE".red, err.code, err.meta, err.message)
|
console.log("HERE".red, err.code, err.meta, err.message)
|
||||||
throw sendError(context, rejectionErrors.gameNotFound)
|
throw sendError(req, res, rejectionErrors.gameNotFound)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
import checkTokenIsValid from "@backend/components/checkTokenIsValid"
|
|
||||||
import createTokenDB from "@backend/components/createTokenDB"
|
|
||||||
import getPlayerByIdDB from "@backend/components/getPlayerByIdDB"
|
|
||||||
import getTokenDB from "@backend/components/getTokenDB"
|
|
||||||
import getTokenFromCookie from "@backend/components/getTokenFromCookie"
|
|
||||||
import sendError from "@backend/components/sendError"
|
|
||||||
import sendResponse from "@backend/components/sendResponse"
|
|
||||||
import { Player, Token } from "@prisma/client"
|
|
||||||
import type { NextApiRequest, NextApiResponse } from "next"
|
|
||||||
|
|
||||||
interface Data {
|
|
||||||
token: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function auth(
|
|
||||||
req: NextApiRequest,
|
|
||||||
res: NextApiResponse<Data>
|
|
||||||
) {
|
|
||||||
const context = { req, res }
|
|
||||||
const type = "ACCESS"
|
|
||||||
|
|
||||||
const { refreshToken, newPlayer } = await getTokenFromCookie(context)
|
|
||||||
|
|
||||||
let player: Player, tokenDB: Token, cookie: string | undefined
|
|
||||||
|
|
||||||
if (!newPlayer) {
|
|
||||||
const token = await checkTokenIsValid(context, refreshToken)
|
|
||||||
tokenDB = await getTokenDB(context, token)
|
|
||||||
player = await getPlayerByIdDB(context, tokenDB)
|
|
||||||
} else {
|
|
||||||
player = newPlayer.player
|
|
||||||
tokenDB = newPlayer.newTokenDB
|
|
||||||
cookie = newPlayer.newToken.value
|
|
||||||
}
|
|
||||||
|
|
||||||
const { newToken, newTokenDB } = await createTokenDB(player, type)
|
|
||||||
return sendResponse(context, {
|
|
||||||
message: `Access-Token generated: ${newTokenDB.id} with Refreshtoken-Token: ${tokenDB.id}`,
|
|
||||||
body: { token: newToken.value },
|
|
||||||
type: ["debug", "infoCyan"],
|
|
||||||
cookie,
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,23 +0,0 @@
|
||||||
import sendResponse from "@backend/components/sendResponse"
|
|
||||||
import getPlayer from "@lib/backend/components/getPlayer"
|
|
||||||
import type { Game } from "@prisma/client"
|
|
||||||
import type { NextApiRequest, NextApiResponse } from "next"
|
|
||||||
|
|
||||||
interface Data {
|
|
||||||
games: Game[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function data(
|
|
||||||
req: NextApiRequest,
|
|
||||||
res: NextApiResponse<Data>
|
|
||||||
) {
|
|
||||||
const context = { req, res }
|
|
||||||
|
|
||||||
const { player, tokenDB } = await getPlayer(context)
|
|
||||||
const games: any = {}
|
|
||||||
return sendResponse(context, {
|
|
||||||
message: `Requested data of user: ${player.id} with Access-Token: ${tokenDB.id}`,
|
|
||||||
body: { games },
|
|
||||||
type: ["debug", "infoCyan"],
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,78 +0,0 @@
|
||||||
import checkPasswordIsValid from "@backend/components/checkPasswordIsValid"
|
|
||||||
import createTokenDB from "@backend/components/createTokenDB"
|
|
||||||
import getPlayerByNameDB from "@backend/components/getPlayerByNameDB"
|
|
||||||
import getUserFromBody from "@backend/components/getUserFromBody"
|
|
||||||
import sendError, { API } from "@backend/components/sendError"
|
|
||||||
import sendResponse from "@backend/components/sendResponse"
|
|
||||||
import logging from "@backend/logging"
|
|
||||||
import { rejectionErrors } from "@lib/backend/errors"
|
|
||||||
import prisma from "@lib/prisma"
|
|
||||||
import jwt from "jsonwebtoken"
|
|
||||||
import type { NextApiRequest, NextApiResponse } from "next"
|
|
||||||
|
|
||||||
interface Data {
|
|
||||||
loggedIn: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function login(
|
|
||||||
req: NextApiRequest,
|
|
||||||
res: NextApiResponse<Data>
|
|
||||||
) {
|
|
||||||
const context = { req, res }
|
|
||||||
|
|
||||||
await preCheck(context)
|
|
||||||
const { username, password } = await getUserFromBody(context)
|
|
||||||
const player = await getPlayerByNameDB(context, username)
|
|
||||||
await checkPasswordIsValid(context, player, password)
|
|
||||||
const { newToken, newTokenDB } = await createTokenDB(player, "REFRESH")
|
|
||||||
return sendResponse(context, {
|
|
||||||
message:
|
|
||||||
"User " +
|
|
||||||
player.id +
|
|
||||||
" logged in and generated Refresh-Token: " +
|
|
||||||
newTokenDB.id,
|
|
||||||
body: { loggedIn: true },
|
|
||||||
type: ["debug", "infoCyan"],
|
|
||||||
cookie: newToken.value,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async function preCheck<T>(context: API<T>) {
|
|
||||||
const { req } = context
|
|
||||||
const oldRefreshToken = req.cookies.token
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (!oldRefreshToken) throw sendError(context, rejectionErrors.noCookie)
|
|
||||||
// Check for old cookie, if unused invalidate it
|
|
||||||
const tokenData = jwt.verify(
|
|
||||||
oldRefreshToken,
|
|
||||||
process.env.TOKEN_SECRET as string
|
|
||||||
)
|
|
||||||
|
|
||||||
if (!tokenData || typeof tokenData === "string") return
|
|
||||||
|
|
||||||
const oldDBToken = await prisma.token.findUniqueOrThrow({
|
|
||||||
where: {
|
|
||||||
id: tokenData.id,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
if (oldDBToken.used)
|
|
||||||
logging("Old login token was used: " + oldDBToken.id, ["debug"], req)
|
|
||||||
else {
|
|
||||||
await prisma.token.update({
|
|
||||||
where: {
|
|
||||||
id: tokenData.id,
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
used: true,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
await logging("Old login token has been invalidated.", ["debug"], req)
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
// err is expected if no correct cookie, just continue, otherwise it has been invalidated above
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
import checkTokenIsValid from "@backend/components/checkTokenIsValid"
|
|
||||||
import getPlayerByIdDB from "@backend/components/getPlayerByIdDB"
|
|
||||||
import getTokenDB from "@backend/components/getTokenDB"
|
|
||||||
import getTokenFromCookie from "@backend/components/getTokenFromCookie"
|
|
||||||
import sendResponse from "@backend/components/sendResponse"
|
|
||||||
import type { NextApiRequest, NextApiResponse } from "next"
|
|
||||||
|
|
||||||
interface Data {
|
|
||||||
token: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function auth(
|
|
||||||
req: NextApiRequest,
|
|
||||||
res: NextApiResponse<Data>
|
|
||||||
) {
|
|
||||||
const context = { req, res }
|
|
||||||
|
|
||||||
const { refreshToken } = await getTokenFromCookie(context)
|
|
||||||
const token = await checkTokenIsValid(context, refreshToken)
|
|
||||||
const tokenDB = await getTokenDB(context, token)
|
|
||||||
const player = await getPlayerByIdDB(context, tokenDB)
|
|
||||||
return sendResponse(context, {
|
|
||||||
message: "loginCheck -> true : " + player.id,
|
|
||||||
type: ["debug", "infoCyan"],
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
import getTokenDB from "@backend/components/getTokenDB"
|
|
||||||
import getTokenFromCookie from "@backend/components/getTokenFromCookie"
|
|
||||||
import sendError from "@backend/components/sendError"
|
|
||||||
import sendResponse from "@backend/components/sendResponse"
|
|
||||||
import decodeToken from "@lib/backend/components/decodeToken"
|
|
||||||
import type { NextApiRequest, NextApiResponse } from "next"
|
|
||||||
|
|
||||||
interface Data {
|
|
||||||
loggedOut: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function logout(
|
|
||||||
req: NextApiRequest,
|
|
||||||
res: NextApiResponse<Data>
|
|
||||||
) {
|
|
||||||
const context = { req, res }
|
|
||||||
|
|
||||||
const { refreshToken } = await getTokenFromCookie(context)
|
|
||||||
const token = await decodeToken(context, refreshToken)
|
|
||||||
const tokenDB = await getTokenDB(context, token, true)
|
|
||||||
|
|
||||||
return sendResponse(context, {
|
|
||||||
message: "User of Token " + tokenDB.id + " logged out.",
|
|
||||||
body: { loggedOut: true },
|
|
||||||
type: ["debug", "infoCyan"],
|
|
||||||
cookie: "",
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
import checkTokenIsValid from "@backend/components/checkTokenIsValid"
|
|
||||||
import getPlayerByIdDB from "@backend/components/getPlayerByIdDB"
|
|
||||||
import getTokenDB from "@backend/components/getTokenDB"
|
|
||||||
import getTokenFromCookie from "@backend/components/getTokenFromCookie"
|
|
||||||
import getUserFromBody from "@backend/components/getUserFromBody"
|
|
||||||
import sendError from "@backend/components/sendError"
|
|
||||||
import sendResponse from "@backend/components/sendResponse"
|
|
||||||
import updatePlayerDB from "@backend/components/updatePlayerDB"
|
|
||||||
import bcrypt from "bcrypt"
|
|
||||||
import type { NextApiRequest, NextApiResponse } from "next"
|
|
||||||
|
|
||||||
interface Data {
|
|
||||||
registered: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function register(
|
|
||||||
req: NextApiRequest,
|
|
||||||
res: NextApiResponse<Data>
|
|
||||||
) {
|
|
||||||
const context = { req, res }
|
|
||||||
|
|
||||||
const { refreshToken } = await getTokenFromCookie(context)
|
|
||||||
const token = await checkTokenIsValid(context, refreshToken)
|
|
||||||
const tokenDB = await getTokenDB(context, token)
|
|
||||||
const { username, password } = await getUserFromBody(context)
|
|
||||||
let player = await getPlayerByIdDB(context, tokenDB)
|
|
||||||
player = await updatePlayerDB(context, player, {
|
|
||||||
username,
|
|
||||||
email: "arst",
|
|
||||||
passwordHash: await bcrypt.hash(password, 10),
|
|
||||||
anonymous: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
return sendResponse(context, {
|
|
||||||
message: "Player registered : " + player.id,
|
|
||||||
statusCode: 201,
|
|
||||||
body: { registered: true },
|
|
||||||
type: ["debug", "infoCyan"],
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
import checkPasswordIsValid from "@backend/components/checkPasswordIsValid"
|
|
||||||
import getPlayerByNameDB from "@backend/components/getPlayerByNameDB"
|
|
||||||
import getUserFromBody from "@backend/components/getUserFromBody"
|
|
||||||
import sendError from "@backend/components/sendError"
|
|
||||||
import sendResponse from "@backend/components/sendResponse"
|
|
||||||
import prisma from "@lib/prisma"
|
|
||||||
import { NextApiRequest, NextApiResponse } from "next"
|
|
||||||
|
|
||||||
interface Data {
|
|
||||||
loggedIn: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export default async function remove(
|
|
||||||
req: NextApiRequest,
|
|
||||||
res: NextApiResponse<Data>
|
|
||||||
) {
|
|
||||||
const context = { req, res }
|
|
||||||
|
|
||||||
const { username, password } = await getUserFromBody(context)
|
|
||||||
const player = await getPlayerByNameDB(context, username)
|
|
||||||
await checkPasswordIsValid(context, player, password)
|
|
||||||
prisma.player.update({
|
|
||||||
where: {
|
|
||||||
id: player.id,
|
|
||||||
},
|
|
||||||
data: {
|
|
||||||
deleted: true,
|
|
||||||
username: null,
|
|
||||||
email: null,
|
|
||||||
passwordHash: null,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
return sendResponse(context, {
|
|
||||||
message: "User successfully deleted: " + player.id,
|
|
||||||
type: ["debug", "infoCyan"],
|
|
||||||
})
|
|
||||||
}
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { NextApiResponseWithSocket } from "../../interfaces/NextApiSocket"
|
import type { NextApiResponseWithSocket } from "../../interfaces/NextApiSocket"
|
||||||
import prisma from "@lib/prisma"
|
import prisma from "@lib/prisma"
|
||||||
import jwt from "jsonwebtoken"
|
|
||||||
import type { NextApiRequest } from "next"
|
import type { NextApiRequest } from "next"
|
||||||
import { Server } from "socket.io"
|
import { Server } from "socket.io"
|
||||||
|
|
||||||
|
@ -37,21 +36,6 @@ interface SocketData {
|
||||||
//
|
//
|
||||||
// }
|
// }
|
||||||
|
|
||||||
async function checkTokenIsValid(rawToken: string) {
|
|
||||||
// Verify the token and get the payload
|
|
||||||
let tokenData: string | jwt.JwtPayload
|
|
||||||
try {
|
|
||||||
tokenData = jwt.verify(rawToken, process.env.TOKEN_SECRET as string)
|
|
||||||
} catch (err: any) {
|
|
||||||
// Deal with the problem in more detail
|
|
||||||
return Promise.reject()
|
|
||||||
}
|
|
||||||
// Making sure the token data is not a string (because it should be an object)
|
|
||||||
if (typeof tokenData === "string") return Promise.reject()
|
|
||||||
|
|
||||||
return tokenData
|
|
||||||
}
|
|
||||||
|
|
||||||
const SocketHandler = (req: NextApiRequest, res: NextApiResponseWithSocket) => {
|
const SocketHandler = (req: NextApiRequest, res: NextApiResponseWithSocket) => {
|
||||||
if (res.socket.server.io) {
|
if (res.socket.server.io) {
|
||||||
console.log("Socket is already running " + req.url)
|
console.log("Socket is already running " + req.url)
|
||||||
|
@ -73,22 +57,6 @@ const SocketHandler = (req: NextApiRequest, res: NextApiResponseWithSocket) => {
|
||||||
io.emit("update-input", msg)
|
io.emit("update-input", msg)
|
||||||
})
|
})
|
||||||
|
|
||||||
socket.on("authenticate", (payload) => {
|
|
||||||
checkTokenIsValid(payload.token)
|
|
||||||
.then(async ({ tokenBody }) => {
|
|
||||||
const token = await prisma.token.findUnique({
|
|
||||||
where: { id: tokenBody.id },
|
|
||||||
})
|
|
||||||
if (!token || token.used) {
|
|
||||||
socket.emit("unauthenticated")
|
|
||||||
} else {
|
|
||||||
socket.emit("authenticated")
|
|
||||||
socket.data.isAuthenticated = true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((err) => console.log("cat", err.message))
|
|
||||||
})
|
|
||||||
|
|
||||||
socket.on("test", (payload) => {
|
socket.on("test", (payload) => {
|
||||||
console.log("Got test:", payload)
|
console.log("Got test:", payload)
|
||||||
// ...
|
// ...
|
||||||
|
|
|
@ -1,230 +0,0 @@
|
||||||
import BurgerMenu from "../../components/BurgerMenu"
|
|
||||||
import Logo from "../../components/Logo"
|
|
||||||
import OptionButton from "../../components/OptionButton"
|
|
||||||
import { gameContext } from "../_app"
|
|
||||||
import { faEye, faLeftLong } from "@fortawesome/pro-regular-svg-icons"
|
|
||||||
import { faPlus, faUserPlus } from "@fortawesome/pro-solid-svg-icons"
|
|
||||||
import { faCirclePlay } from "@fortawesome/pro-thin-svg-icons"
|
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
|
||||||
import getAccessToken, {
|
|
||||||
successfulResponse,
|
|
||||||
} from "@lib/frontend/getAccessToken"
|
|
||||||
import { GetServerSideProps } from "next"
|
|
||||||
import { useRouter } from "next/router"
|
|
||||||
import { useCallback, useContext, useEffect, useState } from "react"
|
|
||||||
import OtpInput from "react-otp-input"
|
|
||||||
import { toast } from "react-toastify"
|
|
||||||
import { z } from "zod"
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
q: string | string[] | undefined
|
|
||||||
}
|
|
||||||
function isInputOnlyNumbers(input: string) {
|
|
||||||
return /^\d+$/.test(input)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function Home({ q }: Props) {
|
|
||||||
const [otp, setOtp] = useState("")
|
|
||||||
const [gameProps, setGameProps] = useContext(gameContext)
|
|
||||||
const router = useRouter()
|
|
||||||
|
|
||||||
const gameFetch = useCallback(
|
|
||||||
async (pin?: string) => {
|
|
||||||
const createSchema = z.object({
|
|
||||||
game: z.object({
|
|
||||||
id: z.string(),
|
|
||||||
}),
|
|
||||||
pin: z.string().optional(),
|
|
||||||
player: z.object({
|
|
||||||
id: z.string(),
|
|
||||||
username: z.string().optional(),
|
|
||||||
isOwner: z.boolean().optional(),
|
|
||||||
}),
|
|
||||||
enemy: z
|
|
||||||
.object({
|
|
||||||
id: z.string(),
|
|
||||||
username: z.string().optional(),
|
|
||||||
isOwner: z.boolean().optional(),
|
|
||||||
})
|
|
||||||
.optional(),
|
|
||||||
})
|
|
||||||
const gamePromise = getAccessToken().then((token) =>
|
|
||||||
fetch("/api/game/" + (!pin ? "create" : "join"), {
|
|
||||||
method: "POST",
|
|
||||||
body: JSON.stringify({ token, pin }),
|
|
||||||
})
|
|
||||||
.then(successfulResponse)
|
|
||||||
.then((game) => createSchema.parse(game))
|
|
||||||
)
|
|
||||||
|
|
||||||
const res = await toast.promise(gamePromise, {
|
|
||||||
pending: {
|
|
||||||
render: "Raum wird " + (!pin ? "erstellt" : "angefragt"),
|
|
||||||
},
|
|
||||||
success: {
|
|
||||||
render: "Raum " + (!pin ? "erstellt" : "angefragt") + " 👌",
|
|
||||||
type: "info",
|
|
||||||
theme: "colored",
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
render: "Es ist ein Fehler aufgetreten 🤯",
|
|
||||||
type: "error",
|
|
||||||
theme: "colored",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
setGameProps(res)
|
|
||||||
|
|
||||||
await toast.promise(router.push("/dev/lobby"), {
|
|
||||||
pending: {
|
|
||||||
render: "Raum wird beigetreten",
|
|
||||||
},
|
|
||||||
success: {
|
|
||||||
render: "Raum begetreten 👌",
|
|
||||||
type: "info",
|
|
||||||
},
|
|
||||||
error: {
|
|
||||||
render: "Es ist ein Fehler aufgetreten 🤯",
|
|
||||||
type: "error",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
},
|
|
||||||
[router, setGameProps]
|
|
||||||
)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (otp.length !== 4) return
|
|
||||||
if (!isInputOnlyNumbers(otp)) {
|
|
||||||
toast("Der Code darf nur Zahlen beinhalten!", {
|
|
||||||
type: "warning",
|
|
||||||
theme: "dark",
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
gameFetch(otp)
|
|
||||||
}, [otp, gameFetch])
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="h-full bg-theme">
|
|
||||||
<div className="mx-auto flex h-full max-w-screen-md flex-col items-center justify-evenly">
|
|
||||||
<Logo />
|
|
||||||
<BurgerMenu />
|
|
||||||
{(() => {
|
|
||||||
switch (q) {
|
|
||||||
case "join":
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col items-center rounded-xl border-4 border-black bg-grayish px-4 py-6 shadow-lg sm:mx-8 sm:p-12 md:w-full">
|
|
||||||
<button
|
|
||||||
className="-mt-2 w-20 self-start rounded-xl border-b-4 border-shield-gray bg-voidDark text-2xl text-grayish duration-100 active:border-b-0 active:border-t-4 sm:-mt-6 sm:w-40 sm:px-2 sm:text-5xl"
|
|
||||||
onClick={() =>
|
|
||||||
setTimeout(() => {
|
|
||||||
// Navigate to the same page with the `start` query parameter set to `false`
|
|
||||||
router.push({
|
|
||||||
pathname: router.pathname,
|
|
||||||
query: null,
|
|
||||||
})
|
|
||||||
}, 200)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon icon={faLeftLong} />
|
|
||||||
</button>
|
|
||||||
<div className="flex flex-col items-center gap-6 sm:gap-12">
|
|
||||||
<OptionButton icon={faPlus}>Raum erstellen</OptionButton>
|
|
||||||
<OptionButton
|
|
||||||
action={() => {
|
|
||||||
router.push({
|
|
||||||
pathname: router.pathname,
|
|
||||||
query: { q: "join" },
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
icon={faUserPlus}
|
|
||||||
>
|
|
||||||
<OtpInput
|
|
||||||
containerStyle={{ color: "initial" }}
|
|
||||||
value={otp}
|
|
||||||
onChange={setOtp}
|
|
||||||
numInputs={4}
|
|
||||||
placeholder="0000"
|
|
||||||
renderSeparator={<span>-</span>}
|
|
||||||
renderInput={(props) => <input {...props} />}
|
|
||||||
/>
|
|
||||||
</OptionButton>
|
|
||||||
<OptionButton icon={faEye}>Zuschauen</OptionButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
case "start":
|
|
||||||
return (
|
|
||||||
<div className="flex flex-col items-center rounded-xl border-4 border-black bg-grayish px-4 py-6 shadow-lg sm:mx-8 sm:p-12 md:w-full">
|
|
||||||
<button
|
|
||||||
className="-mt-2 w-20 self-start rounded-xl border-b-4 border-shield-gray bg-voidDark text-2xl text-grayish duration-100 active:border-b-0 active:border-t-4 sm:-mt-6 sm:w-40 sm:px-2 sm:text-5xl"
|
|
||||||
onClick={() =>
|
|
||||||
setTimeout(() => {
|
|
||||||
// Navigate to the same page with the `start` query parameter set to `false`
|
|
||||||
router.push({
|
|
||||||
pathname: router.pathname,
|
|
||||||
query: null,
|
|
||||||
})
|
|
||||||
}, 200)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<FontAwesomeIcon icon={faLeftLong} />
|
|
||||||
</button>
|
|
||||||
<div className="flex flex-col items-center gap-6 sm:gap-12">
|
|
||||||
<OptionButton action={() => gameFetch()} icon={faPlus}>
|
|
||||||
Raum erstellen
|
|
||||||
</OptionButton>
|
|
||||||
<OptionButton
|
|
||||||
action={() => {
|
|
||||||
router.push({
|
|
||||||
pathname: router.pathname,
|
|
||||||
query: { q: "join" },
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
icon={faUserPlus}
|
|
||||||
>
|
|
||||||
Raum beitreten
|
|
||||||
</OptionButton>
|
|
||||||
<OptionButton icon={faEye}>Zuschauen</OptionButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
default:
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="flex h-36 w-64 items-center justify-center rounded-xl border-4 border-black bg-[#2227] sm:h-48 sm:w-96 md:h-72 md:w-[32rem] md:border-[6px] xl:h-[26rem] xl:w-[48rem]">
|
|
||||||
<FontAwesomeIcon
|
|
||||||
className="text-6xl sm:text-7xl md:text-8xl"
|
|
||||||
icon={faCirclePlay}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
className="font-farro rounded-lg border-b-4 border-orange-400 bg-warn px-12 pb-4 pt-5 text-2xl font-bold duration-100 active:border-b-0 active:border-t-4 sm:rounded-xl sm:border-b-[6px] sm:px-14 sm:pb-5 sm:pt-6 sm:text-3xl sm:active:border-t-[6px] md:rounded-2xl md:border-b-8 md:px-20 md:pb-6 md:pt-7 md:text-4xl md:active:border-t-8 xl:px-24 xl:pb-8 xl:pt-10 xl:text-5xl"
|
|
||||||
onClick={() =>
|
|
||||||
setTimeout(() => {
|
|
||||||
// Navigate to the same page with the `start` query parameter set to `true`
|
|
||||||
router.push({
|
|
||||||
pathname: router.pathname,
|
|
||||||
query: { q: "start" },
|
|
||||||
})
|
|
||||||
}, 200)
|
|
||||||
}
|
|
||||||
>
|
|
||||||
START
|
|
||||||
</button>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})()}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getServerSideProps: GetServerSideProps<Props> = async (
|
|
||||||
context
|
|
||||||
) => {
|
|
||||||
const { q } = context.query
|
|
||||||
|
|
||||||
return { props: { q: q ? q : "" } }
|
|
||||||
}
|
|
|
@ -1,62 +1,34 @@
|
||||||
import Head from "next/head"
|
import BurgerMenu from "../components/BurgerMenu"
|
||||||
import Link from "next/link"
|
import Logo from "../components/Logo"
|
||||||
|
import { faCirclePlay } from "@fortawesome/pro-thin-svg-icons"
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||||
|
import { useRouter } from "next/router"
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="h-full bg-theme">
|
||||||
<Head>
|
<div className="mx-auto flex h-full max-w-screen-md flex-col items-center justify-evenly">
|
||||||
<title>Create Next App</title>
|
<Logo />
|
||||||
<meta name="description" content="Generated by create next app" />
|
<BurgerMenu />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<div className="flex h-36 w-64 items-center justify-center rounded-xl border-4 border-black bg-[#2227] sm:h-48 sm:w-96 md:h-72 md:w-[32rem] md:border-[6px] xl:h-[26rem] xl:w-[48rem]">
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<FontAwesomeIcon
|
||||||
</Head>
|
className="text-6xl sm:text-7xl md:text-8xl"
|
||||||
<main>
|
icon={faCirclePlay}
|
||||||
<p>
|
/>
|
||||||
<Link href="/dev/gamefield" target="_blank">
|
</div>
|
||||||
Gamefield
|
<button
|
||||||
</Link>
|
className="font-farro rounded-lg border-b-4 border-orange-400 bg-warn px-12 pb-4 pt-5 text-2xl font-bold duration-100 active:border-b-0 active:border-t-4 sm:rounded-xl sm:border-b-[6px] sm:px-14 sm:pb-5 sm:pt-6 sm:text-3xl sm:active:border-t-[6px] md:rounded-2xl md:border-b-8 md:px-20 md:pb-6 md:pt-7 md:text-4xl md:active:border-t-8 xl:px-24 xl:pb-8 xl:pt-10 xl:text-5xl"
|
||||||
</p>
|
onClick={() =>
|
||||||
<p>
|
setTimeout(() => {
|
||||||
<Link href="/dev" target="_blank">
|
router.push("/start")
|
||||||
Homepage
|
}, 200)
|
||||||
</Link>
|
}
|
||||||
</p>
|
>
|
||||||
<p>
|
START
|
||||||
<Link href="/dev/lobby" target="_blank">
|
</button>
|
||||||
Lobby
|
</div>
|
||||||
</Link>
|
</div>
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<Link href="/dev/login" target="_blank">
|
|
||||||
Login
|
|
||||||
</Link>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<Link href="/dev/logout" target="_blank">
|
|
||||||
Logout
|
|
||||||
</Link>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<Link href="/dev/grid" target="_blank">
|
|
||||||
Grid Effect
|
|
||||||
</Link>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<Link href="/dev/grid2" target="_blank">
|
|
||||||
Grid Effect with Content
|
|
||||||
</Link>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<Link href="/dev/socket" target="_blank">
|
|
||||||
Socket
|
|
||||||
</Link>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<Link href="/dev/socketio" target="_blank">
|
|
||||||
SocketIO
|
|
||||||
</Link>
|
|
||||||
</p>
|
|
||||||
</main>
|
|
||||||
</>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import SocketIO from "../../components/SocketIO"
|
import SocketIO from "../components/SocketIO"
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return (
|
return (
|
168
leaky-ships/pages/start.tsx
Normal file
168
leaky-ships/pages/start.tsx
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
import BurgerMenu from "../components/BurgerMenu"
|
||||||
|
import Logo from "../components/Logo"
|
||||||
|
import OptionButton from "../components/OptionButton"
|
||||||
|
import { faEye, faLeftLong } from "@fortawesome/pro-regular-svg-icons"
|
||||||
|
import { faPlus, faUserPlus } from "@fortawesome/pro-solid-svg-icons"
|
||||||
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"
|
||||||
|
import useGameState from "@lib/hooks/useGameState"
|
||||||
|
import { createSchema } from "@lib/zodSchemas"
|
||||||
|
import status from "http-status"
|
||||||
|
import { GetServerSideProps } from "next"
|
||||||
|
import { useRouter } from "next/router"
|
||||||
|
import { useCallback, useEffect, useState } from "react"
|
||||||
|
import OtpInput from "react-otp-input"
|
||||||
|
import { toast } from "react-toastify"
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
q: string | string[] | undefined
|
||||||
|
}
|
||||||
|
function isInputOnlyNumbers(input: string) {
|
||||||
|
return /^\d+$/.test(input)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isAuthenticated(res: Response) {
|
||||||
|
if (status[`${res.status}_CLASS`] === status.classes.SUCCESSFUL)
|
||||||
|
return res.json()
|
||||||
|
|
||||||
|
const resStatus = status[`${res.status}_CLASS`]
|
||||||
|
if (typeof resStatus !== "string") return
|
||||||
|
|
||||||
|
toast(status[res.status], {
|
||||||
|
position: "top-center",
|
||||||
|
type: "error",
|
||||||
|
theme: "colored",
|
||||||
|
})
|
||||||
|
return Promise.reject()
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Home({ q }: Props) {
|
||||||
|
const [otp, setOtp] = useState("")
|
||||||
|
const { gameProps, setGameProps } = useGameState()
|
||||||
|
const router = useRouter()
|
||||||
|
const { session } = useGameState()
|
||||||
|
|
||||||
|
const gameFetch = useCallback(
|
||||||
|
async (pin?: string) => {
|
||||||
|
const gamePromise = fetch("/api/game/" + (!pin ? "create" : "join"), {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ pin }),
|
||||||
|
})
|
||||||
|
.then(isAuthenticated)
|
||||||
|
.then((game) => createSchema.parse(game))
|
||||||
|
|
||||||
|
const res = await toast.promise(gamePromise, {
|
||||||
|
pending: {
|
||||||
|
render: "Raum wird " + (!pin ? "erstellt" : "angefragt"),
|
||||||
|
},
|
||||||
|
success: {
|
||||||
|
render: "Raum " + (!pin ? "erstellt" : "angefragt") + " 👌",
|
||||||
|
type: "info",
|
||||||
|
theme: "colored",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
render: "Es ist ein Fehler aufgetreten 🤯",
|
||||||
|
type: "error",
|
||||||
|
theme: "colored",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log(res)
|
||||||
|
setGameProps(res)
|
||||||
|
|
||||||
|
await toast.promise(router.push("/lobby"), {
|
||||||
|
pending: {
|
||||||
|
render: "Raum wird beigetreten",
|
||||||
|
},
|
||||||
|
success: {
|
||||||
|
render: "Raum begetreten 👌",
|
||||||
|
type: "info",
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
render: "Es ist ein Fehler aufgetreten 🤯",
|
||||||
|
type: "error",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
[router, setGameProps]
|
||||||
|
)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (otp.length !== 4) return
|
||||||
|
if (!isInputOnlyNumbers(otp)) {
|
||||||
|
toast("Der Code darf nur Zahlen beinhalten!", {
|
||||||
|
type: "warning",
|
||||||
|
theme: "dark",
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
gameFetch(otp)
|
||||||
|
}, [otp, gameFetch])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="h-full bg-theme">
|
||||||
|
<div className="mx-auto flex h-full max-w-screen-md flex-col items-center justify-evenly">
|
||||||
|
<Logo />
|
||||||
|
<BurgerMenu />
|
||||||
|
<div className="flex flex-col items-center rounded-xl border-4 border-black bg-grayish px-4 py-6 shadow-lg sm:mx-8 sm:p-12 md:w-full">
|
||||||
|
<button
|
||||||
|
className="-mt-2 w-20 self-start rounded-xl border-b-4 border-shield-gray bg-voidDark text-2xl text-grayish duration-100 active:border-b-0 active:border-t-4 sm:-mt-6 sm:w-40 sm:px-2 sm:text-5xl"
|
||||||
|
onClick={() =>
|
||||||
|
setTimeout(() => {
|
||||||
|
// Navigate to the same page with the `start` query parameter set to `false`
|
||||||
|
router.push({
|
||||||
|
pathname: router.pathname,
|
||||||
|
query: null,
|
||||||
|
})
|
||||||
|
}, 200)
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faLeftLong} />
|
||||||
|
</button>
|
||||||
|
<div className="flex flex-col items-center gap-6 sm:gap-12">
|
||||||
|
<OptionButton
|
||||||
|
action={() => gameFetch()}
|
||||||
|
icon={faPlus}
|
||||||
|
disabled={!session}
|
||||||
|
>
|
||||||
|
Raum erstellen
|
||||||
|
</OptionButton>
|
||||||
|
<OptionButton
|
||||||
|
action={() => {
|
||||||
|
router.push({
|
||||||
|
pathname: router.pathname,
|
||||||
|
query: { q: "join" },
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
icon={faUserPlus}
|
||||||
|
disabled={!session}
|
||||||
|
>
|
||||||
|
{q === "join" ? (
|
||||||
|
"Raum beitreten"
|
||||||
|
) : (
|
||||||
|
<OtpInput
|
||||||
|
shouldAutoFocus
|
||||||
|
containerStyle={{ color: "initial" }}
|
||||||
|
value={otp}
|
||||||
|
onChange={setOtp}
|
||||||
|
numInputs={4}
|
||||||
|
placeholder="0000"
|
||||||
|
renderSeparator={<span>-</span>}
|
||||||
|
renderInput={(props) => <input {...props} />}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</OptionButton>
|
||||||
|
<OptionButton icon={faEye}>Zuschauen</OptionButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getServerSideProps: GetServerSideProps<Props> = async (
|
||||||
|
context
|
||||||
|
) => {
|
||||||
|
const { q } = context.query
|
||||||
|
|
||||||
|
return { props: { q: q ? q : "" } }
|
||||||
|
}
|
432
leaky-ships/pnpm-lock.yaml
generated
432
leaky-ships/pnpm-lock.yaml
generated
|
@ -25,24 +25,21 @@ dependencies:
|
||||||
'@fortawesome/sharp-solid-svg-icons':
|
'@fortawesome/sharp-solid-svg-icons':
|
||||||
specifier: ^6.4.0
|
specifier: ^6.4.0
|
||||||
version: 6.4.0
|
version: 6.4.0
|
||||||
|
'@next-auth/prisma-adapter':
|
||||||
|
specifier: ^1.0.6
|
||||||
|
version: 1.0.6(@prisma/client@4.12.0)(next-auth@4.22.1)
|
||||||
'@next/font':
|
'@next/font':
|
||||||
specifier: 13.1.1
|
specifier: 13.1.1
|
||||||
version: 13.1.1
|
version: 13.1.1
|
||||||
'@prisma/client':
|
'@prisma/client':
|
||||||
specifier: ^4.12.0
|
specifier: ^4.12.0
|
||||||
version: 4.12.0(prisma@4.12.0)
|
version: 4.12.0(prisma@4.12.0)
|
||||||
bcrypt:
|
|
||||||
specifier: ^5.1.0
|
|
||||||
version: 5.1.0
|
|
||||||
classnames:
|
classnames:
|
||||||
specifier: ^2.3.2
|
specifier: ^2.3.2
|
||||||
version: 2.3.2
|
version: 2.3.2
|
||||||
colors:
|
colors:
|
||||||
specifier: ^1.4.0
|
specifier: ^1.4.0
|
||||||
version: 1.4.0
|
version: 1.4.0
|
||||||
cookies-next:
|
|
||||||
specifier: ^2.1.1
|
|
||||||
version: 2.1.1
|
|
||||||
eslint:
|
eslint:
|
||||||
specifier: 8.31.0
|
specifier: 8.31.0
|
||||||
version: 8.31.0
|
version: 8.31.0
|
||||||
|
@ -52,12 +49,15 @@ dependencies:
|
||||||
http-status:
|
http-status:
|
||||||
specifier: ^1.6.2
|
specifier: ^1.6.2
|
||||||
version: 1.6.2
|
version: 1.6.2
|
||||||
jsonwebtoken:
|
|
||||||
specifier: ^9.0.0
|
|
||||||
version: 9.0.0
|
|
||||||
next:
|
next:
|
||||||
specifier: 13.1.1
|
specifier: 13.1.1
|
||||||
version: 13.1.1(react-dom@18.2.0)(react@18.2.0)(sass@1.61.0)
|
version: 13.1.1(react-dom@18.2.0)(react@18.2.0)(sass@1.61.0)
|
||||||
|
next-auth:
|
||||||
|
specifier: ^4.22.1
|
||||||
|
version: 4.22.1(next@13.1.1)(nodemailer@6.9.1)(react-dom@18.2.0)(react@18.2.0)
|
||||||
|
nodemailer:
|
||||||
|
specifier: ^6.9.1
|
||||||
|
version: 6.9.1
|
||||||
prisma:
|
prisma:
|
||||||
specifier: ^4.12.0
|
specifier: ^4.12.0
|
||||||
version: 4.12.0
|
version: 4.12.0
|
||||||
|
@ -82,6 +82,9 @@ dependencies:
|
||||||
typescript:
|
typescript:
|
||||||
specifier: 4.9.4
|
specifier: 4.9.4
|
||||||
version: 4.9.4
|
version: 4.9.4
|
||||||
|
unique-names-generator:
|
||||||
|
specifier: ^4.7.1
|
||||||
|
version: 4.7.1
|
||||||
zod:
|
zod:
|
||||||
specifier: ^3.21.4
|
specifier: ^3.21.4
|
||||||
version: 3.21.4
|
version: 3.21.4
|
||||||
|
@ -93,12 +96,6 @@ devDependencies:
|
||||||
'@trivago/prettier-plugin-sort-imports':
|
'@trivago/prettier-plugin-sort-imports':
|
||||||
specifier: ^4.1.1
|
specifier: ^4.1.1
|
||||||
version: 4.1.1(prettier@2.8.7)
|
version: 4.1.1(prettier@2.8.7)
|
||||||
'@types/bcrypt':
|
|
||||||
specifier: ^5.0.0
|
|
||||||
version: 5.0.0
|
|
||||||
'@types/jsonwebtoken':
|
|
||||||
specifier: ^9.0.1
|
|
||||||
version: 9.0.1
|
|
||||||
'@types/node':
|
'@types/node':
|
||||||
specifier: ^18.15.11
|
specifier: ^18.15.11
|
||||||
version: 18.15.11
|
version: 18.15.11
|
||||||
|
@ -362,22 +359,14 @@ packages:
|
||||||
/@humanwhocodes/object-schema@1.2.1:
|
/@humanwhocodes/object-schema@1.2.1:
|
||||||
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
|
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
|
||||||
|
|
||||||
/@mapbox/node-pre-gyp@1.0.10:
|
/@next-auth/prisma-adapter@1.0.6(@prisma/client@4.12.0)(next-auth@4.22.1):
|
||||||
resolution: {integrity: sha512-4ySo4CjzStuprMwk35H5pPbkymjv1SF3jGLj6rAHp/xT/RF7TL7bd9CTm1xDY49K2qF7jmR/g7k+SkLETP6opA==}
|
resolution: {integrity: sha512-Z7agwfSZEeEcqKqrnisBun7VndRPshd6vyDsoRU68MXbkui8storkHgvN2hnNDrqr/hSCF9aRn56a1qpihaB4A==}
|
||||||
hasBin: true
|
peerDependencies:
|
||||||
|
'@prisma/client': '>=2.26.0 || >=3'
|
||||||
|
next-auth: ^4
|
||||||
dependencies:
|
dependencies:
|
||||||
detect-libc: 2.0.1
|
'@prisma/client': 4.12.0(prisma@4.12.0)
|
||||||
https-proxy-agent: 5.0.1
|
next-auth: 4.22.1(next@13.1.1)(nodemailer@6.9.1)(react-dom@18.2.0)(react@18.2.0)
|
||||||
make-dir: 3.1.0
|
|
||||||
node-fetch: 2.6.9
|
|
||||||
nopt: 5.0.0
|
|
||||||
npmlog: 5.0.1
|
|
||||||
rimraf: 3.0.2
|
|
||||||
semver: 7.3.8
|
|
||||||
tar: 6.1.13
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- encoding
|
|
||||||
- supports-color
|
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@next/env@13.1.1:
|
/@next/env@13.1.1:
|
||||||
|
@ -529,6 +518,10 @@ packages:
|
||||||
'@nodelib/fs.scandir': 2.1.5
|
'@nodelib/fs.scandir': 2.1.5
|
||||||
fastq: 1.15.0
|
fastq: 1.15.0
|
||||||
|
|
||||||
|
/@panva/hkdf@1.0.4:
|
||||||
|
resolution: {integrity: sha512-003xWiCuvePbLaPHT+CRuaV4GlyCAVm6XYSbBZDHoWZGn1mNkVKFaDbGJjjxmEFvizUwlCoM6O18FCBMMky2zQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/@pkgr/utils@2.3.1:
|
/@pkgr/utils@2.3.1:
|
||||||
resolution: {integrity: sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==}
|
resolution: {integrity: sha512-wfzX8kc1PMyUILA+1Z/EqoE4UCXGy0iRGMhPwdfae1+f0OXlLqCk+By+aMzgJBzR9AzS4CDizioG6Ss1gvAFJw==}
|
||||||
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
|
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
|
||||||
|
@ -602,12 +595,6 @@ packages:
|
||||||
- supports-color
|
- supports-color
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/@types/bcrypt@5.0.0:
|
|
||||||
resolution: {integrity: sha512-agtcFKaruL8TmcvqbndlqHPSJgsolhf/qPWchFlgnW1gECTN/nKbFcoFnvKAQRFfKbh+BO6A3SWdJu9t+xF3Lw==}
|
|
||||||
dependencies:
|
|
||||||
'@types/node': 18.15.11
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@types/cookie@0.4.1:
|
/@types/cookie@0.4.1:
|
||||||
resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==}
|
resolution: {integrity: sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -622,16 +609,6 @@ packages:
|
||||||
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/@types/jsonwebtoken@9.0.1:
|
|
||||||
resolution: {integrity: sha512-c5ltxazpWabia/4UzhIoaDcIza4KViOQhdbjRlfcIGVnsE3c3brkz9Z+F/EeJIECOQP7W7US2hNE930cWWkPiw==}
|
|
||||||
dependencies:
|
|
||||||
'@types/node': 18.15.11
|
|
||||||
dev: true
|
|
||||||
|
|
||||||
/@types/node@16.18.23:
|
|
||||||
resolution: {integrity: sha512-XAMpaw1s1+6zM+jn2tmw8MyaRDIJfXxqmIQIS0HfoGYPuf7dUWeiUKopwq13KFX9lEp1+THGtlaaYx39Nxr58g==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/@types/node@18.15.11:
|
/@types/node@18.15.11:
|
||||||
resolution: {integrity: sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==}
|
resolution: {integrity: sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==}
|
||||||
|
|
||||||
|
@ -723,10 +700,6 @@ packages:
|
||||||
eslint-visitor-keys: 3.4.0
|
eslint-visitor-keys: 3.4.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/abbrev@1.1.1:
|
|
||||||
resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/accepts@1.3.8:
|
/accepts@1.3.8:
|
||||||
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
@ -747,15 +720,6 @@ packages:
|
||||||
engines: {node: '>=0.4.0'}
|
engines: {node: '>=0.4.0'}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
/agent-base@6.0.2:
|
|
||||||
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
|
|
||||||
engines: {node: '>= 6.0.0'}
|
|
||||||
dependencies:
|
|
||||||
debug: 4.3.4
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/ajv@6.12.6:
|
/ajv@6.12.6:
|
||||||
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
|
resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -792,18 +756,6 @@ packages:
|
||||||
normalize-path: 3.0.0
|
normalize-path: 3.0.0
|
||||||
picomatch: 2.3.1
|
picomatch: 2.3.1
|
||||||
|
|
||||||
/aproba@2.0.0:
|
|
||||||
resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/are-we-there-yet@2.0.0:
|
|
||||||
resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==}
|
|
||||||
engines: {node: '>=10'}
|
|
||||||
dependencies:
|
|
||||||
delegates: 1.0.0
|
|
||||||
readable-stream: 3.6.2
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/arg@5.0.2:
|
/arg@5.0.2:
|
||||||
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
|
resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -914,18 +866,6 @@ packages:
|
||||||
engines: {node: ^4.5.0 || >= 5.9}
|
engines: {node: ^4.5.0 || >= 5.9}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/bcrypt@5.1.0:
|
|
||||||
resolution: {integrity: sha512-RHBS7HI5N5tEnGTmtR/pppX0mmDSBpQ4aCBsj7CEQfYXDcO74A8sIBYcJMuCsis2E81zDxeENYhv66oZwLiA+Q==}
|
|
||||||
engines: {node: '>= 10.0.0'}
|
|
||||||
requiresBuild: true
|
|
||||||
dependencies:
|
|
||||||
'@mapbox/node-pre-gyp': 1.0.10
|
|
||||||
node-addon-api: 5.1.0
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- encoding
|
|
||||||
- supports-color
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/binary-extensions@2.2.0:
|
/binary-extensions@2.2.0:
|
||||||
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
|
resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -953,10 +893,6 @@ packages:
|
||||||
update-browserslist-db: 1.0.10(browserslist@4.21.5)
|
update-browserslist-db: 1.0.10(browserslist@4.21.5)
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/buffer-equal-constant-time@1.0.1:
|
|
||||||
resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/call-bind@1.0.2:
|
/call-bind@1.0.2:
|
||||||
resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==}
|
resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -1006,11 +942,6 @@ packages:
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
fsevents: 2.3.2
|
fsevents: 2.3.2
|
||||||
|
|
||||||
/chownr@2.0.0:
|
|
||||||
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
|
|
||||||
engines: {node: '>=10'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/classnames@2.3.2:
|
/classnames@2.3.2:
|
||||||
resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==}
|
resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -1043,11 +974,6 @@ packages:
|
||||||
/color-name@1.1.4:
|
/color-name@1.1.4:
|
||||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||||
|
|
||||||
/color-support@1.1.3:
|
|
||||||
resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==}
|
|
||||||
hasBin: true
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/colors@1.4.0:
|
/colors@1.4.0:
|
||||||
resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==}
|
resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==}
|
||||||
engines: {node: '>=0.1.90'}
|
engines: {node: '>=0.1.90'}
|
||||||
|
@ -1061,21 +987,14 @@ packages:
|
||||||
/concat-map@0.0.1:
|
/concat-map@0.0.1:
|
||||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||||
|
|
||||||
/console-control-strings@1.1.0:
|
|
||||||
resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/cookie@0.4.2:
|
/cookie@0.4.2:
|
||||||
resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==}
|
resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/cookies-next@2.1.1:
|
/cookie@0.5.0:
|
||||||
resolution: {integrity: sha512-AZGZPdL1hU3jCjN2UMJTGhLOYzNUN9Gm+v8BdptYIHUdwz397Et1p+sZRfvAl8pKnnmMdX2Pk9xDRKCGBum6GA==}
|
resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==}
|
||||||
dependencies:
|
engines: {node: '>= 0.6'}
|
||||||
'@types/cookie': 0.4.1
|
|
||||||
'@types/node': 16.18.23
|
|
||||||
cookie: 0.4.2
|
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/cors@2.8.5:
|
/cors@2.8.5:
|
||||||
|
@ -1168,15 +1087,6 @@ packages:
|
||||||
object-keys: 1.1.1
|
object-keys: 1.1.1
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/delegates@1.0.0:
|
|
||||||
resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/detect-libc@2.0.1:
|
|
||||||
resolution: {integrity: sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==}
|
|
||||||
engines: {node: '>=8'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/didyoumean@1.2.2:
|
/didyoumean@1.2.2:
|
||||||
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
|
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -1205,20 +1115,10 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
esutils: 2.0.3
|
esutils: 2.0.3
|
||||||
|
|
||||||
/ecdsa-sig-formatter@1.0.11:
|
|
||||||
resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==}
|
|
||||||
dependencies:
|
|
||||||
safe-buffer: 5.2.1
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/electron-to-chromium@1.4.356:
|
/electron-to-chromium@1.4.356:
|
||||||
resolution: {integrity: sha512-nEftV1dRX3omlxAj42FwqRZT0i4xd2dIg39sog/CnCJeCcL1TRd2Uh0i9Oebgv8Ou0vzTPw++xc+Z20jzS2B6A==}
|
resolution: {integrity: sha512-nEftV1dRX3omlxAj42FwqRZT0i4xd2dIg39sog/CnCJeCcL1TRd2Uh0i9Oebgv8Ou0vzTPw++xc+Z20jzS2B6A==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/emoji-regex@8.0.0:
|
|
||||||
resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/emoji-regex@9.2.2:
|
/emoji-regex@9.2.2:
|
||||||
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
|
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -1713,13 +1613,6 @@ packages:
|
||||||
resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==}
|
resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/fs-minipass@2.1.0:
|
|
||||||
resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==}
|
|
||||||
engines: {node: '>= 8'}
|
|
||||||
dependencies:
|
|
||||||
minipass: 3.3.6
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/fs.realpath@1.0.0:
|
/fs.realpath@1.0.0:
|
||||||
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
||||||
|
|
||||||
|
@ -1747,21 +1640,6 @@ packages:
|
||||||
resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
|
resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/gauge@3.0.2:
|
|
||||||
resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==}
|
|
||||||
engines: {node: '>=10'}
|
|
||||||
dependencies:
|
|
||||||
aproba: 2.0.0
|
|
||||||
color-support: 1.1.3
|
|
||||||
console-control-strings: 1.1.0
|
|
||||||
has-unicode: 2.0.1
|
|
||||||
object-assign: 4.1.1
|
|
||||||
signal-exit: 3.0.7
|
|
||||||
string-width: 4.2.3
|
|
||||||
strip-ansi: 6.0.1
|
|
||||||
wide-align: 1.1.5
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/get-intrinsic@1.2.0:
|
/get-intrinsic@1.2.0:
|
||||||
resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==}
|
resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -1924,10 +1802,6 @@ packages:
|
||||||
has-symbols: 1.0.3
|
has-symbols: 1.0.3
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/has-unicode@2.0.1:
|
|
||||||
resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/has@1.0.3:
|
/has@1.0.3:
|
||||||
resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
|
resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
|
||||||
engines: {node: '>= 0.4.0'}
|
engines: {node: '>= 0.4.0'}
|
||||||
|
@ -1939,16 +1813,6 @@ packages:
|
||||||
engines: {node: '>= 0.4.0'}
|
engines: {node: '>= 0.4.0'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/https-proxy-agent@5.0.1:
|
|
||||||
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
|
|
||||||
engines: {node: '>= 6'}
|
|
||||||
dependencies:
|
|
||||||
agent-base: 6.0.2
|
|
||||||
debug: 4.3.4
|
|
||||||
transitivePeerDependencies:
|
|
||||||
- supports-color
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/ignore@5.2.4:
|
/ignore@5.2.4:
|
||||||
resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
|
resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
|
||||||
engines: {node: '>= 4'}
|
engines: {node: '>= 4'}
|
||||||
|
@ -2048,11 +1912,6 @@ packages:
|
||||||
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
/is-fullwidth-code-point@3.0.0:
|
|
||||||
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
|
|
||||||
engines: {node: '>=8'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/is-glob@4.0.3:
|
/is-glob@4.0.3:
|
||||||
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
@ -2166,6 +2025,10 @@ packages:
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/jose@4.14.1:
|
||||||
|
resolution: {integrity: sha512-SgjXLpP7jhQkUNKL6RpowoR/IF4QKE+WjLDMpNnh2vmhiFs67NftrNpvFtgbwpvRdtueFliahYYWz9E+XZZQlg==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/js-sdsl@4.4.0:
|
/js-sdsl@4.4.0:
|
||||||
resolution: {integrity: sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==}
|
resolution: {integrity: sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==}
|
||||||
|
|
||||||
|
@ -2197,16 +2060,6 @@ packages:
|
||||||
minimist: 1.2.8
|
minimist: 1.2.8
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/jsonwebtoken@9.0.0:
|
|
||||||
resolution: {integrity: sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==}
|
|
||||||
engines: {node: '>=12', npm: '>=6'}
|
|
||||||
dependencies:
|
|
||||||
jws: 3.2.2
|
|
||||||
lodash: 4.17.21
|
|
||||||
ms: 2.1.3
|
|
||||||
semver: 7.3.8
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/jsx-ast-utils@3.3.3:
|
/jsx-ast-utils@3.3.3:
|
||||||
resolution: {integrity: sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==}
|
resolution: {integrity: sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==}
|
||||||
engines: {node: '>=4.0'}
|
engines: {node: '>=4.0'}
|
||||||
|
@ -2215,21 +2068,6 @@ packages:
|
||||||
object.assign: 4.1.4
|
object.assign: 4.1.4
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/jwa@1.4.1:
|
|
||||||
resolution: {integrity: sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==}
|
|
||||||
dependencies:
|
|
||||||
buffer-equal-constant-time: 1.0.1
|
|
||||||
ecdsa-sig-formatter: 1.0.11
|
|
||||||
safe-buffer: 5.2.1
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/jws@3.2.2:
|
|
||||||
resolution: {integrity: sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==}
|
|
||||||
dependencies:
|
|
||||||
jwa: 1.4.1
|
|
||||||
safe-buffer: 5.2.1
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/language-subtag-registry@0.3.22:
|
/language-subtag-registry@0.3.22:
|
||||||
resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==}
|
resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==}
|
||||||
dev: false
|
dev: false
|
||||||
|
@ -2267,6 +2105,7 @@ packages:
|
||||||
|
|
||||||
/lodash@4.17.21:
|
/lodash@4.17.21:
|
||||||
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
/loose-envify@1.4.0:
|
/loose-envify@1.4.0:
|
||||||
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
|
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
|
||||||
|
@ -2282,13 +2121,6 @@ packages:
|
||||||
yallist: 4.0.0
|
yallist: 4.0.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/make-dir@3.1.0:
|
|
||||||
resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==}
|
|
||||||
engines: {node: '>=8'}
|
|
||||||
dependencies:
|
|
||||||
semver: 6.3.0
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/merge2@1.4.1:
|
/merge2@1.4.1:
|
||||||
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
@ -2321,32 +2153,6 @@ packages:
|
||||||
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
|
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/minipass@3.3.6:
|
|
||||||
resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==}
|
|
||||||
engines: {node: '>=8'}
|
|
||||||
dependencies:
|
|
||||||
yallist: 4.0.0
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/minipass@4.2.5:
|
|
||||||
resolution: {integrity: sha512-+yQl7SX3bIT83Lhb4BVorMAHVuqsskxRdlmO9kTpyukp8vsm2Sn/fUOV9xlnG8/a5JsypJzap21lz/y3FBMJ8Q==}
|
|
||||||
engines: {node: '>=8'}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/minizlib@2.1.2:
|
|
||||||
resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==}
|
|
||||||
engines: {node: '>= 8'}
|
|
||||||
dependencies:
|
|
||||||
minipass: 3.3.6
|
|
||||||
yallist: 4.0.0
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/mkdirp@1.0.4:
|
|
||||||
resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==}
|
|
||||||
engines: {node: '>=10'}
|
|
||||||
hasBin: true
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/ms@2.1.2:
|
/ms@2.1.2:
|
||||||
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
||||||
|
|
||||||
|
@ -2375,6 +2181,32 @@ packages:
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/next-auth@4.22.1(next@13.1.1)(nodemailer@6.9.1)(react-dom@18.2.0)(react@18.2.0):
|
||||||
|
resolution: {integrity: sha512-NTR3f6W7/AWXKw8GSsgSyQcDW6jkslZLH8AiZa5PQ09w1kR8uHtR9rez/E9gAq/o17+p0JYHE8QjF3RoniiObA==}
|
||||||
|
peerDependencies:
|
||||||
|
next: ^12.2.5 || ^13
|
||||||
|
nodemailer: ^6.6.5
|
||||||
|
react: ^17.0.2 || ^18
|
||||||
|
react-dom: ^17.0.2 || ^18
|
||||||
|
peerDependenciesMeta:
|
||||||
|
nodemailer:
|
||||||
|
optional: true
|
||||||
|
dependencies:
|
||||||
|
'@babel/runtime': 7.21.0
|
||||||
|
'@panva/hkdf': 1.0.4
|
||||||
|
cookie: 0.5.0
|
||||||
|
jose: 4.14.1
|
||||||
|
next: 13.1.1(react-dom@18.2.0)(react@18.2.0)(sass@1.61.0)
|
||||||
|
nodemailer: 6.9.1
|
||||||
|
oauth: 0.9.15
|
||||||
|
openid-client: 5.4.1
|
||||||
|
preact: 10.13.2
|
||||||
|
preact-render-to-string: 5.2.6(preact@10.13.2)
|
||||||
|
react: 18.2.0
|
||||||
|
react-dom: 18.2.0(react@18.2.0)
|
||||||
|
uuid: 8.3.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/next@13.1.1(react-dom@18.2.0)(react@18.2.0)(sass@1.61.0):
|
/next@13.1.1(react-dom@18.2.0)(react@18.2.0)(sass@1.61.0):
|
||||||
resolution: {integrity: sha512-R5eBAaIa3X7LJeYvv1bMdGnAVF4fVToEjim7MkflceFPuANY3YyvFxXee/A+acrSYwYPvOvf7f6v/BM/48ea5w==}
|
resolution: {integrity: sha512-R5eBAaIa3X7LJeYvv1bMdGnAVF4fVToEjim7MkflceFPuANY3YyvFxXee/A+acrSYwYPvOvf7f6v/BM/48ea5w==}
|
||||||
engines: {node: '>=14.6.0'}
|
engines: {node: '>=14.6.0'}
|
||||||
|
@ -2420,32 +2252,13 @@ packages:
|
||||||
- babel-plugin-macros
|
- babel-plugin-macros
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/node-addon-api@5.1.0:
|
|
||||||
resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/node-fetch@2.6.9:
|
|
||||||
resolution: {integrity: sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==}
|
|
||||||
engines: {node: 4.x || >=6.0.0}
|
|
||||||
peerDependencies:
|
|
||||||
encoding: ^0.1.0
|
|
||||||
peerDependenciesMeta:
|
|
||||||
encoding:
|
|
||||||
optional: true
|
|
||||||
dependencies:
|
|
||||||
whatwg-url: 5.0.0
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/node-releases@2.0.10:
|
/node-releases@2.0.10:
|
||||||
resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==}
|
resolution: {integrity: sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w==}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/nopt@5.0.0:
|
/nodemailer@6.9.1:
|
||||||
resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==}
|
resolution: {integrity: sha512-qHw7dOiU5UKNnQpXktdgQ1d3OFgRAekuvbJLcdG5dnEo/GtcTHRYM7+UfJARdOFU9WUQO8OiIamgWPmiSFHYAA==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6.0.0'}
|
||||||
hasBin: true
|
|
||||||
dependencies:
|
|
||||||
abbrev: 1.1.1
|
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/normalize-path@3.0.0:
|
/normalize-path@3.0.0:
|
||||||
|
@ -2457,19 +2270,19 @@ packages:
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/npmlog@5.0.1:
|
/oauth@0.9.15:
|
||||||
resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==}
|
resolution: {integrity: sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==}
|
||||||
dependencies:
|
|
||||||
are-we-there-yet: 2.0.0
|
|
||||||
console-control-strings: 1.1.0
|
|
||||||
gauge: 3.0.2
|
|
||||||
set-blocking: 2.0.0
|
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/object-assign@4.1.1:
|
/object-assign@4.1.1:
|
||||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
/object-hash@2.2.0:
|
||||||
|
resolution: {integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==}
|
||||||
|
engines: {node: '>= 6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/object-hash@3.0.0:
|
/object-hash@3.0.0:
|
||||||
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
|
resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==}
|
||||||
engines: {node: '>= 6'}
|
engines: {node: '>= 6'}
|
||||||
|
@ -2536,6 +2349,11 @@ packages:
|
||||||
es-abstract: 1.21.2
|
es-abstract: 1.21.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/oidc-token-hash@5.0.2:
|
||||||
|
resolution: {integrity: sha512-U91Ba78GtVBxcExLI7U+hC2AwJQqXQEW/D3fjmJC4hhSVIgdl954KO4Gu95WqAlgDKJdLATxkmuxraWLT0fVRQ==}
|
||||||
|
engines: {node: ^10.13.0 || >=12.0.0}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/once@1.4.0:
|
/once@1.4.0:
|
||||||
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
|
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -2550,6 +2368,15 @@ packages:
|
||||||
is-wsl: 2.2.0
|
is-wsl: 2.2.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/openid-client@5.4.1:
|
||||||
|
resolution: {integrity: sha512-z19tZRY1CvpDf9L8nFyv5LW3CWoRDuz8EdmUFyouUrf5FDZitaJ8C+tIHF6WnjA2DPG4Fu2JWkNjexNzLWjh3Q==}
|
||||||
|
dependencies:
|
||||||
|
jose: 4.14.1
|
||||||
|
lru-cache: 6.0.0
|
||||||
|
object-hash: 2.2.0
|
||||||
|
oidc-token-hash: 5.0.2
|
||||||
|
dev: false
|
||||||
|
|
||||||
/optionator@0.9.1:
|
/optionator@0.9.1:
|
||||||
resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==}
|
resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
@ -2695,6 +2522,19 @@ packages:
|
||||||
source-map-js: 1.0.2
|
source-map-js: 1.0.2
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/preact-render-to-string@5.2.6(preact@10.13.2):
|
||||||
|
resolution: {integrity: sha512-JyhErpYOvBV1hEPwIxc/fHWXPfnEGdRKxc8gFdAZ7XV4tlzyzG847XAyEZqoDnynP88akM4eaHcSOzNcLWFguw==}
|
||||||
|
peerDependencies:
|
||||||
|
preact: '>=10'
|
||||||
|
dependencies:
|
||||||
|
preact: 10.13.2
|
||||||
|
pretty-format: 3.8.0
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/preact@10.13.2:
|
||||||
|
resolution: {integrity: sha512-q44QFLhOhty2Bd0Y46fnYW0gD/cbVM9dUVtNTDKPcdXSMA7jfY+Jpd6rk3GB0lcQss0z5s/6CmVP0Z/hV+g6pw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/prelude-ls@1.2.1:
|
/prelude-ls@1.2.1:
|
||||||
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
||||||
engines: {node: '>= 0.8.0'}
|
engines: {node: '>= 0.8.0'}
|
||||||
|
@ -2761,6 +2601,10 @@ packages:
|
||||||
hasBin: true
|
hasBin: true
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/pretty-format@3.8.0:
|
||||||
|
resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/prisma@4.12.0:
|
/prisma@4.12.0:
|
||||||
resolution: {integrity: sha512-xqVper4mbwl32BWzLpdznHAYvYDWQQWK2tBfXjdUD397XaveRyAP7SkBZ6kFlIg8kKayF4hvuaVtYwXd9BodAg==}
|
resolution: {integrity: sha512-xqVper4mbwl32BWzLpdznHAYvYDWQQWK2tBfXjdUD397XaveRyAP7SkBZ6kFlIg8kKayF4hvuaVtYwXd9BodAg==}
|
||||||
engines: {node: '>=14.17'}
|
engines: {node: '>=14.17'}
|
||||||
|
@ -2838,15 +2682,6 @@ packages:
|
||||||
pify: 2.3.0
|
pify: 2.3.0
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
/readable-stream@3.6.2:
|
|
||||||
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
|
|
||||||
engines: {node: '>= 6'}
|
|
||||||
dependencies:
|
|
||||||
inherits: 2.0.4
|
|
||||||
string_decoder: 1.3.0
|
|
||||||
util-deprecate: 1.0.2
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/readdirp@3.6.0:
|
/readdirp@3.6.0:
|
||||||
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
|
resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
|
||||||
engines: {node: '>=8.10.0'}
|
engines: {node: '>=8.10.0'}
|
||||||
|
@ -2906,10 +2741,6 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
queue-microtask: 1.2.3
|
queue-microtask: 1.2.3
|
||||||
|
|
||||||
/safe-buffer@5.2.1:
|
|
||||||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/safe-regex-test@1.0.0:
|
/safe-regex-test@1.0.0:
|
||||||
resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==}
|
resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -2946,10 +2777,6 @@ packages:
|
||||||
lru-cache: 6.0.0
|
lru-cache: 6.0.0
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/set-blocking@2.0.0:
|
|
||||||
resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/shebang-command@2.0.0:
|
/shebang-command@2.0.0:
|
||||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -2968,10 +2795,6 @@ packages:
|
||||||
object-inspect: 1.12.3
|
object-inspect: 1.12.3
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/signal-exit@3.0.7:
|
|
||||||
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/slash@3.0.0:
|
/slash@3.0.0:
|
||||||
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
|
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -3047,15 +2870,6 @@ packages:
|
||||||
internal-slot: 1.0.5
|
internal-slot: 1.0.5
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/string-width@4.2.3:
|
|
||||||
resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==}
|
|
||||||
engines: {node: '>=8'}
|
|
||||||
dependencies:
|
|
||||||
emoji-regex: 8.0.0
|
|
||||||
is-fullwidth-code-point: 3.0.0
|
|
||||||
strip-ansi: 6.0.1
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/string.prototype.matchall@4.0.8:
|
/string.prototype.matchall@4.0.8:
|
||||||
resolution: {integrity: sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==}
|
resolution: {integrity: sha512-6zOCOcJ+RJAQshcTvXPHoxoQGONa3e/Lqx90wUA+wEzX78sg5Bo+1tQo4N0pohS0erG9qtCqJDjNCQBjeWVxyg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -3094,12 +2908,6 @@ packages:
|
||||||
es-abstract: 1.21.2
|
es-abstract: 1.21.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/string_decoder@1.3.0:
|
|
||||||
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
|
|
||||||
dependencies:
|
|
||||||
safe-buffer: 5.2.1
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/strip-ansi@6.0.1:
|
/strip-ansi@6.0.1:
|
||||||
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
|
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
@ -3210,18 +3018,6 @@ packages:
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/tar@6.1.13:
|
|
||||||
resolution: {integrity: sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==}
|
|
||||||
engines: {node: '>=10'}
|
|
||||||
dependencies:
|
|
||||||
chownr: 2.0.0
|
|
||||||
fs-minipass: 2.1.0
|
|
||||||
minipass: 4.2.5
|
|
||||||
minizlib: 2.1.2
|
|
||||||
mkdirp: 1.0.4
|
|
||||||
yallist: 4.0.0
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/text-table@0.2.0:
|
/text-table@0.2.0:
|
||||||
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
|
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
|
||||||
|
|
||||||
|
@ -3256,10 +3052,6 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-number: 7.0.0
|
is-number: 7.0.0
|
||||||
|
|
||||||
/tr46@0.0.3:
|
|
||||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/ts-interface-checker@0.1.13:
|
/ts-interface-checker@0.1.13:
|
||||||
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
|
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
|
||||||
dev: true
|
dev: true
|
||||||
|
@ -3324,6 +3116,11 @@ packages:
|
||||||
which-boxed-primitive: 1.0.2
|
which-boxed-primitive: 1.0.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/unique-names-generator@4.7.1:
|
||||||
|
resolution: {integrity: sha512-lMx9dX+KRmG8sq6gulYYpKWZc9RlGsgBR6aoO8Qsm3qvkSJ+3rAymr+TnV8EDMrIrwuFJ4kruzMWM/OpYzPoow==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/update-browserslist-db@1.0.10(browserslist@4.21.5):
|
/update-browserslist-db@1.0.10(browserslist@4.21.5):
|
||||||
resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==}
|
resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
@ -3342,23 +3139,18 @@ packages:
|
||||||
|
|
||||||
/util-deprecate@1.0.2:
|
/util-deprecate@1.0.2:
|
||||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/uuid@8.3.2:
|
||||||
|
resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==}
|
||||||
|
hasBin: true
|
||||||
|
dev: false
|
||||||
|
|
||||||
/vary@1.1.2:
|
/vary@1.1.2:
|
||||||
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
|
resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
/webidl-conversions@3.0.1:
|
|
||||||
resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==}
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/whatwg-url@5.0.0:
|
|
||||||
resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==}
|
|
||||||
dependencies:
|
|
||||||
tr46: 0.0.3
|
|
||||||
webidl-conversions: 3.0.1
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/which-boxed-primitive@1.0.2:
|
/which-boxed-primitive@1.0.2:
|
||||||
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
|
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
|
||||||
dependencies:
|
dependencies:
|
||||||
|
@ -3397,12 +3189,6 @@ packages:
|
||||||
dependencies:
|
dependencies:
|
||||||
isexe: 2.0.0
|
isexe: 2.0.0
|
||||||
|
|
||||||
/wide-align@1.1.5:
|
|
||||||
resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==}
|
|
||||||
dependencies:
|
|
||||||
string-width: 4.2.3
|
|
||||||
dev: false
|
|
||||||
|
|
||||||
/word-wrap@1.2.3:
|
/word-wrap@1.2.3:
|
||||||
resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==}
|
resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
|
@ -7,17 +7,61 @@ datasource db {
|
||||||
url = env("DATABASE_URL")
|
url = env("DATABASE_URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
model Player {
|
model Account {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
createdAt DateTime @default(now())
|
userId String @map("user_id")
|
||||||
updatedAt DateTime @updatedAt
|
type String
|
||||||
deleted Boolean @default(false)
|
provider String
|
||||||
anonymous Boolean @default(true)
|
providerAccountId String @map("provider_account_id")
|
||||||
username String? @unique
|
refresh_token String? @db.Text
|
||||||
email String? @unique
|
access_token String? @db.Text
|
||||||
passwordHash String? @unique
|
expires_at Int?
|
||||||
tokens Token[]
|
ext_expires_in Int?
|
||||||
games Player_Game[]
|
token_type String?
|
||||||
|
scope String?
|
||||||
|
id_token String? @db.Text
|
||||||
|
session_state String?
|
||||||
|
oauth_token_secret String?
|
||||||
|
oauth_token String?
|
||||||
|
|
||||||
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
@@unique([provider, providerAccountId])
|
||||||
|
@@map("accounts")
|
||||||
|
}
|
||||||
|
|
||||||
|
model Session {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
sessionToken String @unique @map("session_token")
|
||||||
|
userId String @map("user_id")
|
||||||
|
expires DateTime
|
||||||
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||||
|
|
||||||
|
@@map("sessions")
|
||||||
|
}
|
||||||
|
|
||||||
|
model User {
|
||||||
|
id String @id @default(cuid())
|
||||||
|
name String?
|
||||||
|
email String? @unique
|
||||||
|
emailVerified DateTime? @map("email_verified")
|
||||||
|
image String? @db.Text
|
||||||
|
createdAt DateTime @default(now()) @map(name: "created_at")
|
||||||
|
updatedAt DateTime @updatedAt @map(name: "updated_at")
|
||||||
|
games User_Game[]
|
||||||
|
accounts Account[]
|
||||||
|
sessions Session[]
|
||||||
|
|
||||||
|
@@map(name: "users")
|
||||||
|
}
|
||||||
|
|
||||||
|
model VerificationToken {
|
||||||
|
identifier String
|
||||||
|
token String @unique
|
||||||
|
expires DateTime
|
||||||
|
|
||||||
|
@@unique([identifier, token])
|
||||||
|
@@map("verificationtokens")
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TokenType {
|
enum TokenType {
|
||||||
|
@ -25,45 +69,35 @@ enum TokenType {
|
||||||
ACCESS
|
ACCESS
|
||||||
}
|
}
|
||||||
|
|
||||||
model Token {
|
|
||||||
id String @id @default(cuid())
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
type TokenType
|
|
||||||
used Boolean @default(false)
|
|
||||||
ownerId String
|
|
||||||
owner Player @relation(fields: [ownerId], references: [id])
|
|
||||||
Socket Socket?
|
|
||||||
}
|
|
||||||
|
|
||||||
model Game {
|
model Game {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @updatedAt
|
updatedAt DateTime @updatedAt
|
||||||
running Boolean @default(true)
|
running Boolean @default(true)
|
||||||
pin Gamepin?
|
gamePin Gamepin?
|
||||||
players Player_Game[]
|
users User_Game[]
|
||||||
}
|
}
|
||||||
|
|
||||||
model Player_Game {
|
model User_Game {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
gameId String
|
gameId String
|
||||||
playerId String
|
userId String
|
||||||
isOwner Boolean
|
isOwner Boolean
|
||||||
moves Move[]
|
moves Move[]
|
||||||
chats Chat[]
|
chats Chat[]
|
||||||
game Game @relation(fields: [gameId], references: [id])
|
game Game @relation(fields: [gameId], references: [id])
|
||||||
player Player @relation(fields: [playerId], references: [id])
|
user User @relation(fields: [userId], references: [id])
|
||||||
|
|
||||||
@@unique([gameId, playerId])
|
@@unique([gameId, userId])
|
||||||
}
|
}
|
||||||
|
|
||||||
model Move {
|
model Move {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
index Int
|
index Int
|
||||||
gameId String
|
gameId String
|
||||||
game Player_Game @relation(fields: [gameId], references: [id])
|
game User_Game @relation(fields: [gameId], references: [id])
|
||||||
}
|
}
|
||||||
|
|
||||||
model Gamepin {
|
model Gamepin {
|
||||||
|
@ -75,17 +109,10 @@ model Gamepin {
|
||||||
}
|
}
|
||||||
|
|
||||||
model Chat {
|
model Chat {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
message String?
|
message String?
|
||||||
event String?
|
event String?
|
||||||
gameId String
|
gameId String
|
||||||
game Player_Game @relation(fields: [gameId], references: [id])
|
game User_Game @relation(fields: [gameId], references: [id])
|
||||||
}
|
|
||||||
|
|
||||||
model Socket {
|
|
||||||
sessionId String @id
|
|
||||||
createdAt DateTime @default(now())
|
|
||||||
tokenId String @unique
|
|
||||||
token Token @relation(fields: [tokenId], references: [id])
|
|
||||||
}
|
}
|
||||||
|
|
12
leaky-ships/types/next-auth.d.ts
vendored
Normal file
12
leaky-ships/types/next-auth.d.ts
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import NextAuth, { DefaultSession } from "next-auth"
|
||||||
|
|
||||||
|
declare module "next-auth" {
|
||||||
|
/**
|
||||||
|
* Returned by `useSession`, `getSession` and received as a prop on the `SessionProvider` React Context
|
||||||
|
*/
|
||||||
|
interface Session {
|
||||||
|
user: {
|
||||||
|
id: string
|
||||||
|
} & DefaultSession["user"]
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue