Migrated to latest solid-start version

This commit is contained in:
aronmal 2024-02-22 17:11:47 +01:00
parent 777b807225
commit 6fb057a102
Signed by: aronmal
GPG key ID: 816B7707426FC612
42 changed files with 4727 additions and 2128 deletions

View file

@ -1,14 +0,0 @@
module.exports = {
parser: "@typescript-eslint/parser",
parserOptions: {
project: ["./tsconfig.eslint.json", "./tsconfig.json"],
tsconfigRootDir: __dirname,
},
plugins: ["@typescript-eslint", "solid"],
extends: [
"plugin:solid/typescript",
"plugin:@typescript-eslint/recommended",
"prettier",
],
ignorePatterns: ["dist/**"],
}

View file

@ -0,0 +1,11 @@
{
"parser": "@typescript-eslint/parser",
"env": {
"node": true
},
"plugins": ["solid"],
"extends": [
"plugin:@typescript-eslint/recommended",
"plugin:solid/typescript"
]
}

View file

@ -1,42 +1,33 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# logs
/log /log
src/drizzle/migrations
# drizzle dist
/drizzle/migrations .vinxi
.output
.vercel
.netlify
netlify
# dependencies # Environment
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# SolidJS
/.solid/
/dist/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
# local env files
.env .env
.env*.local .env*.local
# typescript # dependencies
*.tsbuildinfo /node_modules
# IDEs and editors
/.idea
.project
.classpath
*.launch
.settings/
# Temp
gitignore
# System Files
.DS_Store
Thumbs.db
# playwright # playwright
/test-results/ /test-results/

View file

