Migration from Prisma to Drizzle-ORM

This commit is contained in:
aronmal 2023-08-19 23:16:49 +02:00
parent ed472e40ed
commit 2479dd518d
Signed by: aronmal
GPG key ID: 816B7707426FC612
30 changed files with 1018 additions and 6504 deletions

View file

@ -53,8 +53,7 @@ jobs:
- name: 'Compiling page' - name: 'Compiling page'
run: | run: |
echo "${{ secrets.ENV_FILE }}" > .env echo "${{ secrets.ENV_FILE }}" > .env
pnpm prisma generate pnpm build
pnpm run build
- name: Run Playwright tests - name: Run Playwright tests
run: pnpm playwright test run: pnpm playwright test

View file

@ -3,8 +3,8 @@
# logs # logs
/log /log
# prisma # drizzle
/prisma/migrations /drizzle/migrations
# dependencies # dependencies
/node_modules /node_modules

View file

@ -0,0 +1,11 @@
import "dotenv/config"
import type { Config } from "drizzle-kit"
export default {
schema: "./src/drizzle/schema.ts",
out: "./src/drizzle/migrations",
driver: "pg",
dbCredentials: {
connectionString: process.env.DATABASE_URL ?? "",
},
} satisfies Config

View file

@ -5,7 +5,9 @@ import {
type Page, type Page,
} from "@playwright/test" } from "@playwright/test"
import { createHash, randomBytes } from "crypto" import { createHash, randomBytes } from "crypto"
import prisma from "~/lib/prisma" import { and, desc, eq } from "drizzle-orm"
import db from "~/drizzle"
import { verificationTokens } from "~/drizzle/schemas/Tables"
const callbackUrl = process.env.NEXTAUTH_URL + "/" const callbackUrl = process.env.NEXTAUTH_URL + "/"
const player1Email = (browser: Browser) => const player1Email = (browser: Browser) =>
@ -46,20 +48,20 @@ test.describe.serial("Check Email auth", () => {
.update(`${token}${process.env.AUTH_SECRET}`) .update(`${token}${process.env.AUTH_SECRET}`)
.digest("hex") .digest("hex")
// Use Prisma to fetch the latest token for the email // Use drizzle to fetch the latest token for the email
const latestToken = await prisma.verificationToken.findFirst({ const latestToken = await db.query.verificationTokens.findFirst({
where: { identifier: player1Email(browser) }, where: eq(verificationTokens.identifier, player1Email(browser)),
orderBy: { expires: "desc" }, orderBy: [desc(verificationTokens.expires)],
})
await prisma.verificationToken.update({
where: {
identifier_token: {
identifier: player1Email(browser),
token: latestToken?.token ?? "",
},
},
data: { token: hash },
}) })
await db
.update(verificationTokens)
.set({ token: hash })
.where(
and(
eq(verificationTokens.identifier, player1Email(browser)),
eq(verificationTokens.token, latestToken?.token ?? ""),
),
)
const params = new URLSearchParams({ const params = new URLSearchParams({
callbackUrl, callbackUrl,

View file

@ -1,6 +0,0 @@
import { PrismaClient } from "@prisma/client"
import "@total-typescript/ts-reset"
declare global {
let prismaClient: PrismaClient
}

View file

@ -5,14 +5,13 @@
"start": "solid-start start --port 3000", "start": "solid-start start --port 3000",
"build": "solid-start build", "build": "solid-start build",
"lint": "eslint --fix \"**/*.{ts,tsx,js,jsx}\"", "lint": "eslint --fix \"**/*.{ts,tsx,js,jsx}\"",
"push": "prisma db push", "push": "drizzle-kit push:pg",
"postinstall": "prisma generate",
"test": "pnpm playwright test --ui" "test": "pnpm playwright test --ui"
}, },
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"@auth/core": "0.12.0", "@auth/core": "0.12.0",
"@auth/prisma-adapter": "^1.0.1", "@auth/drizzle-adapter": "^0.3.1",
"@auth/solid-start": "^0.1.1", "@auth/solid-start": "^0.1.1",
"@fortawesome/fontawesome-svg-core": "^6.4.2", "@fortawesome/fontawesome-svg-core": "^6.4.2",
"@fortawesome/pro-duotone-svg-icons": "^6.4.2", "@fortawesome/pro-duotone-svg-icons": "^6.4.2",
@ -22,22 +21,23 @@
"@fortawesome/pro-thin-svg-icons": "^6.4.2", "@fortawesome/pro-thin-svg-icons": "^6.4.2",
"@fortawesome/react-fontawesome": "^0.2.0", "@fortawesome/react-fontawesome": "^0.2.0",
"@fortawesome/sharp-solid-svg-icons": "^6.4.2", "@fortawesome/sharp-solid-svg-icons": "^6.4.2",
"@prisma/client": "^5.1.1", "@paralleldrive/cuid2": "^2.2.2",
"@solidjs/meta": "^0.28.6", "@solidjs/meta": "^0.28.6",
"@solidjs/router": "^0.8.3", "@solidjs/router": "^0.8.3",
"classnames": "^2.3.2", "classnames": "^2.3.2",
"colors": "^1.4.0", "colors": "^1.4.0",
"drizzle-orm": "^0.28.2",
"drizzle-zod": "^0.5.0",
"http-status": "^1.6.2", "http-status": "^1.6.2",
"nodemailer": "6.9.4", "nodemailer": "6.9.4",
"prisma": "^5.1.1", "postgres": "^3.3.5",
"socket.io": "^4.7.2", "socket.io": "^4.7.2",
"socket.io-client": "^4.7.2", "socket.io-client": "^4.7.2",
"solid-js": "^1.7.11", "solid-js": "^1.7.11",
"solid-start": "^0.3.3", "solid-start": "^0.3.3",
"solid-zustand": "^1.7.0", "solid-zustand": "^1.7.0",
"unique-names-generator": "^4.7.1", "unique-names-generator": "^4.7.1",
"zod": "3.21.1", "zod": "3.21.1"
"zod-prisma-types": "^2.7.9"
}, },
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.37.0", "@playwright/test": "^1.37.0",
@ -48,9 +48,11 @@
"@typescript-eslint/eslint-plugin": "^6.4.0", "@typescript-eslint/eslint-plugin": "^6.4.0",
"autoprefixer": "^10.4.15", "autoprefixer": "^10.4.15",
"dotenv": "^16.3.1", "dotenv": "^16.3.1",
"drizzle-kit": "^0.19.12",
"eslint": "^8.47.0", "eslint": "^8.47.0",
"eslint-config-prettier": "^9.0.0", "eslint-config-prettier": "^9.0.0",
"eslint-plugin-solid": "^0.12.1", "eslint-plugin-solid": "^0.12.1",
"pg": "^8.11.2",
"postcss": "^8.4.28", "postcss": "^8.4.28",
"prettier": "^3.0.2", "prettier": "^3.0.2",
"prettier-plugin-organize-imports": "^3.2.3", "prettier-plugin-organize-imports": "^3.2.3",

View file

@ -8,9 +8,9 @@ dependencies:
'@auth/core': '@auth/core':
specifier: 0.12.0 specifier: 0.12.0
version: 0.12.0(nodemailer@6.9.4) version: 0.12.0(nodemailer@6.9.4)
'@auth/prisma-adapter': '@auth/drizzle-adapter':
specifier: ^1.0.1 specifier: ^0.3.1
version: 1.0.1(@prisma/client@5.1.1)(nodemailer@6.9.4) version: 0.3.1(nodemailer@6.9.4)
'@auth/solid-start': '@auth/solid-start':
specifier: ^0.1.1 specifier: ^0.1.1
version: 0.1.1(@auth/core@0.12.0)(solid-js@1.7.11)(solid-start@0.3.3) version: 0.1.1(@auth/core@0.12.0)(solid-js@1.7.11)(solid-start@0.3.3)
@ -38,9 +38,9 @@ dependencies:
'@fortawesome/sharp-solid-svg-icons': '@fortawesome/sharp-solid-svg-icons':
specifier: ^6.4.2 specifier: ^6.4.2
version: 6.4.2 version: 6.4.2
'@prisma/client': '@paralleldrive/cuid2':
specifier: ^5.1.1 specifier: ^2.2.2
version: 5.1.1(prisma@5.1.1) version: 2.2.2
'@solidjs/meta': '@solidjs/meta':
specifier: ^0.28.6 specifier: ^0.28.6
version: 0.28.6(solid-js@1.7.11) version: 0.28.6(solid-js@1.7.11)
@ -53,15 +53,21 @@ dependencies:
colors: colors:
specifier: ^1.4.0 specifier: ^1.4.0
version: 1.4.0 version: 1.4.0
drizzle-orm:
specifier: ^0.28.2
version: 0.28.2(pg@8.11.2)(postgres@3.3.5)
drizzle-zod:
specifier: ^0.5.0
version: 0.5.0(drizzle-orm@0.28.2)(zod@3.21.1)
http-status: http-status:
specifier: ^1.6.2 specifier: ^1.6.2
version: 1.6.2 version: 1.6.2
nodemailer: nodemailer:
specifier: 6.9.4 specifier: 6.9.4
version: 6.9.4 version: 6.9.4
prisma: postgres:
specifier: ^5.1.1 specifier: ^3.3.5
version: 5.1.1 version: 3.3.5
socket.io: socket.io:
specifier: ^4.7.2 specifier: ^4.7.2
version: 4.7.2 version: 4.7.2
@ -83,9 +89,6 @@ dependencies:
zod: zod:
specifier: 3.21.1 specifier: 3.21.1
version: 3.21.1 version: 3.21.1
zod-prisma-types:
specifier: ^2.7.9
version: 2.7.9
devDependencies: devDependencies:
'@playwright/test': '@playwright/test':
@ -112,6 +115,9 @@ devDependencies:
dotenv: dotenv:
specifier: ^16.3.1 specifier: ^16.3.1
version: 16.3.1 version: 16.3.1
drizzle-kit:
specifier: ^0.19.12
version: 0.19.12
eslint: eslint:
specifier: ^8.47.0 specifier: ^8.47.0
version: 8.47.0 version: 8.47.0
@ -121,6 +127,9 @@ devDependencies:
eslint-plugin-solid: eslint-plugin-solid:
specifier: ^0.12.1 specifier: ^0.12.1
version: 0.12.1(eslint@8.47.0)(typescript@5.1.6) version: 0.12.1(eslint@8.47.0)(typescript@5.1.6)
pg:
specifier: ^8.11.2
version: 8.11.2
postcss: postcss:
specifier: ^8.4.28 specifier: ^8.4.28
version: 8.4.28 version: 8.4.28
@ -171,6 +180,23 @@ packages:
/@antfu/utils@0.7.6: /@antfu/utils@0.7.6:
resolution: {integrity: sha512-pvFiLP2BeOKA/ZOS6jxx4XhKzdVLHDhGlFEaZ2flWWYf2xOqVniqpk38I04DFRyz+L0ASggl7SkItTc+ZLju4w==} resolution: {integrity: sha512-pvFiLP2BeOKA/ZOS6jxx4XhKzdVLHDhGlFEaZ2flWWYf2xOqVniqpk38I04DFRyz+L0ASggl7SkItTc+ZLju4w==}
/@auth/core@0.11.1(nodemailer@6.9.4):
resolution: {integrity: sha512-PzvebszgJ4NpQNz8Fsjn39oEY8MzULKppr7Um7DX/HLrS3zthgLY0yAnwkA+2/kxwAb36dIkX+C72q6TziiTaA==}
peerDependencies:
nodemailer: ^6.8.0
peerDependenciesMeta:
nodemailer:
optional: true
dependencies:
'@panva/hkdf': 1.1.1
cookie: 0.5.0
jose: 4.14.4
nodemailer: 6.9.4
oauth4webapi: 2.3.0
preact: 10.11.3
preact-render-to-string: 5.2.3(preact@10.11.3)
dev: false
/@auth/core@0.12.0(nodemailer@6.9.4): /@auth/core@0.12.0(nodemailer@6.9.4):
resolution: {integrity: sha512-XYipdAc/nKu014VOgpcPyLlj1ghWlnwyloaB1UjQd9ElZRZQ9YpSizzXGLON23t/a0FyabOBBl0/awD2tW58Rg==} resolution: {integrity: sha512-XYipdAc/nKu014VOgpcPyLlj1ghWlnwyloaB1UjQd9ElZRZQ9YpSizzXGLON23t/a0FyabOBBl0/awD2tW58Rg==}
peerDependencies: peerDependencies:
@ -188,30 +214,10 @@ packages:
preact-render-to-string: 5.2.3(preact@10.11.3) preact-render-to-string: 5.2.3(preact@10.11.3)
dev: false dev: false
/@auth/core@0.9.0(nodemailer@6.9.4): /@auth/drizzle-adapter@0.3.1(nodemailer@6.9.4):
resolution: {integrity: sha512-W2WO0WCBg1T3P8+yjQPzurTQhPv6ecBYfJ2oE3uvXPAX5ZLWAMSjKFAIa9oLZy5pwrB+YehJZPnlIxVilhrVcg==} resolution: {integrity: sha512-zSuewnrozY0EZYVrt2T5VY0R+wA3chXncanmUgvAgoX+pcussKMVFmnSrSYuc3i4vfM2qCmAa6S6dkSH5RViSA==}
peerDependencies:
nodemailer: ^6.8.0
peerDependenciesMeta:
nodemailer:
optional: true
dependencies: dependencies:
'@panva/hkdf': 1.1.1 '@auth/core': 0.11.1(nodemailer@6.9.4)
cookie: 0.5.0
jose: 4.14.4
nodemailer: 6.9.4
oauth4webapi: 2.3.0
preact: 10.11.3
preact-render-to-string: 5.2.3(preact@10.11.3)
dev: false
/@auth/prisma-adapter@1.0.1(@prisma/client@5.1.1)(nodemailer@6.9.4):
resolution: {integrity: sha512-sBp9l/jVr7l9y7rp2Pv6eoP7i8X2CgRNE3jDWJ0B/u+HnKRofXflD1cldPqRSAkJhqH3UxhVtMTEijT9FoofmQ==}
peerDependencies:
'@prisma/client': '>=2.26.0 || >=3 || >=4'
dependencies:
'@auth/core': 0.9.0(nodemailer@6.9.4)
'@prisma/client': 5.1.1(prisma@5.1.1)
transitivePeerDependencies: transitivePeerDependencies:
- nodemailer - nodemailer
dev: false dev: false
@ -1325,6 +1331,24 @@ packages:
'@babel/helper-validator-identifier': 7.22.5 '@babel/helper-validator-identifier': 7.22.5
to-fast-properties: 2.0.0 to-fast-properties: 2.0.0
/@drizzle-team/studio@0.0.5:
resolution: {integrity: sha512-ps5qF0tMxWRVu+V5gvCRrQNqlY92aTnIKdq27gm9LZMSdaKYZt6AVvSK1dlUMzs6Rt0Jm80b+eWct6xShBKhIw==}
dev: true
/@esbuild-kit/core-utils@3.1.0:
resolution: {integrity: sha512-Uuk8RpCg/7fdHSceR1M6XbSZFSuMrxcePFuGgyvsBn+u339dk5OeL4jv2EojwTN2st/unJGsVm4qHWjWNmJ/tw==}
dependencies:
esbuild: 0.17.19
source-map-support: 0.5.21
dev: true
/@esbuild-kit/esm-loader@2.5.5:
resolution: {integrity: sha512-Qwfvj/qoPbClxCRNuac1Du01r9gvNOT+pMYtJDapfB1eoGN1YlJ1BixLyL9WVENRx5RXgNLdfYdx/CuswlGhMw==}
dependencies:
'@esbuild-kit/core-utils': 3.1.0
get-tsconfig: 4.7.0
dev: true
/@esbuild/android-arm64@0.17.19: /@esbuild/android-arm64@0.17.19:
resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==} resolution: {integrity: sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -1846,6 +1870,11 @@ packages:
'@jridgewell/resolve-uri': 3.1.1 '@jridgewell/resolve-uri': 3.1.1
'@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/sourcemap-codec': 1.4.15
/@noble/hashes@1.3.1:
resolution: {integrity: sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==}
engines: {node: '>= 16'}
dev: false
/@nodelib/fs.scandir@2.1.5: /@nodelib/fs.scandir@2.1.5:
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
@ -1868,6 +1897,12 @@ packages:
resolution: {integrity: sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA==} resolution: {integrity: sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA==}
dev: false dev: false
/@paralleldrive/cuid2@2.2.2:
resolution: {integrity: sha512-ZOBkgDwEdoYVlSeRbYYXs0S9MejQofiVYoTbKzy/6GQa39/q5tQU2IX46+shYnUkpEl3wc+J6wRlar7r2EK2xA==}
dependencies:
'@noble/hashes': 1.3.1
dev: false
/@playwright/test@1.37.0: /@playwright/test@1.37.0:
resolution: {integrity: sha512-181WBLk4SRUyH1Q96VZl7BP6HcK0b7lbdeKisn3N/vnjitk+9HbdlFz/L5fey05vxaAhldIDnzo8KUoy8S3mmQ==} resolution: {integrity: sha512-181WBLk4SRUyH1Q96VZl7BP6HcK0b7lbdeKisn3N/vnjitk+9HbdlFz/L5fey05vxaAhldIDnzo8KUoy8S3mmQ==}
engines: {node: '>=16'} engines: {node: '>=16'}
@ -1882,50 +1917,6 @@ packages:
/@polka/url@1.0.0-next.21: /@polka/url@1.0.0-next.21:
resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==} resolution: {integrity: sha512-a5Sab1C4/icpTZVzZc5Ghpz88yQtGOyNqYXcZgOssB2uuAr+wF/MvN6bgtW32q7HHrvBki+BsZ0OuNv6EV3K9g==}
/@prisma/client@5.1.1(prisma@5.1.1):
resolution: {integrity: sha512-fxcCeK5pMQGcgCqCrWsi+I2rpIbk0rAhdrN+ke7f34tIrgPwA68ensrpin+9+fZvuV2OtzHmuipwduSY6HswdA==}
engines: {node: '>=16.13'}
requiresBuild: true
peerDependencies:
prisma: '*'
peerDependenciesMeta:
prisma:
optional: true
dependencies:
'@prisma/engines-version': 5.1.1-1.6a3747c37ff169c90047725a05a6ef02e32ac97e
prisma: 5.1.1
dev: false
/@prisma/debug@5.1.1:
resolution: {integrity: sha512-R9e2Tn8f+ujVjwn6ne1YkXY35BXzUmxJbGsmD1c8RAZ/NXgbYktEFAwIkOZn5H5zRfY2VDSBvGI6TFpnOu50cg==}
dependencies:
'@types/debug': 4.1.8
debug: 4.3.4
strip-ansi: 6.0.1
transitivePeerDependencies:
- supports-color
dev: false
/@prisma/engines-version@5.1.1-1.6a3747c37ff169c90047725a05a6ef02e32ac97e:
resolution: {integrity: sha512-owZqbY/wucbr65bXJ/ljrHPgQU5xXTSkmcE/JcbqE1kusuAXV/TLN3/exmz21SZ5rJ7WDkyk70J2G/n68iogbQ==}
dev: false
/@prisma/engines@5.1.1:
resolution: {integrity: sha512-NV/4nVNWFZSJCCIA3HIFJbbDKO/NARc9ej0tX5S9k2EVbkrFJC4Xt9b0u4rNZWL4V+F5LAjvta8vzEUw0rw+HA==}
requiresBuild: true
dev: false
/@prisma/generator-helper@5.1.1:
resolution: {integrity: sha512-Qk9iiVk4JZQYZrYsc1Wx9fXFFnS1AH4T7WyLxCIFnX/end0K5tOK75Qxv6mjZAHE0XUGrzoTlZUkbSDVYz/CvQ==}
dependencies:
'@prisma/debug': 5.1.1
'@types/cross-spawn': 6.0.2
cross-spawn: 7.0.3
kleur: 4.1.5
transitivePeerDependencies:
- supports-color
dev: false
/@rollup/plugin-commonjs@24.1.0(rollup@3.28.0): /@rollup/plugin-commonjs@24.1.0(rollup@3.28.0):
resolution: {integrity: sha512-eSL45hjhCWI0jCCXcNtLVqM5N1JlBGvlFfY0m6oOYnLCJ6N0qEXoZql4sY2MOUArzhH4SA/qBpTxvvZp2Sc+DQ==} resolution: {integrity: sha512-eSL45hjhCWI0jCCXcNtLVqM5N1JlBGvlFfY0m6oOYnLCJ6N0qEXoZql4sY2MOUArzhH4SA/qBpTxvvZp2Sc+DQ==}
engines: {node: '>=14.0.0'} engines: {node: '>=14.0.0'}
@ -2057,12 +2048,6 @@ packages:
'@types/node': 18.17.5 '@types/node': 18.17.5
dev: false dev: false
/@types/cross-spawn@6.0.2:
resolution: {integrity: sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==}
dependencies:
'@types/node': 18.17.5
dev: false
/@types/debug@4.1.8: /@types/debug@4.1.8:
resolution: {integrity: sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==} resolution: {integrity: sha512-/vPO1EPOs306Cvhwv7KfVfYvOJqA/S/AXjaHQiJboCZzcNDb+TIJFN9/2C9DZ//ijSKWioNyUxD792QmDJ+HKQ==}
dependencies: dependencies:
@ -2537,6 +2522,10 @@ packages:
/buffer-from@1.1.2: /buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
/buffer-writer@2.0.0:
resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==}
engines: {node: '>=4'}
/builtin-modules@3.3.0: /builtin-modules@3.3.0:
resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -2574,6 +2563,11 @@ packages:
engines: {node: '>= 6'} engines: {node: '>= 6'}
dev: true dev: true
/camelcase@7.0.1:
resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==}
engines: {node: '>=14.16'}
dev: true
/caniuse-lite@1.0.30001520: /caniuse-lite@1.0.30001520:
resolution: {integrity: sha512-tahF5O9EiiTzwTUqAeFjIZbn4Dnqxzz7ktrgGlMYNLH43Ul26IgTMH/zvL3DG0lZxBYnlT04axvInszUsZULdA==} resolution: {integrity: sha512-tahF5O9EiiTzwTUqAeFjIZbn4Dnqxzz7ktrgGlMYNLH43Ul26IgTMH/zvL3DG0lZxBYnlT04axvInszUsZULdA==}
@ -2593,6 +2587,11 @@ packages:
supports-color: 7.2.0 supports-color: 7.2.0
dev: true dev: true
/chalk@5.3.0:
resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==}
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
dev: true
/chokidar@3.5.3: /chokidar@3.5.3:
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
engines: {node: '>= 8.10.0'} engines: {node: '>= 8.10.0'}
@ -2611,6 +2610,17 @@ packages:
resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==} resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==}
dev: false dev: false
/cli-color@2.0.3:
resolution: {integrity: sha512-OkoZnxyC4ERN3zLzZaY9Emb7f/MhBOIpePv0Ycok0fJYT+Ouo00UBEIwsVsr0yoow++n5YWlSUgST9GKhNHiRQ==}
engines: {node: '>=0.10'}
dependencies:
d: 1.0.1
es5-ext: 0.10.62
es6-iterator: 2.0.3
memoizee: 0.4.15
timers-ext: 0.1.7
dev: true
/cliui@8.0.1: /cliui@8.0.1:
resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -2619,10 +2629,6 @@ packages:
strip-ansi: 6.0.1 strip-ansi: 6.0.1
wrap-ansi: 7.0.0 wrap-ansi: 7.0.0
/code-block-writer@12.0.0:
resolution: {integrity: sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==}
dev: false
/color-convert@1.9.3: /color-convert@1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
dependencies: dependencies:
@ -2653,6 +2659,11 @@ packages:
engines: {node: '>= 6'} engines: {node: '>= 6'}
dev: true dev: true
/commander@9.5.0:
resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==}
engines: {node: ^12.20.0 || >=14}
dev: true
/commondir@1.0.1: /commondir@1.0.1:
resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==}
@ -2734,6 +2745,13 @@ packages:
/csstype@3.1.2: /csstype@3.1.2:
resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==}
/d@1.0.1:
resolution: {integrity: sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==}
dependencies:
es5-ext: 0.10.62
type: 1.2.0
dev: true
/debug@2.6.9: /debug@2.6.9:
resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==}
peerDependencies: peerDependencies:
@ -2803,6 +2821,12 @@ packages:
resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
dev: true dev: true
/difflib@0.2.4:
resolution: {integrity: sha512-9YVwmMb0wQHQNr5J9m6BSj6fk4pfGITGQOOs+D9Fl+INODWFOfvhIU1hNv6GgR1RBoC/9NJcwu77zShxV0kT7w==}
dependencies:
heap: 0.2.7
dev: true
/dir-glob@3.0.1: /dir-glob@3.0.1:
resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -2825,6 +2849,109 @@ packages:
resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==} resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==}
engines: {node: '>=12'} engines: {node: '>=12'}
/dreamopt@0.8.0:
resolution: {integrity: sha512-vyJTp8+mC+G+5dfgsY+r3ckxlz+QMX40VjPQsZc5gxVAxLmi64TBoVkP54A/pRAXMXsbu2GMMBrZPxNv23waMg==}
engines: {node: '>=0.4.0'}
dependencies:
wordwrap: 1.0.0
dev: true
/drizzle-kit@0.19.12:
resolution: {integrity: sha512-rcsmh5gUIkvuD0WrbEc+aLpqY2q2J8ltynRcJiJo2l01hhsYvPnX0sgxWlFXlfAIa5ZXNw2nJZhYlslI6tG3MA==}
hasBin: true
dependencies:
'@drizzle-team/studio': 0.0.5
'@esbuild-kit/esm-loader': 2.5.5
camelcase: 7.0.1
chalk: 5.3.0
commander: 9.5.0
esbuild: 0.18.20
esbuild-register: 3.4.2(esbuild@0.18.20)
glob: 8.1.0
hanji: 0.0.5
json-diff: 0.9.0
minimatch: 7.4.6
zod: 3.21.1
transitivePeerDependencies:
- supports-color
dev: true
/drizzle-orm@0.28.2(pg@8.11.2)(postgres@3.3.5):
resolution: {integrity: sha512-QRyuzvpJr7GE6LpvZ/sg2nAKNg2if1uGGkgFTiXn4auuYId//vVJe6HBsDTktfKfcaDGzIYos+/f+PS5EkBmrg==}
peerDependencies:
'@aws-sdk/client-rds-data': '>=3'
'@cloudflare/workers-types': '>=3'
'@libsql/client': '*'
'@neondatabase/serverless': '>=0.1'
'@opentelemetry/api': ^1.4.1
'@planetscale/database': '>=1'
'@types/better-sqlite3': '*'
'@types/pg': '*'
'@types/sql.js': '*'
'@vercel/postgres': '*'
better-sqlite3: '>=7'
bun-types: '*'
knex: '*'
kysely: '*'
mysql2: '>=2'
pg: '>=8'
postgres: '>=3'
sql.js: '>=1'
sqlite3: '>=5'
peerDependenciesMeta:
'@aws-sdk/client-rds-data':
optional: true
'@cloudflare/workers-types':
optional: true
'@libsql/client':
optional: true
'@neondatabase/serverless':
optional: true
'@opentelemetry/api':
optional: true
'@planetscale/database':
optional: true
'@types/better-sqlite3':
optional: true
'@types/pg':
optional: true
'@types/sql.js':
optional: true
'@vercel/postgres':
optional: true
better-sqlite3:
optional: true
bun-types:
optional: true
knex:
optional: true
kysely:
optional: true
mysql2:
optional: true
pg:
optional: true
postgres:
optional: true
sql.js:
optional: true
sqlite3:
optional: true
dependencies:
pg: 8.11.2
postgres: 3.3.5
dev: false
/drizzle-zod@0.5.0(drizzle-orm@0.28.2)(zod@3.21.1):
resolution: {integrity: sha512-gIOXclphhaleYFEGZFxSyJBoiPRyksGyIPgmgWz6a+j5JeaOrOf1QOPjf1p5AHYA+1O3Q01ondGOZfgObxBTsg==}
peerDependencies:
drizzle-orm: '>=0.23.13'
zod: '*'
dependencies:
drizzle-orm: 0.28.2(pg@8.11.2)(postgres@3.3.5)
zod: 3.21.1
dev: false
/ee-first@1.1.1: /ee-first@1.1.1:
resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==}
@ -2952,6 +3079,40 @@ packages:
is-symbol: 1.0.4 is-symbol: 1.0.4
dev: true dev: true
/es5-ext@0.10.62:
resolution: {integrity: sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==}
engines: {node: '>=0.10'}
requiresBuild: true
dependencies:
es6-iterator: 2.0.3
es6-symbol: 3.1.3
next-tick: 1.1.0
dev: true
/es6-iterator@2.0.3:
resolution: {integrity: sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==}
dependencies:
d: 1.0.1
es5-ext: 0.10.62
es6-symbol: 3.1.3
dev: true
/es6-symbol@3.1.3:
resolution: {integrity: sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==}
dependencies:
d: 1.0.1
ext: 1.7.0
dev: true
/es6-weak-map@2.0.3:
resolution: {integrity: sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==}
dependencies:
d: 1.0.1
es5-ext: 0.10.62
es6-iterator: 2.0.3
es6-symbol: 3.1.3
dev: true
/esbuild-plugin-solid@0.5.0(esbuild@0.17.19)(solid-js@1.7.11): /esbuild-plugin-solid@0.5.0(esbuild@0.17.19)(solid-js@1.7.11):
resolution: {integrity: sha512-ITK6n+0ayGFeDVUZWNMxX+vLsasEN1ILrg4pISsNOQ+mq4ljlJJiuXotInd+HE0MzwTcA9wExT1yzDE2hsqPsg==} resolution: {integrity: sha512-ITK6n+0ayGFeDVUZWNMxX+vLsasEN1ILrg4pISsNOQ+mq4ljlJJiuXotInd+HE0MzwTcA9wExT1yzDE2hsqPsg==}
peerDependencies: peerDependencies:
@ -2966,6 +3127,17 @@ packages:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
/esbuild-register@3.4.2(esbuild@0.18.20):
resolution: {integrity: sha512-kG/XyTDyz6+YDuyfB9ZoSIOOmgyFCH+xPRtsCa8W85HLRV5Csp+o3jWVbOSHgSLfyLc5DmP+KFDNwty4mEjC+Q==}
peerDependencies:
esbuild: '>=0.12 <1'
dependencies:
debug: 4.3.4
esbuild: 0.18.20
transitivePeerDependencies:
- supports-color
dev: true
/esbuild@0.17.19: /esbuild@0.17.19:
resolution: {integrity: sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==} resolution: {integrity: sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -3174,6 +3346,13 @@ packages:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
/event-emitter@0.3.5:
resolution: {integrity: sha512-D9rRn9y7kLPnJ+hMq7S/nhvoKwwvVJahBi2BPmx3bvbsEdK3W9ii8cBSGjP+72/LnM4n6fo3+dkCX5FeTQruXA==}
dependencies:
d: 1.0.1
es5-ext: 0.10.62
dev: true
/execa@5.1.1: /execa@5.1.1:
resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -3202,6 +3381,12 @@ packages:
signal-exit: 3.0.7 signal-exit: 3.0.7
strip-final-newline: 3.0.0 strip-final-newline: 3.0.0
/ext@1.7.0:
resolution: {integrity: sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==}
dependencies:
type: 2.7.2
dev: true
/fast-deep-equal@3.1.3: /fast-deep-equal@3.1.3:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
dev: true dev: true
@ -3365,6 +3550,12 @@ packages:
get-intrinsic: 1.2.1 get-intrinsic: 1.2.1
dev: true dev: true
/get-tsconfig@4.7.0:
resolution: {integrity: sha512-pmjiZ7xtB8URYm74PlGJozDNyhvsVLUcpBa8DZBG3bWHwaHa9bPiRpiSfovw+fjhwONSCWKRyk+JQHEGZmMrzw==}
dependencies:
resolve-pkg-maps: 1.0.0
dev: true
/glob-parent@5.1.2: /glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'} engines: {node: '>= 6'}
@ -3453,6 +3644,13 @@ packages:
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
dev: true dev: true
/hanji@0.0.5:
resolution: {integrity: sha512-Abxw1Lq+TnYiL4BueXqMau222fPSPMFtya8HdpWsz/xVAhifXou71mPh/kY2+08RgFcVccjG3uZHs6K5HAe3zw==}
dependencies:
lodash.throttle: 4.1.1
sisteransi: 1.0.5
dev: true
/has-bigints@1.0.2: /has-bigints@1.0.2:
resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==}
dev: true dev: true
@ -3495,6 +3693,10 @@ packages:
dependencies: dependencies:
function-bind: 1.1.1 function-bind: 1.1.1
/heap@0.2.7:
resolution: {integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==}
dev: true
/html-entities@2.3.3: /html-entities@2.3.3:
resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==} resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==}
@ -3672,6 +3874,10 @@ packages:
engines: {node: '>=8'} engines: {node: '>=8'}
dev: true dev: true
/is-promise@2.2.2:
resolution: {integrity: sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==}
dev: true
/is-reference@1.2.1: /is-reference@1.2.1:
resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==}
dependencies: dependencies:
@ -3780,6 +3986,15 @@ packages:
engines: {node: '>=4'} engines: {node: '>=4'}
hasBin: true hasBin: true
/json-diff@0.9.0:
resolution: {integrity: sha512-cVnggDrVkAAA3OvFfHpFEhOnmcsUpleEKq4d4O8sQWWSH40MBrWstKigVB1kGrgLWzuom+7rRdaCsnBD6VyObQ==}
hasBin: true
dependencies:
cli-color: 2.0.3
difflib: 0.2.4
dreamopt: 0.8.0
dev: true
/json-schema-traverse@0.4.1: /json-schema-traverse@0.4.1:
resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==}
dev: true dev: true
@ -3814,11 +4029,6 @@ packages:
resolution: {integrity: sha512-7n6wXq4gNgBELfDCpzKc+mRrZFs7D+wgfF5WRFLNAr4DA/qtr9Js8uOAVAfHhuLMfAcQ0pRKqbpjx+TcJVdE1Q==} resolution: {integrity: sha512-7n6wXq4gNgBELfDCpzKc+mRrZFs7D+wgfF5WRFLNAr4DA/qtr9Js8uOAVAfHhuLMfAcQ0pRKqbpjx+TcJVdE1Q==}
dev: true dev: true
/kleur@4.1.5:
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
engines: {node: '>=6'}
dev: false
/known-css-properties@0.24.0: /known-css-properties@0.24.0:
resolution: {integrity: sha512-RTSoaUAfLvpR357vWzAz/50Q/BmHfmE6ETSWfutT0AJiw10e6CmcdYRQJlLRd95B53D0Y2aD1jSxD3V3ySF+PA==} resolution: {integrity: sha512-RTSoaUAfLvpR357vWzAz/50Q/BmHfmE6ETSWfutT0AJiw10e6CmcdYRQJlLRd95B53D0Y2aD1jSxD3V3ySF+PA==}
dev: true dev: true
@ -3854,6 +4064,10 @@ packages:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
dev: true dev: true
/lodash.throttle@4.1.1:
resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==}
dev: true
/lodash@4.17.21: /lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
@ -3876,12 +4090,31 @@ packages:
yallist: 4.0.0 yallist: 4.0.0
dev: true dev: true
/lru-queue@0.1.0:
resolution: {integrity: sha512-BpdYkt9EvGl8OfWHDQPISVpcl5xZthb+XPsbELj5AQXxIC8IriDZIQYjBJPEm5rS420sjZ0TLEzRcq5KdBhYrQ==}
dependencies:
es5-ext: 0.10.62
dev: true
/magic-string@0.27.0: /magic-string@0.27.0:
resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==}
engines: {node: '>=12'} engines: {node: '>=12'}
dependencies: dependencies:
'@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/sourcemap-codec': 1.4.15
/memoizee@0.4.15:
resolution: {integrity: sha512-UBWmJpLZd5STPm7PMUlOw/TSy972M+z8gcyQ5veOnSDRREz/0bmpyTfKt3/51DhEBqCZQn1udM/5flcSPYhkdQ==}
dependencies:
d: 1.0.1
es5-ext: 0.10.62
es6-weak-map: 2.0.3
event-emitter: 0.3.5
is-promise: 2.2.2
lru-queue: 0.1.0
next-tick: 1.1.0
timers-ext: 0.1.7
dev: true
/merge-anything@5.1.7: /merge-anything@5.1.7:
resolution: {integrity: sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==} resolution: {integrity: sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==}
engines: {node: '>=12.13'} engines: {node: '>=12.13'}
@ -3935,6 +4168,13 @@ packages:
dependencies: dependencies:
brace-expansion: 2.0.1 brace-expansion: 2.0.1
/minimatch@7.4.6:
resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==}
engines: {node: '>=10'}
dependencies:
brace-expansion: 2.0.1
dev: true
/minimist@1.2.8: /minimist@1.2.8:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
@ -3973,6 +4213,10 @@ packages:
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
/next-tick@1.1.0:
resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==}
dev: true
/node-releases@2.0.13: /node-releases@2.0.13:
resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==}
@ -4113,6 +4357,9 @@ packages:
p-limit: 3.1.0 p-limit: 3.1.0
dev: true dev: true
/packet-reader@1.0.0:
resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==}
/parent-module@1.0.1: /parent-module@1.0.1:
resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -4153,6 +4400,62 @@ packages:
engines: {node: '>=8'} engines: {node: '>=8'}
dev: true dev: true
/pg-cloudflare@1.1.1:
resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==}
requiresBuild: true
optional: true
/pg-connection-string@2.6.2:
resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==}
/pg-int8@1.0.1:
resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==}
engines: {node: '>=4.0.0'}
/pg-pool@3.6.1(pg@8.11.2):
resolution: {integrity: sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==}
peerDependencies:
pg: '>=8.0'
dependencies:
pg: 8.11.2
/pg-protocol@1.6.0:
resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==}
/pg-types@2.2.0:
resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==}
engines: {node: '>=4'}
dependencies:
pg-int8: 1.0.1
postgres-array: 2.0.0
postgres-bytea: 1.0.0
postgres-date: 1.0.7
postgres-interval: 1.2.0
/pg@8.11.2:
resolution: {integrity: sha512-l4rmVeV8qTIrrPrIR3kZQqBgSN93331s9i6wiUiLOSk0Q7PmUxZD/m1rQI622l3NfqBby9Ar5PABfS/SulfieQ==}
engines: {node: '>= 8.0.0'}
peerDependencies:
pg-native: '>=3.0.1'
peerDependenciesMeta:
pg-native:
optional: true
dependencies:
buffer-writer: 2.0.0
packet-reader: 1.0.0
pg-connection-string: 2.6.2
pg-pool: 3.6.1(pg@8.11.2)
pg-protocol: 1.6.0
pg-types: 2.2.0
pgpass: 1.0.5
optionalDependencies:
pg-cloudflare: 1.1.1
/pgpass@1.0.5:
resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==}
dependencies:
split2: 4.2.0
/picocolors@1.0.0: /picocolors@1.0.0:
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
@ -4252,6 +4555,28 @@ packages:
picocolors: 1.0.0 picocolors: 1.0.0
source-map-js: 1.0.2 source-map-js: 1.0.2
/postgres-array@2.0.0:
resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==}
engines: {node: '>=4'}
/postgres-bytea@1.0.0:
resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==}
engines: {node: '>=0.10.0'}
/postgres-date@1.0.7:
resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==}
engines: {node: '>=0.10.0'}
/postgres-interval@1.2.0:
resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
engines: {node: '>=0.10.0'}
dependencies:
xtend: 4.0.2
/postgres@3.3.5:
resolution: {integrity: sha512-+JD93VELV9gHkqpV5gdL5/70HdGtEw4/XE1S4BC8f1mcPmdib3K5XsKVbnR1XcAyC41zOnifJ+9YRKxdIsXiUw==}
dev: false
/preact-render-to-string@5.2.3(preact@10.11.3): /preact-render-to-string@5.2.3(preact@10.11.3):
resolution: {integrity: sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==} resolution: {integrity: sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==}
peerDependencies: peerDependencies:
@ -4353,15 +4678,6 @@ packages:
resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==} resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==}
dev: false dev: false
/prisma@5.1.1:
resolution: {integrity: sha512-WJFG/U7sMmcc6TjJTTifTfpI6Wjoh55xl4AzopVwAdyK68L9/ogNo8QQ2cxuUjJf/Wa82z/uhyh3wMzvRIBphg==}
engines: {node: '>=16.13'}
hasBin: true
requiresBuild: true
dependencies:
'@prisma/engines': 5.1.1
dev: false
/prop-types@15.8.1: /prop-types@15.8.1:
resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==}
dependencies: dependencies:
@ -4457,6 +4773,10 @@ packages:
engines: {node: '>=4'} engines: {node: '>=4'}
dev: true dev: true
/resolve-pkg-maps@1.0.0:
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
dev: true
/resolve@1.22.4: /resolve@1.22.4:
resolution: {integrity: sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==} resolution: {integrity: sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==}
hasBin: true hasBin: true
@ -4612,6 +4932,10 @@ packages:
mrmime: 1.0.1 mrmime: 1.0.1
totalist: 3.0.1 totalist: 3.0.1
/sisteransi@1.0.5:
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
dev: true
/slash@3.0.0: /slash@3.0.0:
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -4806,6 +5130,10 @@ packages:
resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
/split2@4.2.0:
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
engines: {node: '>= 10.x'}
/statuses@1.5.0: /statuses@1.5.0:
resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==}
engines: {node: '>= 0.6'} engines: {node: '>= 0.6'}
@ -4961,6 +5289,13 @@ packages:
any-promise: 1.3.0 any-promise: 1.3.0
dev: true dev: true
/timers-ext@0.1.7:
resolution: {integrity: sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==}
dependencies:
es5-ext: 0.10.62
next-tick: 1.1.0
dev: true
/titleize@3.0.0: /titleize@3.0.0:
resolution: {integrity: sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==} resolution: {integrity: sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -5027,6 +5362,14 @@ packages:
engines: {node: '>=10'} engines: {node: '>=10'}
dev: true dev: true
/type@1.2.0:
resolution: {integrity: sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==}
dev: true
/type@2.7.2:
resolution: {integrity: sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==}
dev: true
/typed-array-buffer@1.0.0: /typed-array-buffer@1.0.0:
resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==} resolution: {integrity: sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@ -5289,6 +5632,10 @@ packages:
dependencies: dependencies:
isexe: 2.0.0 isexe: 2.0.0
/wordwrap@1.0.0:
resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==}
dev: true
/wrap-ansi@7.0.0: /wrap-ansi@7.0.0:
resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -5318,6 +5665,10 @@ packages:
engines: {node: '>=0.4.0'} engines: {node: '>=0.4.0'}
dev: false dev: false
/xtend@4.0.2:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'}
/y18n@5.0.8: /y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'} engines: {node: '>=10'}
@ -5355,21 +5706,8 @@ packages:
engines: {node: '>=10'} engines: {node: '>=10'}
dev: true dev: true
/zod-prisma-types@2.7.9:
resolution: {integrity: sha512-JgPN32d/Wm6/E61oHXek2jDT6VxBpKVPmLom7585SmdCyj+xb+OAg8O3G0BLU+gWNiC+Eyt3blo1S/8W9sIaxA==}
hasBin: true
dependencies:
'@prisma/generator-helper': 5.1.1
code-block-writer: 12.0.0
lodash: 4.17.21
zod: 3.21.1
transitivePeerDependencies:
- supports-color
dev: false
/zod@3.21.1: /zod@3.21.1:
resolution: {integrity: sha512-+dTu2m6gmCbO9Ahm4ZBDapx2O6ZY9QSPXst2WXjcznPMwf2YNpn3RevLx4KkZp1OPW/ouFcoBtBzFz/LeY69oA==} resolution: {integrity: sha512-+dTu2m6gmCbO9Ahm4ZBDapx2O6ZY9QSPXst2WXjcznPMwf2YNpn3RevLx4KkZp1OPW/ouFcoBtBzFz/LeY69oA==}
dev: false
/zustand@4.4.1(react@18.2.0): /zustand@4.4.1(react@18.2.0):
resolution: {integrity: sha512-QCPfstAS4EBiTQzlaGP1gmorkh/UL1Leaj2tdj+zZCZ/9bm0WS7sI2wnfD5lpOszFqWJ1DcPnGoY8RDL61uokw==} resolution: {integrity: sha512-QCPfstAS4EBiTQzlaGP1gmorkh/UL1Leaj2tdj+zZCZ/9bm0WS7sI2wnfD5lpOszFqWJ1DcPnGoY8RDL61uokw==}

File diff suppressed because it is too large Load diff

View file

@ -50,13 +50,13 @@ model User {
email String? @unique email String? @unique
emailVerified DateTime? @map("email_verified") emailVerified DateTime? @map("email_verified")
image String? image String?
createdAt DateTime @default(now()) @map(name: "created_at") createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map(name: "updated_at") updatedAt DateTime @updatedAt @map("updated_at")
games User_Game[] games User_Game[]
accounts Account[] accounts Account[]
sessions Session[] sessions Session[]
@@map(name: "users") @@map("users")
} }
model VerificationToken { model VerificationToken {

View file

@ -1,9 +1,6 @@
import classNames from "classnames" import classNames from "classnames"
function BurgerMenu(props: { function BurgerMenu(props: { onClick?: () => void; blur?: boolean }) {
onClick?: () => void
blur?: boolean
}) {
return ( return (
<button <button
id="menu" id="menu"

View file

@ -0,0 +1,10 @@
import { drizzle } from "drizzle-orm/postgres-js"
import postgres from "postgres"
import * as schema from "./schemas/Tables"
const queryClient = postgres(process.env.DATABASE_URL ?? "")
const db = drizzle(queryClient, {
schema,
})
export default db

View file

@ -0,0 +1,214 @@
import type { AdapterAccount } from "@auth/core/adapters"
import { createId } from "@paralleldrive/cuid2"
import { relations } from "drizzle-orm"
import {
AnyPgColumn,
boolean,
integer,
pgTable,
primaryKey,
text,
timestamp,
unique,
} from "drizzle-orm/pg-core"
import { gameState, moveType, orientation } from "./Types"
export const users = pgTable("user", {
id: text("id").notNull().primaryKey(),
name: text("name"),
email: text("email").notNull().unique(),
emailVerified: timestamp("emailVerified", { mode: "date" }),
image: text("image"),
createdAt: timestamp("created_at").defaultNow(),
updatedAt: timestamp("updated_at").notNull().defaultNow(),
})
export const accounts = pgTable(
"account",
{
userId: text("userId")
.notNull()
.references(() => users.id, { onDelete: "cascade" }),
type: text("type").$type<AdapterAccount["type"]>().notNull(),
provider: text("provider").notNull(),
providerAccountId: text("providerAccountId").notNull(),
refresh_token: text("refresh_token"),
access_token: text("access_token"),
expires_at: integer("expires_at"),
extExpiresIn: integer("ext_expires_in"),
token_type: text("token_type"),
scope: text("scope"),
id_token: text("id_token"),
session_state: text("session_state"),
oauthTokenSecret: text("oauth_token_secret"),
oauthToken: text("oauth_token"),
},
(account) => ({
compoundKey: primaryKey(account.provider, account.providerAccountId),
}),
)
export const sessions = pgTable("session", {
sessionToken: text("sessionToken").notNull().primaryKey(),
userId: text("userId")
.notNull()
.references(() => users.id, { onDelete: "cascade" }),
expires: timestamp("expires", { mode: "date" }).notNull(),
})
export const verificationTokens = pgTable(
"verificationToken",
{
identifier: text("identifier").notNull(),
token: text("token").notNull(),
expires: timestamp("expires", { mode: "date" }).notNull(),
},
(vt) => ({
compoundKey: primaryKey(vt.identifier, vt.token),
}),
)
export const games = pgTable("game", {
id: text("id").notNull().primaryKey().default(createId()),
createdAt: timestamp("created_at").defaultNow(),
updatedAt: timestamp("updated_at").notNull().defaultNow(),
state: gameState("state").notNull().default("lobby"),
allowSpectators: boolean("allow_spectators").notNull().default(true),
allowSpecials: boolean("allow_specials").notNull().default(true),
allowChat: boolean("allow_chat").notNull().default(true),
allowMarkDraw: boolean("allow_mark_draw").notNull().default(true),
})
export const gamepins = pgTable("gamepin", {
id: text("id").notNull().primaryKey().default(createId()),
createdAt: timestamp("created_at").defaultNow(),
pin: text("pin").notNull().unique(),
gameId: text("game_id")
.notNull()
.unique()
.references((): AnyPgColumn => games.id),
})
export const ships = pgTable("ship", {
id: text("id").notNull().primaryKey().default(createId()),
size: integer("size").notNull(),
variant: integer("variant").notNull(),
x: integer("x").notNull(),
y: integer("y").notNull(),
orientation: orientation("orientation").notNull(),
user_game_id: text("user_game_id")
.notNull()
.references(() => user_games.id, { onDelete: "cascade" }),
})
export const hits = pgTable("hit", {
id: text("id").notNull().primaryKey().default(createId()),
x: integer("x").notNull(),
y: integer("y").notNull(),
hit: boolean("hit").notNull(),
user_game_id: text("user_game_id")
.notNull()
.references(() => user_games.id, { onDelete: "cascade" }),
})
export const moves = pgTable("move", {
id: text("id").notNull().primaryKey().default(createId()),
createdAt: timestamp("created_at").defaultNow(),
index: integer("index").notNull(),
type: moveType("type").notNull(),
x: integer("x").notNull(),
y: integer("y").notNull(),
orientation: orientation("orientation").notNull(),
user_game_id: text("user_game_id")
.notNull()
.references(() => user_games.id, { onDelete: "cascade" }),
})
export const chats = pgTable("chat", {
id: text("id").notNull().primaryKey().default(createId()),
createdAt: timestamp("created_at").notNull().defaultNow(),
message: text("message"),
event: text("event"),
user_game_id: text("user_game_id")
.notNull()
.references(() => user_games.id, { onDelete: "cascade" }),
})
export const user_games = pgTable(
"user_game",
{
id: text("id").notNull().primaryKey().default(createId()),
createdAt: timestamp("created_at").defaultNow(),
gameId: text("game_id")
.notNull()
.references(() => games.id, { onDelete: "cascade" }),
userId: text("user_id")
.notNull()
.references(() => users.id, { onDelete: "cascade" }),
index: integer("index").notNull(),
},
(t) => ({
gameIndex: unique().on(t.gameId, t.index),
}),
)
export const usersRelations = relations(users, ({ many }) => ({
user_games: many(user_games),
sessions: many(sessions),
}))
export const sessionsRelations = relations(sessions, ({ one }) => ({
user: one(users, {
fields: [sessions.userId],
references: [users.id],
}),
}))
export const gamesRelations = relations(games, ({ one, many }) => ({
gamePin: one(gamepins, {
fields: [games.id],
references: [gamepins.gameId],
}),
users: many(user_games),
}))
export const gamepinsRelations = relations(gamepins, ({ one }) => ({
game: one(games, { fields: [gamepins.gameId], references: [games.id] }),
}))
export const shipsRelations = relations(ships, ({ one }) => ({
userGame: one(user_games, {
fields: [ships.user_game_id],
references: [user_games.id],
}),
}))
export const hitsRelations = relations(hits, ({ one }) => ({
userGame: one(user_games, {
fields: [hits.user_game_id],
references: [user_games.id],
}),
}))
export const userGamesRelations = relations(user_games, ({ one, many }) => ({
user: one(users, { fields: [user_games.userId], references: [users.id] }),
game: one(games, { fields: [user_games.gameId], references: [games.id] }),
moves: many(moves),
ships: many(ships),
hits: many(hits),
chats: many(chats),
}))
export const movesRelations = relations(moves, ({ one }) => ({
userGame: one(user_games, {
fields: [moves.user_game_id],
references: [user_games.id],
}),
}))
export const chatsRelations = relations(chats, ({ one }) => ({
userGame: one(user_games, {
fields: [chats.user_game_id],
references: [user_games.id],
}),
}))

View file

@ -0,0 +1,16 @@
import { pgEnum } from "drizzle-orm/pg-core"
export const gameState = pgEnum("game_state", [
"lobby",
"starting",
"running",
"ended",
"aborted",
])
export const moveType = pgEnum("move_type", [
"missile",
"vtorpedo",
"htorpedo",
"radar",
])
export const orientation = pgEnum("orientation", ["h", "v"])

View file

@ -1,4 +1,3 @@
import { produce } from "immer"
import create from "solid-zustand" import create from "solid-zustand"
const initialState: { const initialState: {
@ -20,12 +19,7 @@ export type Action = {
export const useDrawProps = create<State & Action>()((set) => ({ export const useDrawProps = create<State & Action>()((set) => ({
...initialState, ...initialState,
setColor: (color) => setColor: (color) => set((state) => ({ ...state, color })),
set(
produce((state) => {
state.color = color
}),
),
reset: () => { reset: () => {
set(initialState) set(initialState)
}, },

View file

@ -1,4 +1,3 @@
import { GameState, MoveType } from "@prisma/client"
import { getPayloadwithChecksum } from "~/lib/getPayloadwithChecksum" import { getPayloadwithChecksum } from "~/lib/getPayloadwithChecksum"
import { socket } from "~/lib/socket" import { socket } from "~/lib/socket"
import { import {
@ -10,6 +9,8 @@ import {
} from "~/lib/utils/helpers" } from "~/lib/utils/helpers"
import { import {
GamePropsSchema, GamePropsSchema,
GameState,
MoveType,
PlayerSchema, PlayerSchema,
optionalGamePropsSchema, optionalGamePropsSchema,
} from "~/lib/zodSchemas" } from "~/lib/zodSchemas"
@ -100,7 +101,7 @@ export const useGameProps = create<State & Action>()((set) => ({
state.payload.users.map((e) => { state.payload.users.map((e) => {
if (!e) return e if (!e) return e
if (i === e.index) e.moves.push(move) if (i === e.index) e.moves.push(move)
else if (move.type !== MoveType.radar) else if (move.type !== MoveType.Enum.radar)
e.hits.push( e.hits.push(
...list.map(({ x, y }) => ({ ...list.map(({ x, y }) => ({
hit: !!intersectingShip(e.ships, { hit: !!intersectingShip(e.ships, {

View file

@ -155,7 +155,7 @@ function useSocket() {
.then(isAuthenticated) .then(isAuthenticated)
.then((game) => GamePropsSchema.parse(game)) .then((game) => GamePropsSchema.parse(game))
.then((res) => full(res)) .then((res) => full(res))
.catch((e) => console.log(e)) .catch((e) => console.log("Failed to get /api/game/running: ", e))
return return
} }
if (isConnected()) return if (isConnected()) return

View file

@ -1,5 +1,4 @@
import { Session } from "@auth/core/types" import { Session } from "@auth/core/types"
import { GameState } from "@prisma/client"
import type { Server as HTTPServer } from "http" import type { Server as HTTPServer } from "http"
import type { Socket as NetSocket } from "net" import type { Socket as NetSocket } from "net"
import type { import type {
@ -9,6 +8,7 @@ import type {
} from "socket.io" } from "socket.io"
import type { Socket as SocketforClient } from "socket.io-client" import type { Socket as SocketforClient } from "socket.io-client"
import { GamePropsSchema } from "~/lib/zodSchemas" import { GamePropsSchema } from "~/lib/zodSchemas"
import { GameState } from "../lib/zodSchemas"
import { import {
DrawLineProps, DrawLineProps,
GameSettings, GameSettings,
@ -25,7 +25,7 @@ interface SocketWithIO extends NetSocket {
server: SocketServer server: SocketServer
} }
export interface RequestWithSocket extends Request { export interface ResponseWithSocket extends Response {
socket: SocketWithIO socket: SocketWithIO
} }
@ -74,7 +74,7 @@ interface SocketData {
index: number index: number
} }
user: Session["user"] user: Session["user"]
gameId: string | null gameId: string
index: number index: number
} }

View file

@ -1,6 +1,5 @@
import { IconDefinition } from "@fortawesome/pro-solid-svg-icons" import { IconDefinition } from "@fortawesome/pro-solid-svg-icons"
import { MoveType, Orientation } from "@prisma/client" import { MoveType, Orientation, PlayerSchema } from "~/lib/zodSchemas"
import { PlayerSchema } from "~/lib/zodSchemas"
export interface Position { export interface Position {
x: number x: number

View file

@ -56,15 +56,19 @@ async function logging(
`[${new Date().toString().slice(0, 33)}] ` + messages.console `[${new Date().toString().slice(0, 33)}] ` + messages.console
messages.file = `[${new Date().toString().slice(0, 33)}] ` + messages.file messages.file = `[${new Date().toString().slice(0, 33)}] ` + messages.file
if (request) { if (request) {
const forwardedFor = request.headers const xForwardedFor =
console.log(JSON.stringify(forwardedFor)) typeof request.headers.get === "function"
? request.headers.get("x-forwarded-for")
: "0.0.0.0" // request.headers
if (typeof request.headers.get !== "function")
console.log("IncomingHttpHeaders", request.headers)
// ("x-forwarded-for") // ("x-forwarded-for")
// const ip = (forwardedFor || "127.0.0.1, 192.168.178.1").split(",") const ip = (xForwardedFor || "127.0.0.1, 192.168.178.1").split(",")
// const route = request.url const route = request.url
// messages.console = [ip[0].yellow, route?.green, messages.console].join( messages.console = [ip[0].yellow, route?.green, messages.console].join(
// " - ", " - ",
// ) )
// messages.file = [ip[0], route, messages.file].join(" - ") messages.file = [ip[0], route, messages.file].join(" - ")
} }
await fs.promises.appendFile("log/log.txt", messages.file + "\n") await fs.promises.appendFile("log/log.txt", messages.file + "\n")
console.log(messages.console) console.log(messages.console)

View file

@ -13,7 +13,7 @@ export default function sendError(
: ["solved" in err && err.solved ? "debug" : "error"], : ["solved" in err && err.solved ? "debug" : "error"],
request, request,
) )
if ("name" in err) console.log(err) if ("name" in err) console.log("Sending Respons: " + err)
// If something went wrong, let the client know with status 500 // If something went wrong, let the client know with status 500
return json(null, { status: "statusCode" in err ? err.statusCode : 500 }) return json(null, { status: "statusCode" in err ? err.statusCode : 500 })
} }

View file

@ -1,15 +0,0 @@
// lib/prisma.ts
import { PrismaClient } from "@prisma/client"
let prisma: PrismaClient
if (process.env.NODE_ENV === "production") {
prisma = new PrismaClient()
} else {
if (!global.prismaClient) {
global.prismaClient = new PrismaClient()
}
prisma = global.prismaClient
}
export default prisma

View file

@ -1,4 +1,3 @@
import { Orientation } from "@prisma/client"
import { count } from "~/components/Gamefield/Gamefield" import { count } from "~/components/Gamefield/Gamefield"
import type { import type {
Hit, Hit,
@ -9,7 +8,9 @@ import type {
ShipProps, ShipProps,
Target, Target,
TargetList, TargetList,
TargetPreview,
} from "../../interfaces/frontend" } from "../../interfaces/frontend"
import { Orientation } from "../zodSchemas"
export function borderCN(count: number, x: number, y: number) { export function borderCN(count: number, x: number, y: number) {
if (x === 0) return "left" if (x === 0) return "left"
@ -115,13 +116,13 @@ export const initlialTarget = {
x: 2, x: 2,
y: 2, y: 2,
show: false, show: false,
orientation: Orientation.h, orientation: Orientation.Enum.h,
} }
export const initlialTargetPreview = { export const initlialTargetPreview = {
x: 2, x: 2,
y: 2, y: 2,
show: false, show: false,
orientation: Orientation.h, orientation: Orientation.Enum.h,
} }
export const initlialMouseCursor = { export const initlialMouseCursor = {
shouldShow: false, shouldShow: false,
@ -132,7 +133,7 @@ export const initlialMouseCursor = {
export const shipProps = ( export const shipProps = (
ships: ShipProps[], ships: ShipProps[],
mode: number, mode: number,
targetPreview: Position & { orientation: Orientation }, targetPreview: Omit<TargetPreview, "show">,
) => ({ ) => ({
size: mode + 2, size: mode + 2,
variant: variant:

View file

@ -1,5 +1,38 @@
import { GameState, MoveType, Orientation } from "@prisma/client" import { createSelectSchema } from "drizzle-zod"
import { z } from "zod" import { z } from "zod"
import {
accounts,
chats,
gamepins,
games,
hits,
moves,
sessions,
ships,
user_games,
users,
verificationTokens,
} from "~/drizzle/schemas/Tables"
import { gameState, moveType, orientation } from "~/drizzle/schemas/Types"
export const GameState = z.enum(gameState.enumValues)
export const MoveType = z.enum(moveType.enumValues)
export const Orientation = z.enum(orientation.enumValues)
export type GameState = z.infer<typeof GameState>
export type MoveType = z.infer<typeof MoveType>
export type Orientation = z.infer<typeof Orientation>
export const usersSchema = createSelectSchema(users)
export const accountsSchema = createSelectSchema(accounts)
export const sessionsSchema = createSelectSchema(sessions)
export const verificationTokensSchema = createSelectSchema(verificationTokens)
export const gamesSchema = createSelectSchema(games)
export const gamepinsSchema = createSelectSchema(gamepins)
export const shipsSchema = createSelectSchema(ships)
export const hitsSchema = createSelectSchema(hits)
export const movesSchema = createSelectSchema(moves)
export const chatsSchema = createSelectSchema(chats)
export const user_gamesSchema = createSelectSchema(user_games)
export const PlayerSchema = z export const PlayerSchema = z
.object({ .object({
@ -17,10 +50,10 @@ export const PlayerSchema = z
moves: z moves: z
.object({ .object({
index: z.number(), index: z.number(),
type: z.nativeEnum(MoveType), type: MoveType,
x: z.number(), x: z.number(),
y: z.number(), y: z.number(),
orientation: z.nativeEnum(Orientation), orientation: Orientation,
}) })
.array(), .array(),
ships: z ships: z
@ -29,7 +62,7 @@ export const PlayerSchema = z
variant: z.number(), variant: z.number(),
x: z.number(), x: z.number(),
y: z.number(), y: z.number(),
orientation: z.nativeEnum(Orientation), orientation: Orientation,
}) })
.array(), .array(),
hits: z hits: z
@ -48,7 +81,7 @@ export const CreateSchema = z.object({
game: z game: z
.object({ .object({
id: z.string(), id: z.string(),
state: z.nativeEnum(GameState), state: GameState,
allowSpectators: z.boolean(), allowSpectators: z.boolean(),
allowSpecials: z.boolean(), allowSpecials: z.boolean(),
allowChat: z.boolean(), allowChat: z.boolean(),

View file

@ -1,11 +1,16 @@
import { getSession } from "@auth/solid-start" import { getSession } from "@auth/solid-start"
import { Game } from "@prisma/client" import { eq } from "drizzle-orm"
import { APIEvent } from "solid-start" import { APIEvent } from "solid-start"
import { z } from "zod"
import db from "~/drizzle"
import { games } from "~/drizzle/schemas/Tables"
import { rejectionErrors } from "~/lib/backend/errors" import { rejectionErrors } from "~/lib/backend/errors"
import sendResponse from "~/lib/backend/sendResponse" import sendResponse from "~/lib/backend/sendResponse"
import prisma from "~/lib/prisma" import { gamesSchema } from "~/lib/zodSchemas"
import { authOptions } from "~/server/auth" import { authOptions } from "~/server/auth"
type Game = z.infer<typeof gamesSchema>
interface Data { interface Data {
game: Game game: Game
} }
@ -20,19 +25,14 @@ export async function GET({ request }: APIEvent) {
return sendResponse(request, rejectionErrors.unauthorized) return sendResponse(request, rejectionErrors.unauthorized)
} }
let game: Game | null let game: Game | undefined
switch (request.method) {
case "DELETE":
game = await prisma.game.delete({
where: { id: gameId },
})
break
default: if (request.method === "DELETE")
game = await prisma.game.findFirst({ game = (await db.delete(games).where(eq(games.id, gameId)).returning())[0]
where: { id: gameId }, else
}) game = await db.query.games.findFirst({
} where: (game) => eq(game.id, gameId),
})
if (!game) { if (!game) {
return sendResponse(request, rejectionErrors.gameNotFound) return sendResponse(request, rejectionErrors.gameNotFound)

View file

@ -1,10 +1,12 @@
import { getSession } from "@auth/solid-start" import { getSession } from "@auth/solid-start"
import { eq } from "drizzle-orm"
import { APIEvent } from "solid-start" import { APIEvent } from "solid-start"
import db from "~/drizzle"
import { chats, gamepins, games, user_games } from "~/drizzle/schemas/Tables"
import { rejectionErrors } from "~/lib/backend/errors" import { rejectionErrors } from "~/lib/backend/errors"
import sendResponse from "~/lib/backend/sendResponse" import sendResponse from "~/lib/backend/sendResponse"
import prisma from "~/lib/prisma"
import { authOptions } from "~/server/auth" import { authOptions } from "~/server/auth"
import { composeBody, gameSelects, getAnyRunningGame } from "./running" import { composeBody, gameSelects, getRunningGameToUser } from "./running"
export async function POST({ request }: APIEvent) { export async function POST({ request }: APIEvent) {
const session = await getSession(request, authOptions) const session = await getSession(request, authOptions)
@ -21,36 +23,32 @@ export async function POST({ request }: APIEvent) {
const created = false const created = false
let game = await getAnyRunningGame(id) let game = await getRunningGameToUser(id)
if (game) { if (game) {
return sendResponse(request, { return sendResponse(request, {
redirectUrl: "/api/game/running", redirectUrl: "/api/game/running",
message: "Running game already exists.", message: "Running game already exists.",
}) })
} else { } else {
game = await prisma.game.create({ const gameId = (await db.insert(games).values({}).returning())[0].id
data: { const user_Game = (
gamePin: { await db
create: { .insert(user_games)
pin, .values({ gameId, userId: id, index: 0 })
}, .returning()
}, )[0]
users: { await db.insert(gamepins).values({ gameId, pin })
create: { await db
userId: id, .insert(chats)
index: 0, .values({ user_game_id: user_Game.id, event: "created" })
chats: { game = await db.query.games.findFirst({
create: { where: eq(games.id, gameId),
event: "created",
},
},
},
},
},
...gameSelects, ...gameSelects,
}) })
} }
if (!game) return
const body = composeBody(game) const body = composeBody(game)
return sendResponse(request, { return sendResponse(request, {

View file

@ -1,13 +1,15 @@
import { getSession } from "@auth/solid-start" import { getSession } from "@auth/solid-start"
import { and, eq, exists, inArray, ne } from "drizzle-orm"
import { APIEvent } from "solid-start" import { APIEvent } from "solid-start"
import db from "~/drizzle"
import { user_games, users } from "~/drizzle/schemas/Tables"
import { rejectionErrors } from "~/lib/backend/errors" import { rejectionErrors } from "~/lib/backend/errors"
import getPinFromBody from "~/lib/backend/getPinFromBody" import getPinFromBody from "~/lib/backend/getPinFromBody"
import logging from "~/lib/backend/logging" import logging from "~/lib/backend/logging"
import sendError from "~/lib/backend/sendError" import sendError from "~/lib/backend/sendError"
import sendResponse from "~/lib/backend/sendResponse" import sendResponse from "~/lib/backend/sendResponse"
import prisma from "~/lib/prisma"
import { authOptions } from "~/server/auth" import { authOptions } from "~/server/auth"
import { composeBody, gameSelects } from "./running" import { composeBody, gameSelects, getGameById } from "./running"
export async function POST({ request }: APIEvent) { export async function POST({ request }: APIEvent) {
const session = await getSession(request, authOptions) const session = await getSession(request, authOptions)
@ -20,14 +22,11 @@ export async function POST({ request }: APIEvent) {
const { email, id } = session.user const { email, id } = session.user
try { try {
const game = await prisma.game.findFirst({ const gamePin = await db.query.gamepins.findFirst({
where: { where: (gamePin) => eq(gamePin.pin, pin ?? ""),
gamePin: { with: { game: true },
pin,
},
},
}) })
if (!game) { if (!gamePin?.game) {
return sendResponse(request, { return sendResponse(request, {
message: "Spiel existiert nicht", message: "Spiel existiert nicht",
statusCode: 404, statusCode: 404,
@ -35,20 +34,28 @@ export async function POST({ request }: APIEvent) {
}) })
} }
const games = await prisma.game.findMany({ let game = await db.query.games.findFirst({
where: { where: (game) =>
NOT: { and(
state: "ended", ne(game.state, "ended"),
}, exists(
users: { db
some: { .select()
userId: id, .from(user_games)
}, .where(
}, inArray(
}, user_games.userId,
db
.select({ data: users.id })
.from(users)
.where(eq(users.id, id)),
),
),
),
),
...gameSelects, ...gameSelects,
}) })
if (games.length) { if (!game) {
return sendResponse(request, { return sendResponse(request, {
message: "Spieler ist bereits in Spiel!", message: "Spieler ist bereits in Spiel!",
redirectUrl: "/api/game/running", redirectUrl: "/api/game/running",
@ -56,18 +63,22 @@ export async function POST({ request }: APIEvent) {
}) })
} }
const user_Game = await prisma.user_Game.create({ const gameId = (
data: { await db
gameId: game.id, .insert(user_games)
userId: id, .values({
index: 1, gameId: game.id,
}, userId: id,
select: { index: 1,
game: gameSelects, })
}, .returning()
}) )[0].gameId
const body = composeBody(user_Game.game) game = await getGameById(gameId)
if (!game) return
const body = composeBody(game)
return sendResponse(request, { return sendResponse(request, {
message: `User <${email}> joined game: ${game.id}`, message: `User <${email}> joined game: ${game.id}`,

View file

@ -1,31 +1,37 @@
import { getSession } from "@auth/solid-start" import { getSession } from "@auth/solid-start"
import { type APIEvent } from "solid-start/api" import { and, eq, exists, ne } from "drizzle-orm"
import { APIEvent } from "solid-start/api"
import db from "~/drizzle"
import { games, user_games, users } from "~/drizzle/schemas/Tables"
import { rejectionErrors } from "~/lib/backend/errors" import { rejectionErrors } from "~/lib/backend/errors"
import sendResponse from "~/lib/backend/sendResponse" import sendResponse from "~/lib/backend/sendResponse"
import { getPayloadwithChecksum } from "~/lib/getPayloadwithChecksum" import { getPayloadwithChecksum } from "~/lib/getPayloadwithChecksum"
import prisma from "~/lib/prisma"
import { GamePropsSchema } from "~/lib/zodSchemas" import { GamePropsSchema } from "~/lib/zodSchemas"
import { authOptions } from "~/server/auth" import { authOptions } from "~/server/auth"
export const gameSelects = { export const gameSelects = {
select: { columns: {
id: true, id: true,
allowChat: true, allowChat: true,
allowMarkDraw: true, allowMarkDraw: true,
allowSpecials: true, allowSpecials: true,
allowSpectators: true, allowSpectators: true,
state: true, state: true,
},
with: {
gamePin: { gamePin: {
select: { columns: {
pin: true, pin: true,
}, },
}, },
users: { users: {
select: { columns: {
id: true, id: true,
index: true, index: true,
},
with: {
chats: { chats: {
select: { columns: {
id: true, id: true,
event: true, event: true,
message: true, message: true,
@ -33,7 +39,7 @@ export const gameSelects = {
}, },
}, },
moves: { moves: {
select: { columns: {
index: true, index: true,
type: true, type: true,
x: true, x: true,
@ -42,7 +48,7 @@ export const gameSelects = {
}, },
}, },
ships: { ships: {
select: { columns: {
size: true, size: true,
variant: true, variant: true,
x: true, x: true,
@ -51,14 +57,14 @@ export const gameSelects = {
}, },
}, },
hits: { hits: {
select: { columns: {
x: true, x: true,
y: true, y: true,
hit: true, hit: true,
}, },
}, },
user: { user: {
select: { columns: {
id: true, id: true,
name: true, name: true,
}, },
@ -66,40 +72,33 @@ export const gameSelects = {
}, },
}, },
}, },
} } as const
export const getAnyGame = (gameId: string) => { export const getGameById = async (gameId: string) => {
const game = prisma.game.findFirst({ return db.query.games.findFirst({
where: { where: and(ne(games.state, "ended"), eq(games.id, gameId)),
NOT: {
state: "ended",
},
id: gameId,
},
...gameSelects, ...gameSelects,
}) })
return game
} }
export const getAnyRunningGame = (userId: string) => { export const getRunningGameToUser = async (userId: string) => {
const game = prisma.game.findFirst({ return db.query.games.findFirst({
where: { where: (game) =>
NOT: { and(
state: "ended", ne(game.state, "ended"),
}, exists(
users: { db
some: { .select()
userId, .from(user_games)
}, .where(exists(db.select().from(users).where(eq(users.id, userId)))),
}, ),
}, ),
...gameSelects, ...gameSelects,
}) })
return game
} }
export function composeBody( export function composeBody(
gameDB: NonNullable<Awaited<ReturnType<typeof getAnyRunningGame>>>, gameDB: NonNullable<Awaited<ReturnType<typeof getRunningGameToUser>>>,
): GamePropsSchema { ): GamePropsSchema {
const { gamePin, ...game } = gameDB const { gamePin, ...game } = gameDB
const users = gameDB.users const users = gameDB.users
@ -132,7 +131,7 @@ export async function GET({ request }: APIEvent) {
const { email, id } = session.user const { email, id } = session.user
const game = await getAnyRunningGame(id) const game = await getRunningGameToUser(id)
if (!game) if (!game)
return sendResponse(request, { return sendResponse(request, {

View file

@ -1,34 +1,39 @@
import { getSession } from "@auth/solid-start" import { getSession } from "@auth/solid-start"
import colors from "colors" import colors from "colors"
import { and, eq } from "drizzle-orm"
import status from "http-status" import status from "http-status"
import { Server } from "socket.io" import { Server } from "socket.io"
import { RequestWithSocket, sServer } from "~/interfaces/NextApiSocket" import { APIEvent } from "solid-start"
import db from "~/drizzle"
import { games, moves, ships, user_games } from "~/drizzle/schemas/Tables"
import { ResponseWithSocket, sServer } from "~/interfaces/NextApiSocket"
import logging from "~/lib/backend/logging" import logging from "~/lib/backend/logging"
import prisma from "~/lib/prisma"
import { GamePropsSchema } from "~/lib/zodSchemas" import { GamePropsSchema } from "~/lib/zodSchemas"
import { authOptions } from "~/server/auth" import { authOptions } from "~/server/auth"
import { import {
composeBody, composeBody,
gameSelects, gameSelects,
getAnyGame, getGameById,
getAnyRunningGame, getRunningGameToUser,
} from "./game/running" } from "./game/running"
colors.enable() colors.enable()
export async function GET({ request }: { request: RequestWithSocket }) { const res = new Response() as ResponseWithSocket
if (request.socket.server.io) {
export async function GET({ request }: APIEvent) {
if (res.socket.server.io) {
logging("Socket is already running " + request.url, ["infoCyan"], request) logging("Socket is already running " + request.url, ["infoCyan"], request)
} else { } else {
logging("Socket is initializing " + request.url, ["infoCyan"], request) logging("Socket is initializing " + request.url, ["infoCyan"], request)
const io: sServer = new Server(request.socket.server, { const io: sServer = new Server(res.socket.server, {
path: "/api/ws", path: "/api/ws",
cors: { cors: {
origin: "https://leaky-ships.mal-noh.de", origin: "https://leaky-ships.mal-noh.de",
}, },
}) })
request.socket.server.io = io res.socket.server.io = io
// io.use(authenticate) // io.use(authenticate)
io.use(async (socket, next) => { io.use(async (socket, next) => {
@ -38,7 +43,7 @@ export async function GET({ request }: { request: RequestWithSocket }) {
if (!session) return next(new Error(status["401"])) if (!session) return next(new Error(status["401"]))
socket.data.user = session.user socket.data.user = session.user
const game = await getAnyRunningGame(socket.data.user?.id ?? "") const game = await getRunningGameToUser(socket.data.user?.id ?? "")
if (!game) { if (!game) {
logging( logging(
"Forbidden, no game found: " + "Forbidden, no game found: " +
@ -82,63 +87,74 @@ export async function GET({ request }: { request: RequestWithSocket }) {
) )
socket.on("update", async (cb) => { socket.on("update", async (cb) => {
const game = await getAnyGame(socket.data.gameId ?? "") const game = await getGameById(socket.data.gameId ?? "")
if (!game) return if (!game) return
const body = composeBody(game) const body = composeBody(game)
cb(body) cb(body)
}) })
socket.on("gameSetting", async (payload, cb) => { socket.on("gameSetting", async (payload, cb) => {
const game = await prisma.game.update({ const game = await db
where: { id: socket.data.gameId ?? "" }, .update(games)
data: payload, .set(payload)
...gameSelects, .where(eq(games.id, socket.data.gameId))
}) .returning()
.then((updatedGame) =>
db.query.games.findFirst({
where: eq(games.id, updatedGame[0].id),
...gameSelects,
}),
)
if (!game) return
const { hash } = composeBody(game) const { hash } = composeBody(game)
if (!hash) return if (!hash) return
cb(hash) cb(hash)
socket.to(game.id).emit("gameSetting", payload, hash) socket.to(game?.id).emit("gameSetting", payload, hash)
}) })
socket.on("ping", (callback) => callback()) socket.on("ping", (callback) => callback())
socket.on("leave", async (cb) => { socket.on("leave", async (cb) => {
if (!socket.data.gameId || !socket.data.user?.id) return cb(false) if (!socket.data.gameId || !socket.data.user?.id) return cb(false)
const user_Game = await prisma.user_Game.delete({ const user_Game = await db
where: { .delete(user_games)
gameId_userId: { .where(
gameId: socket.data.gameId, and(
userId: socket.data.user?.id, eq(user_games.gameId, socket.data.gameId),
}, eq(user_games.userId, socket.data.user?.id ?? ""),
}, ),
}) )
const enemy = await prisma.user_Game.findFirst({ .returning()
where: { if (!user_Game) return
gameId: socket.data.gameId, const enemy = await db.query.user_games.findFirst({
}, where: eq(user_games.gameId, socket.data.gameId),
}) })
let body: GamePropsSchema let body: GamePropsSchema
if (user_Game.index === 1 && enemy) { if (user_Game[0].index === 1 && enemy) {
const { game } = await prisma.user_Game.update({ const game = await db
where: { .update(user_games)
gameId_index: { .set({
gameId: socket.data.gameId,
index: 2,
},
},
data: {
index: 1, index: 1,
}, })
select: { .where(
game: { ...gameSelects }, and(
}, eq(user_games.gameId, socket.data.gameId),
}) eq(user_games.index, 2),
),
)
.returning()
.then((user_Game) =>
db.query.games.findFirst({
where: eq(games.id, user_Game[0].gameId),
...gameSelects,
}),
)
if (!game) return
body = composeBody(game) body = composeBody(game)
} else { } else {
const game = await prisma.game.findUnique({ const game = await db.query.games.findFirst({
where: { where: eq(games.id, socket.data.gameId),
id: socket.data.gameId,
},
...gameSelects, ...gameSelects,
}) })
if (!game) return cb(false) if (!game) return cb(false)
@ -156,11 +172,7 @@ export async function GET({ request }: { request: RequestWithSocket }) {
cb(true) cb(true)
if (!payload.users.length) { if (!payload.users.length) {
await prisma.game.delete({ await db.delete(games).where(eq(games.id, socket.data.gameId))
where: {
id: socket.data.gameId,
},
})
} }
}) })
@ -200,41 +212,42 @@ export async function GET({ request }: { request: RequestWithSocket }) {
socket.on("gameState", async (newState) => { socket.on("gameState", async (newState) => {
if (socket.data.index !== 0 || !socket.data.gameId) return if (socket.data.index !== 0 || !socket.data.gameId) return
await prisma.game.update({ await db
where: { id: socket.data.gameId }, .update(games)
data: { .set({
state: newState, state: newState,
}, })
}) .where(eq(games.id, socket.data.gameId))
io.to(socket.data.gameId).emit("gameState", newState) io.to(socket.data.gameId).emit("gameState", newState)
if (newState === "running") if (newState === "running")
io.to(socket.data.gameId).emit("activeIndex", 0) io.to(socket.data.gameId).emit("activeIndex", 0)
}) })
socket.on("ships", async (ships) => { socket.on("ships", async (shipsData) => {
if ( if (
!socket.data.gameId || !socket.data.gameId ||
!socket.data.user?.id || !socket.data.user?.id ||
typeof socket.data.index === "undefined" typeof socket.data.index === "undefined"
) )
return return
await prisma.user_Game.update({
where: { const user_Game = await db.query.user_games.findFirst({
gameId_userId: { where: and(
gameId: socket.data.gameId, eq(user_games.gameId, socket.data.gameId),
userId: socket.data.user.id, eq(user_games.userId, socket.data.user?.id ?? ""),
}, ),
},
data: {
ships: {
deleteMany: {},
createMany: {
data: ships,
},
},
},
}) })
socket.to(socket.data.gameId).emit("ships", ships, socket.data.index)
if (!user_Game) return
await db
.insert(ships)
.values(
shipsData.map((ship) => ({ ...ship, user_game_id: user_Game.id })),
)
socket
.to(socket.data.gameId)
.emit("ships", shipsData, socket.data.index)
}) })
socket.on("dispatchMove", async (props) => { socket.on("dispatchMove", async (props) => {
@ -244,23 +257,22 @@ export async function GET({ request }: { request: RequestWithSocket }) {
typeof socket.data.index === "undefined" typeof socket.data.index === "undefined"
) )
return return
const user_Game = await prisma.user_Game
.update({ const user_Game = await db.query.user_games.findFirst({
where: { where: (uG) =>
gameId_userId: { and(
gameId: socket.data.gameId, eq(uG.gameId, socket.data.gameId),
userId: socket.data.user?.id, eq(uG.userId, socket.data.user?.id ?? ""),
}, ),
}, with: { game: gameSelects },
data: { })
moves: {
create: props,
},
},
select: { game: gameSelects },
})
.catch((e) => console.log(e, props))
if (!user_Game?.game) return if (!user_Game?.game) return
await db
.insert(moves)
.values({ ...props, user_game_id: user_Game.id })
.returning()
const game = user_Game.game const game = user_Game.game
const l1 = game.users[0].moves.length const l1 = game.users[0].moves.length
const l2 = game.users[1].moves.length const l2 = game.users[1].moves.length
@ -286,4 +298,5 @@ export async function GET({ request }: { request: RequestWithSocket }) {
}) })
}) })
} }
return res
} }

View file

@ -1,6 +1,6 @@
import AzureADProvider from "@auth/core/providers/azure-ad" import AzureADProvider from "@auth/core/providers/azure-ad"
import EmailProvider from "@auth/core/providers/email" import EmailProvider from "@auth/core/providers/email"
import { PrismaAdapter } from "@auth/prisma-adapter" import { DrizzleAdapter } from "@auth/drizzle-adapter"
import { type SolidAuthConfig } from "@auth/solid-start" import { type SolidAuthConfig } from "@auth/solid-start"
import { import {
animals, animals,
@ -8,7 +8,7 @@ import {
NumberDictionary, NumberDictionary,
uniqueNamesGenerator, uniqueNamesGenerator,
} from "unique-names-generator" } from "unique-names-generator"
import prisma from "~/lib/prisma" import db from "~/drizzle"
const numberDictionary = NumberDictionary.generate({ min: 0, max: 9999 }) const numberDictionary = NumberDictionary.generate({ min: 0, max: 9999 })
const customConfig: Config = { const customConfig: Config = {
@ -31,7 +31,7 @@ export const authOptions: SolidAuthConfig = {
tenantId: process.env.AZURE_AD_TENANT_ID, tenantId: process.env.AZURE_AD_TENANT_ID,
}), }),
], ],
adapter: PrismaAdapter(prisma), adapter: DrizzleAdapter(db),
secret: process.env.AUTH_SECRET, secret: process.env.AUTH_SECRET,
callbacks: { callbacks: {
signIn: ({ user, account }) => { signIn: ({ user, account }) => {

View file

@ -7,5 +7,4 @@ export default defineConfig({
host: "0.0.0.0", host: "0.0.0.0",
strictPort: true, strictPort: true,
}, },
ssr: { external: ["@prisma/client"] },
}) })