@ -1,9 +1,9 @@
{ {
"name": "leaky-ships", "name": "leaky-ships",
"scripts": { "scripts": {
"dev": "solid-start dev --port 3000", "dev": "vinxi dev",
"start": "solid-start start --port 3000", "build": "vinxi build",
"build": "solid-start build", "start": "vinxi start",
"lint": "eslint --fix \"**/*.{ts,tsx,js,jsx}\"", "lint": "eslint --fix \"**/*.{ts,tsx,js,jsx}\"",
"push": "drizzle-kit push:pg", "push": "drizzle-kit push:pg",
"test": "pnpm playwright test --ui", "test": "pnpm playwright test --ui",
@ -11,64 +11,65 @@
}, },
"type": "module", "type": "module",
"dependencies": { "dependencies": {
"@auth/core": "^0.13.0", "@auth/core": "^0.27.0",
"@auth/drizzle-adapter": "^0.3.2", "@auth/drizzle-adapter": "^0.7.0",
"@auth/solid-start": "^0.1.1", "@auth/solid-start": "^0.6.1",
"@fortawesome/fontawesome-svg-core": "^6.4.2", "@fortawesome/fontawesome-svg-core": "^6.5.1",
"@fortawesome/pro-duotone-svg-icons": "^6.4.2", "@fortawesome/pro-duotone-svg-icons": "^6.5.1",
"@fortawesome/pro-light-svg-icons": "^6.4.2", "@fortawesome/pro-light-svg-icons": "^6.5.1",
"@fortawesome/pro-regular-svg-icons": "^6.4.2", "@fortawesome/pro-regular-svg-icons": "^6.5.1",
"@fortawesome/pro-solid-svg-icons": "^6.4.2", "@fortawesome/pro-solid-svg-icons": "^6.5.1",
"@fortawesome/pro-thin-svg-icons": "^6.4.2", "@fortawesome/pro-thin-svg-icons": "^6.5.1",
"@fortawesome/sharp-solid-svg-icons": "^6.4.2", "@fortawesome/sharp-solid-svg-icons": "^6.5.1",
"@paralleldrive/cuid2": "^2.2.2", "@paralleldrive/cuid2": "^2.2.2",
"@solidjs/meta": "^0.28.6", "@solidjs/meta": "^0.29.3",
"@solidjs/router": "^0.8.3", "@solidjs/router": "^0.12.4",
"classnames": "^2.3.2", "@solidjs/start": "^0.5.9",
"classnames": "^2.5.1",
"colors": "^1.4.0", "colors": "^1.4.0",
"drizzle-orm": "^0.28.6", "drizzle-orm": "^0.29.4",
"drizzle-zod": "^0.5.1", "drizzle-zod": "^0.5.1",
"http-status": "^1.7.0", "http-status": "^1.7.3",
"json-stable-stringify": "^1.0.2", "json-stable-stringify": "^1.1.1",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"nodemailer": "^6.9.5", "nodemailer": "^6.9.10",
"object-hash": "^3.0.0", "object-hash": "^3.0.0",
"postgres": "^3.3.5", "postgres": "^3.4.3",
"socket.io": "^4.7.2", "socket.io": "^4.7.4",
"socket.io-client": "^4.7.2", "socket.io-client": "^4.7.4",
"solid-color": "^0.0.4", "solid-color": "^0.0.4",
"solid-js": "^1.7.11", "solid-js": "^1.8.15",
"solid-start": "^0.3.5",
"tinycolor2": "^1.6.0", "tinycolor2": "^1.6.0",
"unique-names-generator": "^4.7.1", "unique-names-generator": "^4.7.1",
"zod": "3.21.1" "vinxi": "^0.3.3",
"zod": "3.22.4"
}, },
"packageManager": "pnpm@8.7.4", "packageManager": "pnpm@8.7.4",
"devDependencies": { "devDependencies": {
"@playwright/test": "^1.37.1", "@playwright/test": "^1.41.2",
"@total-typescript/ts-reset": "^0.4.2", "@total-typescript/ts-reset": "^0.5.1",
"@types/json-stable-stringify": "^1.0.34", "@types/json-stable-stringify": "^1.0.36",
"@types/node": "^20.5.9", "@types/node": "^20.11.19",
"@types/nodemailer": "^6.4.9", "@types/nodemailer": "^6.4.14",
"@types/object-hash": "^3.0.4", "@types/object-hash": "^3.0.6",
"@types/web-bluetooth": "^0.0.17", "@types/web-bluetooth": "^0.0.20",
"@typescript-eslint/eslint-plugin": "^6.6.0", "@typescript-eslint/eslint-plugin": "^7.0.2",
"autoprefixer": "^10.4.15", "autoprefixer": "^10.4.17",
"dotenv": "^16.3.1", "dotenv": "^16.4.5",
"drizzle-kit": "^0.19.13", "drizzle-kit": "^0.20.14",
"eslint": "^8.48.0", "eslint": "^8.56.0",
"eslint-config-prettier": "^9.0.0", "eslint-config-prettier": "^9.1.0",
"eslint-plugin-solid": "^0.12.1", "eslint-plugin-solid": "^0.13.1",
"pg": "^8.11.3", "pg": "^8.11.3",
"postcss": "^8.4.29", "postcss": "^8.4.35",
"prettier": "^3.0.3", "prettier": "^3.2.5",
"prettier-plugin-organize-imports": "^3.2.3", "prettier-plugin-organize-imports": "^3.2.4",
"prettier-plugin-tailwindcss": "^0.5.4", "prettier-plugin-tailwindcss": "^0.5.11",
"sass": "^1.66.1", "sass": "^1.71.1",
"solid-start-node": "^0.3.5", "solid-start-node": "^0.3.10",
"tailwindcss": "^3.3.3", "tailwindcss": "^3.4.1",
"typescript": "^5.2.2", "typescript": "^5.3.3",
"vite": "^4.4.9" "vite": "^5.1.4"
}, },
"pnpm": { "pnpm": {
"overrides": { "overrides": {

File diff suppressed because it is too large Load diff

39
leaky-ships/src/app.tsx Normal file
View file

@ -0,0 +1,39 @@
// @refresh reload
import "@fortawesome/fontawesome-svg-core/styles.css"
import { Link, Meta, MetaProvider, Title } from "@solidjs/meta"
import { Router } from "@solidjs/router"
import { FileRoutes } from "@solidjs/start"
import { Suspense } from "solid-js"
import "./styles/App.scss"
import "./styles/globals.scss"
import "./styles/grid.scss"
import "./styles/grid2.scss"
import "./styles/root.css"
export default function App() {
return (
<Router
root={(props) => (
<MetaProvider>
<Title>Leaky Ships</Title>
<Meta charset="utf-8" />
<Meta name="viewport" content="width=device-width, initial-scale=1" />
<Link rel="manifest" href="/manifest.json" />
<Link rel="icon" href="/favicon.ico" />
<Meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta name="theme-color" content="#000000" />
<Meta
name="description"
content="Battleship web app with react frontend and ASP .NET backend"
/>
<Link rel="apple-touch-icon" href="/logo192.png" />
<Suspense>{props.children}</Suspense>
</MetaProvider>
)}
>
<FileRoutes />
</Router>
)
}

View file

@ -24,8 +24,8 @@ import {
import { socket } from "~/lib/socket" import { socket } from "~/lib/socket"
import { modes } from "~/lib/utils/helpers" import { modes } from "~/lib/utils/helpers"
// import { Icons, toast } from "react-toastify" // import { Icons, toast } from "react-toastify"
import { useNavigate } from "@solidjs/router"
import { For, Show, createEffect } from "solid-js" import { For, Show, createEffect } from "solid-js"
import { useNavigate } from "solid-start"
import { clearDrawing } from "~/hooks/useDraw" import { clearDrawing } from "~/hooks/useDraw"
import { import {
color, color,

View file

@ -1,8 +1,8 @@
// import Bluetooth from "./Bluetooth" // import Bluetooth from "./Bluetooth"
// import FogImages from "./FogImages" // import FogImages from "./FogImages"
// import { toast } from "react-toastify" // import { toast } from "react-toastify"
import { useNavigate } from "@solidjs/router"
import { createEffect, onCleanup } from "solid-js" import { createEffect, onCleanup } from "solid-js"
import { useNavigate } from "solid-start"
import BorderTiles from "~/components/Gamefield/BorderTiles" import BorderTiles from "~/components/Gamefield/BorderTiles"
import EventBar from "~/components/Gamefield/EventBar" import EventBar from "~/components/Gamefield/EventBar"
import HitElems from "~/components/Gamefield/HitElems" import HitElems from "~/components/Gamefield/HitElems"

View file

@ -2,8 +2,8 @@ import {
faRightFromBracket, faRightFromBracket,
faSpinnerThird, faSpinnerThird,
} from "@fortawesome/pro-solid-svg-icons" } from "@fortawesome/pro-solid-svg-icons"
import { useNavigate } from "@solidjs/router"
import { JSX, Show, createEffect, createSignal, onCleanup } from "solid-js" import { JSX, Show, createEffect, createSignal, onCleanup } from "solid-js"
import { useNavigate } from "solid-start"
import { FontAwesomeIcon } from "~/components/FontAwesomeIcon" import { FontAwesomeIcon } from "~/components/FontAwesomeIcon"
import { full, gameProps, leave, reset, users } from "~/hooks/useGameProps" import { full, gameProps, leave, reset, users } from "~/hooks/useGameProps"
import { useSession } from "~/hooks/useSession" import { useSession } from "~/hooks/useSession"

View file

@ -1,9 +1,8 @@
import classNames from "classnames" import classNames from "classnames"
import { A } from "solid-start"
function Logo(props: { small?: boolean }) { function Logo(props: { small?: boolean }) {
return ( return (
<A href="/"> <a href="/">
<div class="relative flex flex-col items-center rounded-sm border-x-4 border-y-2 border-shield-gray bg-shield-lightgray md:border-x-8 md:border-y-4"> <div class="relative flex flex-col items-center rounded-sm border-x-4 border-y-2 border-shield-gray bg-shield-lightgray md:border-x-8 md:border-y-4">
<h1 <h1
class={classNames( class={classNames(
@ -16,7 +15,7 @@ function Logo(props: { small?: boolean }) {
</h1> </h1>
<Screws small={props.small} /> <Screws small={props.small} />
</div> </div>
</A> </a>
) )
} }

View file

@ -1,7 +1,6 @@
import { IconDefinition } from "@fortawesome/fontawesome-svg-core" import { IconDefinition } from "@fortawesome/fontawesome-svg-core"
import classNames from "classnames" import classNames from "classnames"
import { JSX } from "solid-js" import { JSX } from "solid-js"
import { A } from "solid-start"
import { FontAwesomeIcon } from "./FontAwesomeIcon" import { FontAwesomeIcon } from "./FontAwesomeIcon"
const styles = { const styles = {
@ -20,7 +19,7 @@ export function OptionAnchor(props: {
disabled?: boolean disabled?: boolean
}) { }) {
return ( return (
<A <a
class={classNames( class={classNames(
styles.wrapper, styles.wrapper,
props.disabled ? styles.disabled : styles.enabled, props.disabled ? styles.disabled : styles.enabled,
@ -30,7 +29,7 @@ export function OptionAnchor(props: {
> >
<span class="mx-auto">{props.text}</span> <span class="mx-auto">{props.text}</span>
<FontAwesomeIcon class={styles.icon} icon={props.icon} /> <FontAwesomeIcon class={styles.icon} icon={props.icon} />
</A> </a>
) )
} }

View file

@ -2,7 +2,7 @@ import { drizzle } from "drizzle-orm/postgres-js"
import postgres from "postgres" import postgres from "postgres"
import * as schema from "./schemas/Tables" import * as schema from "./schemas/Tables"
const queryClient = postgres(process.env.DATABASE_URL ?? "") const queryClient = postgres(import.meta.env.VITE_DATABASE_URL ?? "")
const db = drizzle(queryClient, { const db = drizzle(queryClient, {
schema, schema,
}) })

View file

@ -1,3 +1,3 @@
import { mount, StartClient } from "solid-start/entry-client" import { mount, StartClient } from "@solidjs/start/client"
mount(() => <StartClient />, document) mount(() => <StartClient />, document.getElementById("app")!)

View file

@ -1,9 +1,20 @@
import { import { StartServer, createHandler } from "@solidjs/start/server"
createHandler,
renderAsync,
StartServer,
} from "solid-start/entry-server"
export default createHandler( export default createHandler(() => (
renderAsync((event) => <StartServer event={event} />), <StartServer
) document={({ assets, children, scripts }) => (
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
{assets}
</head>
<body id="app">
{children}
{scripts}
</body>
</html>
)}
/>
))

View file

@ -1,4 +1,7 @@
import { Session } from "@auth/core/types" import { Session } from "@auth/core/types"
import { getSession } from "@auth/solid-start"
import { useIsRouting } from "@solidjs/router"
import status from "http-status"
import stringify from "json-stable-stringify" import stringify from "json-stable-stringify"
import { import {
JSX, JSX,
@ -8,7 +11,8 @@ import {
createSignal, createSignal,
useContext, useContext,
} from "solid-js" } from "solid-js"
import { useIsRouting } from "solid-start" import { getRequestEvent } from "solid-js/web"
import { authOptions } from "~/server/auth"
import { gameProps, setGameProps, users } from "./useGameProps" import { gameProps, setGameProps, users } from "./useGameProps"
const [state, setState] = createSignal<Session | null | undefined>(undefined) const [state, setState] = createSignal<Session | null | undefined>(undefined)
@ -61,12 +65,17 @@ const contextValue = {
} }
export const SessionCtx = createContext(contextValue) export const SessionCtx = createContext(contextValue)
export async function getSessionFromServer() {
"use server"
const event = getRequestEvent()
if (!event) return
const session = await getSession(event.request, authOptions)
if (session) return session
else return null
}
export function SessionProvider(props: { children: JSX.Element }) { export function SessionProvider(props: { children: JSX.Element }) {
const fetchData = () => const [data, { refetch }] = createResource(() => getSessionFromServer())
fetch("/api/session").then((res) =>
res.ok ? (res.json() as Promise<Session>) : null,
)
const [data, { refetch }] = createResource(fetchData)
const isRouting = useIsRouting() const isRouting = useIsRouting()
createEffect(() => { createEffect(() => {
@ -77,8 +86,9 @@ export function SessionProvider(props: { children: JSX.Element }) {
createEffect(() => { createEffect(() => {
const session = data() const session = data()
const hashDiff = stringify(session) !== stringify(state()) const hashDiff = stringify(session) !== stringify(state())
if (session === undefined || data.loading || !hashDiff) return if (!session || !hashDiff) return
console.log("Session updated.") console.log("Session updated.")
// @ts-ignore
setState(session) setState(session)
}) })
@ -103,3 +113,14 @@ export function SessionProvider(props: { children: JSX.Element }) {
} }
export const useSession = () => useContext(SessionCtx) export const useSession = () => useContext(SessionCtx)
export function isAuthenticated(res: Response) {
switch (status[`${res.status}_CLASS`]) {
case status.classes.SUCCESSFUL:
case status.classes.REDIRECTION:
return res.json()
}
const resStatus = status[`${res.status}_CLASS`]
if (typeof resStatus !== "string") return
}

View file

@ -1,12 +1,11 @@
import status from "http-status" import status from "http-status"
// import { toast } from "react-toastify" // import { toast } from "react-toastify"
import { useNavigate } from "@solidjs/router"
import { createEffect, createSignal, onCleanup } from "solid-js" import { createEffect, createSignal, onCleanup } from "solid-js"
import { useNavigate } from "solid-start"
import { getPayloadFromProps } from "~/lib/getPayloadFromProps" import { getPayloadFromProps } from "~/lib/getPayloadFromProps"
import { getPayloadwithChecksum } from "~/lib/getPayloadwithChecksum" import { getPayloadwithChecksum } from "~/lib/getPayloadwithChecksum"
import { socket } from "~/lib/socket" import { socket } from "~/lib/socket"
import { GamePropsSchema, GameState } from "~/lib/zodSchemas" import { GamePropsSchema, GameState } from "~/lib/zodSchemas"
import { isAuthenticated } from "~/routes/start"
import { GameSettings, PlayerEvent } from "../interfaces/frontend" import { GameSettings, PlayerEvent } from "../interfaces/frontend"
import { import {
DispatchMove, DispatchMove,
@ -20,7 +19,7 @@ import {
setShips, setShips,
users, users,
} from "./useGameProps" } from "./useGameProps"
import { useSession } from "./useSession" import { isAuthenticated, useSession } from "./useSession"
/** This function should only be called once per page, otherwise there will be multiple socket connections and duplicate event listeners. */ /** This function should only be called once per page, otherwise there will be multiple socket connections and duplicate event listeners. */
function useSocket() { function useSocket() {

View file

@ -1,5 +1,6 @@
import { Session } from "@auth/core/types" import { Session } from "@auth/core/types"
import http from "http" import type { Server as HTTPServer } from "http"
import type { Socket as NetSocket } from "net"
import type { import type {
Server as IOServer, Server as IOServer,
Server, Server,
@ -16,10 +17,14 @@ import {
ShipProps, ShipProps,
} from "./frontend" } from "./frontend"
export interface SocketServer extends http.Server { interface SocketServer extends HTTPServer {
io?: IOServer io?: IOServer
} }
export interface SocketWithIO extends NetSocket {
server: SocketServer
}
export interface ServerToClientEvents { export interface ServerToClientEvents {
gameSetting: (payload: GameSettings, hash: string) => void gameSetting: (payload: GameSettings, hash: string) => void
playerEvent: (event: PlayerEvent) => void playerEvent: (event: PlayerEvent) => void

View file

@ -1,4 +1,4 @@
import { APIEvent } from "solid-start" import { APIEvent } from "@solidjs/start/server/types"
import { z } from "zod" import { z } from "zod"
import sendError from "./sendError" import sendError from "./sendError"

View file

@ -1,7 +1,7 @@
import { APIEvent } from "@solidjs/start/server/types"
import colors, { Color } from "colors" import colors, { Color } from "colors"
import fs from "fs" import fs from "fs"
import { IncomingMessage } from "http" import { IncomingMessage } from "http"
import { APIEvent } from "solid-start"
colors.enable() colors.enable()

View file

@ -0,0 +1,111 @@
import { and, eq, exists, ne } from "drizzle-orm"
import db from "~/drizzle"
import { games, user_games } from "~/drizzle/schemas/Tables"
import { getPayloadwithChecksum } from "~/lib/getPayloadwithChecksum"
import { GamePropsSchema } from "~/lib/zodSchemas"
export const gameSelects = {
columns: {
id: true,
allowChat: true,
allowMarkDraw: true,
allowSpecials: true,
allowSpectators: true,
state: true,
},
with: {
gamePin: {
columns: {
pin: true,
},
},
users: {
columns: {
id: true,
index: true,
},
with: {
chats: {
columns: {
id: true,
event: true,
message: true,
createdAt: true,
},
},
moves: {
columns: {
index: true,
type: true,
x: true,
y: true,
orientation: true,
},
},
ships: {
columns: {
size: true,
variant: true,
x: true,
y: true,
orientation: true,
},
},
user: {
columns: {
id: true,
name: true,
},
},
},
},
},
} as const
export const getGameById = async (gameId: string) => {
return db.query.games.findFirst({
where: and(ne(games.state, "ended"), eq(games.id, gameId)),
...gameSelects,
})
}
export const getRunningGameToUser = async (userId: string) => {
return db.query.games.findFirst({
where: (game) =>
and(
ne(game.state, "ended"),
exists(
db
.select()
.from(user_games)
.where(
and(
eq(user_games.gameId, game.id),
eq(user_games.userId, userId),
),
),
),
),
...gameSelects,
})
}
export function composeBody(
gameDB: NonNullable<Awaited<ReturnType<typeof getRunningGameToUser>>>,
): GamePropsSchema {
const { gamePin, users, ...game } = gameDB
const mappedUsers = users.map(({ user, ...props }) => ({
...props,
...user,
}))
const composedUsers = {
0: mappedUsers.find((e) => e.index === 0) ?? null,
1: mappedUsers.find((e) => e.index === 1) ?? null,
}
const payload = {
game: game,
gamePin: gamePin?.pin ?? null,
users: composedUsers,
}
return getPayloadwithChecksum(payload)
}

View file

@ -1,4 +1,4 @@
import { APIEvent, json } from "solid-start" import { APIEvent } from "@solidjs/start/server/types"
import { rejectionError } from "./errors" import { rejectionError } from "./errors"
import logging from "./logging" import logging from "./logging"
@ -15,5 +15,7 @@ export default function sendError(
) )
if ("name" in err) console.log("Sending Respons: " + 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 new Response(null, {
status: "statusCode" in err ? err.statusCode : 500,
})
} }

View file

@ -1,4 +1,5 @@
import { APIEvent, json, redirect } from "solid-start/api" import { redirect } from "@solidjs/router"
import { APIEvent } from "@solidjs/start/server/types"
import logging, { Logging } from "./logging" import logging, { Logging } from "./logging"
export interface Result<T> { export interface Result<T> {
@ -18,6 +19,11 @@ export default function sendResponse<T>(
return redirect(result.redirectUrl) return redirect(result.redirectUrl)
} else { } else {
logging(result.message, result.type ?? ["debug"], request) logging(result.message, result.type ?? ["debug"], request)
return json(result.body, { status: result.statusCode ?? 200 }) return new Response(JSON.stringify(result.body), {
status: result.statusCode ?? 200,
headers: {
"Content-Type": "application/json",
},
})
} }
} }

View file

@ -1,56 +0,0 @@
// @refresh reload
import "@fortawesome/fontawesome-svg-core/styles.css"
import { Suspense } from "solid-js"
import {
Body,
ErrorBoundary,
FileRoutes,
Head,
Html,
Link,
Meta,
Routes,
Scripts,
Title,
} from "solid-start"
import { SessionProvider } from "./hooks/useSession"
import "./styles/App.scss"
import "./styles/globals.scss"
import "./styles/grid.scss"
import "./styles/grid2.scss"
import "./styles/root.css"
export default function Root() {
return (
<Html lang="en">
<Head>
<Title>Leaky Ships</Title>
<Meta charset="utf-8" />
<Meta name="viewport" content="width=device-width, initial-scale=1" />
<Link rel="manifest" href="/manifest.json" />
<Link rel="icon" href="/favicon.ico" />
<Meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta name="theme-color" content="#000000" />
<Meta
name="description"
content="Battleship web app with react frontend and ASP .NET backend"
/>
<Link rel="apple-touch-icon" href="/logo192.png" />
</Head>
<Body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<Suspense fallback={<div>Loading</div>}>
<ErrorBoundary>
<SessionProvider>
<Routes>
<FileRoutes />
</Routes>
</SessionProvider>
</ErrorBoundary>
</Suspense>
<Scripts />
</Body>
</Html>
)
}

View file

@ -1,5 +1,5 @@
import { redirect } from "solid-start" import { Navigate } from "@solidjs/router"
export function GET() { export default function NOT_FOUND() {
return redirect("/") return <Navigate href="/" />
} }

View file

@ -1,6 +1,6 @@
import { getSession } from "@auth/solid-start" import { getSession } from "@auth/solid-start"
import { APIEvent } from "@solidjs/start/server/types"
import { eq } from "drizzle-orm" import { eq } from "drizzle-orm"
import { APIEvent } from "solid-start"
import { z } from "zod" import { z } from "zod"
import db from "~/drizzle" import db from "~/drizzle"
import { games } from "~/drizzle/schemas/Tables" import { games } from "~/drizzle/schemas/Tables"

View file

@ -1,13 +1,17 @@
import { getSession } from "@auth/solid-start" import { getSession } from "@auth/solid-start"
import { createId } from "@paralleldrive/cuid2" import { createId } from "@paralleldrive/cuid2"
import { APIEvent } from "@solidjs/start/server/types"
import { eq } from "drizzle-orm" import { eq } from "drizzle-orm"
import { APIEvent } from "solid-start"
import db from "~/drizzle" import db from "~/drizzle"
import { chats, gamepins, games, user_games } from "~/drizzle/schemas/Tables" import { chats, gamepins, games, user_games } from "~/drizzle/schemas/Tables"
import { rejectionErrors } from "~/lib/backend/errors" import { rejectionErrors } from "~/lib/backend/errors"
import {
composeBody,
gameSelects,
getRunningGameToUser,
} from "~/lib/backend/processRes"
import sendResponse from "~/lib/backend/sendResponse" import sendResponse from "~/lib/backend/sendResponse"
import { authOptions } from "~/server/auth" import { authOptions } from "~/server/auth"
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)
@ -15,6 +19,8 @@ export async function POST({ request }: APIEvent) {
if (!session?.user) { if (!session?.user) {
return sendResponse(request, rejectionErrors.unauthorized) return sendResponse(request, rejectionErrors.unauthorized)
} }
// @ts-ignore
const { email, id } = session.user const { email, id } = session.user
// Generate a random 4-digit code // Generate a random 4-digit code

View file

@ -1,16 +1,16 @@
import { getSession } from "@auth/solid-start" import { getSession } from "@auth/solid-start"
import { createId } from "@paralleldrive/cuid2" import { createId } from "@paralleldrive/cuid2"
import { APIEvent } from "@solidjs/start/server/types"
import { and, eq } from "drizzle-orm" import { and, eq } from "drizzle-orm"
import { APIEvent } from "solid-start"
import db from "~/drizzle" import db from "~/drizzle"
import { user_games } from "~/drizzle/schemas/Tables" import { user_games } 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 { composeBody, gameSelects, getGameById } from "~/lib/backend/processRes"
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 { authOptions } from "~/server/auth" import { authOptions } from "~/server/auth"
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,6 +20,7 @@ export async function POST({ request }: APIEvent) {
return sendResponse(request, rejectionErrors.unauthorized) return sendResponse(request, rejectionErrors.unauthorized)
} }
// @ts-ignore
const { email, id } = session.user const { email, id } = session.user
try { try {

View file

@ -1,121 +1,14 @@
import { getSession } from "@auth/solid-start" import { getSession } from "@auth/solid-start"
import { and, eq, exists, ne, notExists } from "drizzle-orm" import { APIEvent } from "@solidjs/start/server/types"
import { APIEvent } from "solid-start/api" import { eq, notExists } from "drizzle-orm"
import db from "~/drizzle" import db from "~/drizzle"
import { games, user_games } from "~/drizzle/schemas/Tables" import { games, user_games } from "~/drizzle/schemas/Tables"
import { rejectionErrors } from "~/lib/backend/errors" import { rejectionErrors } from "~/lib/backend/errors"
import logging from "~/lib/backend/logging" import logging from "~/lib/backend/logging"
import { composeBody, getRunningGameToUser } from "~/lib/backend/processRes"
import sendResponse from "~/lib/backend/sendResponse" import sendResponse from "~/lib/backend/sendResponse"
import { getPayloadwithChecksum } from "~/lib/getPayloadwithChecksum"
import { GamePropsSchema } from "~/lib/zodSchemas"
import { authOptions } from "~/server/auth" import { authOptions } from "~/server/auth"
export const gameSelects = {
columns: {
id: true,
allowChat: true,
allowMarkDraw: true,
allowSpecials: true,
allowSpectators: true,
state: true,
},
with: {
gamePin: {
columns: {
pin: true,
},
},
users: {
columns: {
id: true,
index: true,
},
with: {
chats: {
columns: {
id: true,
event: true,
message: true,
createdAt: true,
},
},
moves: {
columns: {
index: true,
type: true,
x: true,
y: true,
orientation: true,
},
},
ships: {
columns: {
size: true,
variant: true,
x: true,
y: true,
orientation: true,
},
},
user: {
columns: {
id: true,
name: true,
},
},
},
},
},
} as const
export const getGameById = async (gameId: string) => {
return db.query.games.findFirst({
where: and(ne(games.state, "ended"), eq(games.id, gameId)),
...gameSelects,
})
}
export const getRunningGameToUser = async (userId: string) => {
return db.query.games.findFirst({
where: (game) =>
and(
ne(game.state, "ended"),
exists(
db
.select()
.from(user_games)
.where(
and(
eq(user_games.gameId, game.id),
eq(user_games.userId, userId),
),
),
),
),
...gameSelects,
})
}
export function composeBody(
gameDB: NonNullable<Awaited<ReturnType<typeof getRunningGameToUser>>>,
): GamePropsSchema {
const { gamePin, users, ...game } = gameDB
const mappedUsers = users.map(({ user, ...props }) => ({
...props,
...user,
}))
const composedUsers = {
0: mappedUsers.find((e) => e.index === 0) ?? null,
1: mappedUsers.find((e) => e.index === 1) ?? null,
}
const payload = {
game: game,
gamePin: gamePin?.pin ?? null,
users: composedUsers,
}
return getPayloadwithChecksum(payload)
}
export async function GET({ request }: APIEvent) { export async function GET({ request }: APIEvent) {
const session = await getSession(request, authOptions) const session = await getSession(request, authOptions)
@ -143,6 +36,7 @@ export async function GET({ request }: APIEvent) {
) )
} }
// @ts-ignore
const { email, id } = session.user const { email, id } = session.user
const game = await getRunningGameToUser(id) const game = await getRunningGameToUser(id)

View file

@ -1,10 +0,0 @@
import { getSession } from "@auth/solid-start"
import status from "http-status"
import { APIEvent, json } from "solid-start"
import { authOptions } from "~/server/auth"
export async function GET({ request }: APIEvent) {
const session = await getSession(request, authOptions)
if (session) return json(session)
else return new Response(null, { status: status["UNAUTHORIZED"] })
}

View file

@ -1,47 +1,45 @@
import { getSession } from "@auth/solid-start" import { getSession } from "@auth/solid-start"
import { createId } from "@paralleldrive/cuid2" import { createId } from "@paralleldrive/cuid2"
import { APIEvent } from "@solidjs/start/server/types"
import colors from "colors" import colors from "colors"
import { and, eq } from "drizzle-orm" 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 { APIEvent } from "solid-start"
import db from "~/drizzle" import db from "~/drizzle"
import { games, moves, ships, user_games } from "~/drizzle/schemas/Tables" import { games, moves, ships, user_games } from "~/drizzle/schemas/Tables"
import { SocketServer, sServer } from "~/interfaces/ApiSocket" import { SocketWithIO, sServer } from "~/interfaces/ApiSocket"
import logging from "~/lib/backend/logging" import logging from "~/lib/backend/logging"
import { GamePropsSchema } from "~/lib/zodSchemas"
import { authOptions } from "~/server/auth"
import { import {
composeBody, composeBody,
gameSelects, gameSelects,
getGameById, getGameById,
getRunningGameToUser, getRunningGameToUser,
} from "./game/running" } from "~/lib/backend/processRes"
import { GamePropsSchema } from "~/lib/zodSchemas"
import { authOptions } from "~/server/auth"
colors.enable() colors.enable()
export async function GET({ export async function GET({ request, nativeEvent }: APIEvent) {
request, const socket = nativeEvent.node.res.socket as SocketWithIO
httpServer, if (socket.server.io) {
}: APIEvent & { httpServer: SocketServer }) {
if (httpServer.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(httpServer, { const io: sServer = new Server(socket.server, {
path: "/api/ws", path: "/api/ws",
cors: { cors: {
origin: "https://leaky-ships.mal-noh.de", origin: import.meta.env.VITE_AUTH_URL,
}, },
}) })
httpServer.io = io socket.server.io = io
// io.use(authenticate) // io.use(authenticate)
io.use(async (socket, next) => { io.use(async (socket, next) => {
const request = socket.request const request = socket.request
try { try {
const url = process.env.AUTH_URL! + request.url const url = import.meta.env.VITE_AUTH_URL! + request.url
const session = await getSession( const session = await getSession(
new Request(url, { new Request(url, {
headers: request.headers as Record<string, string>, headers: request.headers as Record<string, string>,
@ -49,6 +47,8 @@ export async function GET({
authOptions, authOptions,
) )
if (!session) return next(new Error(status["401"])) if (!session) return next(new Error(status["401"]))
// @ts-ignore
socket.data.user = session.user socket.data.user = session.user
const game = await getRunningGameToUser(socket.data.user?.id ?? "") const game = await getRunningGameToUser(socket.data.user?.id ?? "")

View file

@ -1,4 +1,4 @@
import { Link, Meta, Title } from "solid-start" import { Link, Meta, Title } from "@solidjs/meta"
import Gamefield from "~/components/Gamefield/Gamefield" import Gamefield from "~/components/Gamefield/Gamefield"
export default function Home() { export default function Home() {

View file

@ -1,4 +1,4 @@
import { Link, Meta, Title } from "solid-start" import { Link, Meta, Title } from "@solidjs/meta"
import Grid from "~/components/Grid" import Grid from "~/components/Grid"
export default function Home() { export default function Home() {

View file

@ -1,4 +1,4 @@
import { Link, Meta, Title } from "solid-start" import { Link, Meta, Title } from "@solidjs/meta"
import Grid2 from "~/components/Grid2" import Grid2 from "~/components/Grid2"
export default function Home() { export default function Home() {

View file

@ -1,4 +1,3 @@
import { A } from "solid-start"
import BurgerMenu from "~/components/BurgerMenu" import BurgerMenu from "~/components/BurgerMenu"
import Logo from "~/components/Logo" import Logo from "~/components/Logo"
@ -11,13 +10,13 @@ export default function Home() {
<div class="flex h-36 w-64 items-center justify-center overflow-hidden rounded-xl border-8 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]"> <div class="flex h-36 w-64 items-center justify-center overflow-hidden rounded-xl border-8 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]">
<video controls preload="metadata" src="/Regelwerk.mp4" /> <video controls preload="metadata" src="/Regelwerk.mp4" />
</div> </div>
<A <a
id="start" id="start"
class="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" class="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"
href="/start" href="/start"
> >
START START
</A> </a>
</div> </div>
</div> </div>
) )

View file

@ -1,8 +1,8 @@
import { signIn } from "@auth/solid-start/client" import { signIn } from "@auth/solid-start/client"
import { faLeftLong } from "@fortawesome/pro-solid-svg-icons" import { faLeftLong } from "@fortawesome/pro-solid-svg-icons"
import { useNavigate, useSearchParams } from "@solidjs/router"
import classNames from "classnames" import classNames from "classnames"
import { Show, createEffect, createSignal } from "solid-js" import { Show, createEffect, createSignal } from "solid-js"
import { A, useNavigate, useSearchParams } from "solid-start"
import { FontAwesomeIcon } from "~/components/FontAwesomeIcon" import { FontAwesomeIcon } from "~/components/FontAwesomeIcon"
import { useSession } from "~/hooks/useSession" import { useSession } from "~/hooks/useSession"
@ -55,7 +55,7 @@ function Login() {
if (session()) navigator("/signout") if (session()) navigator("/signout")
}) })
const login = (provider: "email" | "azure-ad") => const login = (provider: "discord") =>
signIn(provider, { email: email(), callbackUrl: "/" }) signIn(provider, { email: email(), callbackUrl: "/" })
return ( return (
@ -85,7 +85,7 @@ function Login() {
onSubmit={(e) => { onSubmit={(e) => {
e.preventDefault() e.preventDefault()
if (!email()) return if (!email()) return
login("email") // login("email")
}} }}
> >
<label for="email" class="mx-2 text-lg"> <label for="email" class="mx-2 text-lg">
@ -130,7 +130,7 @@ function Login() {
</a> </a>
<button <button
id="microsoft" id="microsoft"
onClick={() => login("azure-ad")} onClick={() => login("discord")}
class="flex w-full justify-evenly rounded-lg border border-gray-400 bg-slate-100 px-5 py-3 text-black drop-shadow-md duration-300 hover:bg-slate-200" class="flex w-full justify-evenly rounded-lg border border-gray-400 bg-slate-100 px-5 py-3 text-black drop-shadow-md duration-300 hover:bg-slate-200"
> >
<img <img
@ -147,14 +147,14 @@ function Login() {
<Show when={errorType}> <Show when={errorType}>
<hr class="mt-8 border-gray-400" /> <hr class="mt-8 border-gray-400" />
<div class="flex flex-col items-center"> <div class="flex flex-col items-center">
<A <a
id="back" id="back"
href="/" href="/"
class="mt-10 rounded-lg border-2 border-gray-400 bg-gray-500 bg-opacity-75 px-16 py-2 text-white shadow-inner drop-shadow-md backdrop-blur-md transition-colors duration-300 hover:border-blue-600" class="mt-10 rounded-lg border-2 border-gray-400 bg-gray-500 bg-opacity-75 px-16 py-2 text-white shadow-inner drop-shadow-md backdrop-blur-md transition-colors duration-300 hover:border-blue-600"
> >
<FontAwesomeIcon icon={faLeftLong} /> <FontAwesomeIcon icon={faLeftLong} />
<span class="mx-4 font-bold">Return</span> <span class="mx-4 font-bold">Return</span>
</A> </a>
</div> </div>
</Show> </Show>
</div> </div>

View file

@ -1,7 +1,7 @@
import { signOut } from "@auth/solid-start/client" import { signOut } from "@auth/solid-start/client"
import { faLeftLong } from "@fortawesome/pro-solid-svg-icons" import { faLeftLong } from "@fortawesome/pro-solid-svg-icons"
import { useNavigate } from "@solidjs/router"
import { createEffect } from "solid-js" import { createEffect } from "solid-js"
import { useNavigate } from "solid-start"
import { FontAwesomeIcon } from "~/components/FontAwesomeIcon" import { FontAwesomeIcon } from "~/components/FontAwesomeIcon"
import { useSession } from "~/hooks/useSession" import { useSession } from "~/hooks/useSession"

View file

@ -1,11 +1,7 @@
import { faEye, faLeftLong } from "@fortawesome/pro-regular-svg-icons" import { faEye, faLeftLong } from "@fortawesome/pro-regular-svg-icons"
import { faPlus, faUserPlus } from "@fortawesome/pro-solid-svg-icons" import { faPlus, faUserPlus } from "@fortawesome/pro-solid-svg-icons"
import { GamePropsSchema } from "~/lib/zodSchemas" import { useNavigate, useSearchParams } from "@solidjs/router"
// import OtpInput from "react-otp-input"
// import { Icons, toast } from "react-toastify"
import status from "http-status"
import { Show, createEffect, createSignal } from "solid-js" import { Show, createEffect, createSignal } from "solid-js"
import { A, useNavigate, useSearchParams } from "solid-start"
import BurgerMenu from "~/components/BurgerMenu" import BurgerMenu from "~/components/BurgerMenu"
import { FontAwesomeIcon } from "~/components/FontAwesomeIcon" import { FontAwesomeIcon } from "~/components/FontAwesomeIcon"
import Logo from "~/components/Logo" import Logo from "~/components/Logo"
@ -15,43 +11,17 @@ import {
OptionDiv, OptionDiv,
} from "~/components/OptionButton" } from "~/components/OptionButton"
import { full } from "~/hooks/useGameProps" import { full } from "~/hooks/useGameProps"
import { useSession } from "~/hooks/useSession" import {
SessionProvider,
export function isAuthenticated(res: Response) { isAuthenticated,
switch (status[`${res.status}_CLASS`]) { useSession,
case status.classes.SUCCESSFUL: } from "~/hooks/useSession"
case status.classes.REDIRECTION: import { GamePropsSchema } from "~/lib/zodSchemas"
return res.json()
}
const resStatus = status[`${res.status}_CLASS`]
if (typeof resStatus !== "string") return
// toast(status[res.status], {
// position: "top-center",
// type: "info",
// theme: "colored",
// })
}
// const handleConfirmation = () => {
// const toastId = "confirm"
// toast.warn(
// <div id="toast-confirm">
// <h4>You are already in another round, do you want to:</h4>
// <button onClick={() => toast.dismiss(toastId)}>Join</button>
// or
// <button onClick={() => toast.dismiss(toastId)}>Leave</button>
// </div>,
// { autoClose: false, toastId },
// )
// }
export default function Start() { export default function Start() {
const [otp, setOtp] = createSignal("") const [otp, setOtp] = createSignal("")
const navigator = useNavigate() const navigator = useNavigate()
const { session } = useSession() const { session } = useSession()
const [searchParams] = useSearchParams() const [searchParams] = useSearchParams()
const query = () => { const query = () => {
@ -138,27 +108,28 @@ export default function Start() {
}) })
return ( return (
<SessionProvider>
<div class="h-full bg-theme"> <div class="h-full bg-theme">
<div class="mx-auto flex h-full max-w-screen-md flex-col items-center justify-evenly"> <div class="mx-auto flex h-full max-w-screen-md flex-col items-center justify-evenly">
<Logo /> <Logo />
<BurgerMenu /> <BurgerMenu />
<div class="flex flex-col items-center gap-4 rounded-xl border-4 border-black bg-grayish px-6 pb-6 pt-4 shadow-lg sm:mx-8 sm:px-12 sm:pb-12 sm:pt-8 md:w-full"> <div class="flex flex-col items-center gap-4 rounded-xl border-4 border-black bg-grayish px-6 pb-6 pt-4 shadow-lg sm:mx-8 sm:px-12 sm:pb-12 sm:pt-8 md:w-full">
<div class="flex w-full justify-between"> <div class="flex w-full justify-between">
<A <a
id="back" id="back"
class="self-start rounded-lg border-b-4 border-shield-gray bg-voidDark px-8 text-2xl text-grayish duration-100 active:border-b-0 active:border-t-4 sm:rounded-xl sm:px-14 sm:py-1 sm:text-5xl" class="self-start rounded-lg border-b-4 border-shield-gray bg-voidDark px-8 text-2xl text-grayish duration-100 active:border-b-0 active:border-t-4 sm:rounded-xl sm:px-14 sm:py-1 sm:text-5xl"
href="/" href="/"
> >
<FontAwesomeIcon icon={faLeftLong} /> <FontAwesomeIcon icon={faLeftLong} />
</A> </a>
<Show when={!session()?.user?.id}> <Show when={!session()?.user?.id}>
<A <a
id="login" id="login"
class="self-start rounded-lg border-b-4 border-orange-500 bg-yellow-500 px-4 text-2xl active:border-b-0 active:border-t-4 sm:rounded-xl sm:px-9 sm:py-2 sm:text-4xl" class="self-start rounded-lg border-b-4 border-orange-500 bg-yellow-500 px-4 text-2xl active:border-b-0 active:border-t-4 sm:rounded-xl sm:px-9 sm:py-2 sm:text-4xl"
href="/signin" href="/signin"
> >
Login Login
</A> </a>
</Show> </Show>
</div> </div>
<div class="flex flex-col items-center gap-6 sm:gap-12"> <div class="flex flex-col items-center gap-6 sm:gap-12">
@ -214,5 +185,6 @@ export default function Start() {
</div> </div>
</div> </div>
</div> </div>
</SessionProvider>
) )
} }

View file

@ -1,5 +1,4 @@
import AzureADProvider from "@auth/core/providers/azure-ad" import Discord from "@auth/core/providers/discord"
import EmailProvider from "@auth/core/providers/email"
import { DrizzleAdapter } from "@auth/drizzle-adapter" import { DrizzleAdapter } from "@auth/drizzle-adapter"
import { type SolidAuthConfig } from "@auth/solid-start" import { type SolidAuthConfig } from "@auth/solid-start"
import { import {
@ -20,19 +19,14 @@ const customConfig: Config = {
export const authOptions: SolidAuthConfig = { export const authOptions: SolidAuthConfig = {
providers: [ providers: [
// @ts-expect-error Types are wrong // @ts-ignore
EmailProvider({ Discord({
server: process.env.EMAIL_SERVER, clientId: import.meta.env.VITE_DISCORD_CLIENT_ID,
from: process.env.EMAIL_FROM, clientSecret: import.meta.env.VITE_DISCORD_CLIENT_SECRET,
}),
AzureADProvider({
clientId: process.env.AZURE_AD_CLIENT_ID ?? "",
clientSecret: process.env.AZURE_AD_CLIENT_SECRET ?? "",
tenantId: process.env.AZURE_AD_TENANT_ID,
}), }),
], ],
adapter: DrizzleAdapter(db), adapter: DrizzleAdapter(db),
secret: process.env.AUTH_SECRET, secret: import.meta.env.VITE_AUTH_SECRET,
callbacks: { callbacks: {
signIn: ({ user, account }) => { signIn: ({ user, account }) => {
// Custom signIn callback to add username to email provider // Custom signIn callback to add username to email provider
@ -43,6 +37,7 @@ export const authOptions: SolidAuthConfig = {
}, },
session: ({ session, user }) => { session: ({ session, user }) => {
if (session?.user) { if (session?.user) {
// @ts-ignore
session.user.id = user.id session.user.id = user.id
} }
return session return session

16
leaky-ships/src/types/env.d.ts vendored Normal file
View file

@ -0,0 +1,16 @@
/// <reference types="vinxi/client" />
interface ImportMetaEnv {
readonly VITE_DISCORD_CLIENT_ID: string
readonly VITE_DISCORD_CLIENT_SECRET: string
readonly VITE_AUTH_SECRET: string
readonly VITE_AUTH_URL: string | undefined
readonly VITE_DATABASE_URL: string
}
// eslint-disable-next-line no-unused-vars
interface ImportMeta {
readonly env: ImportMetaEnv
}

View file

@ -1,3 +0,0 @@
{
"include": [".eslintrc.cjs"]
}

View file

@ -1,15 +1,17 @@
{ {
"compilerOptions": { "compilerOptions": {
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"target": "ESNext", "target": "ESNext",
"module": "ESNext", "module": "ESNext",
"moduleResolution": "node", "moduleResolution": "node",
"jsxImportSource": "solid-js", "allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"jsx": "preserve", "jsx": "preserve",
"jsxImportSource": "solid-js",
"allowJs": true,
"strict": true, "strict": true,
"types": ["solid-start/env"], "noEmit": true,
"baseUrl": "./", "types": ["vinxi/client"],
"isolatedModules": true,
"paths": { "paths": {
"~/*": ["./src/*"] "~/*": ["./src/*"]
} }

View file

@ -1,10 +1,3 @@
import solid from "solid-start/vite" import { defineConfig } from "@solidjs/start/config"
import { defineConfig } from "vite"
export default defineConfig({ export default defineConfig({})
plugins: [solid({ ssr: false })],
server: {
host: "0.0.0.0",
strictPort: true,
},
})