From dae00716ecb3f87263e531ff559f980c5561543e Mon Sep 17 00:00:00 2001 From: Blake Matthes Date: Wed, 19 Feb 2025 14:07:51 -0600 Subject: [PATCH] refactor(lst): refactor to monolithic completed --- apps/frontend/src/lib/store/sessionStore.ts | 20 -- apps/ocme/index.ts | 14 -- apps/ocme/package.json | 13 -- apps/ocme/src/app.ts | 27 --- apps/server/tsconfig.json | 7 - {apps/frontend => frontend}/.gitignore | 0 {apps/frontend => frontend}/README.md | 0 {apps/frontend => frontend}/components.json | 0 {apps/frontend => frontend}/eslint.config.js | 0 {apps/frontend => frontend}/index.html | 0 {apps/frontend => frontend}/package.json | 0 {apps/frontend => frontend}/public/vite.svg | 0 {apps/frontend => frontend}/src/App.tsx | 9 +- .../src/assets/react.svg | 0 .../src/components/LoginForm.tsx | 14 +- .../src/components/providers/Providers.tsx | 0 .../src/components/ui/button.tsx | 0 frontend/src/lib/hooks/useLogout.ts | 12 ++ .../src/lib/hooks/useSession.ts | 22 ++- frontend/src/lib/store/sessionStore.ts | 36 ++++ {apps/frontend => frontend}/src/lib/utils.ts | 0 {apps/frontend => frontend}/src/main.tsx | 0 {apps/frontend => frontend}/src/styles.css | 0 {apps/frontend => frontend}/src/vite-env.d.ts | 0 {apps/frontend => frontend}/tsconfig.app.json | 0 {apps/frontend => frontend}/tsconfig.json | 0 .../frontend => frontend}/tsconfig.node.json | 0 {apps/frontend => frontend}/vite.config.ts | 2 +- lerna.json | 9 - nx.json | 1 - package.json | 56 ++---- packages/lst-auth/.gitignore | 175 ------------------ packages/lst-auth/README.md | 15 -- packages/lst-auth/index.ts | 99 ---------- packages/lst-auth/package.json | 18 -- packages/lst-auth/routes/login.ts | 45 ----- packages/lst-auth/test/test.ts | 10 - packages/lst-auth/tsconfig.json | 27 --- packages/shared/package.json | 18 -- packages/shared/src/index.ts | 5 - packages/shared/src/utils/createPassword.ts | 0 packages/shared/tsconfig.json | 9 - packages/ui/package.json | 18 -- {packages => server}/database/.gitignore | 0 {packages => server}/database/README.md | 0 .../database/drizzle.config.ts | 0 .../drizzle/0000_stormy_thunderbolt.sql | 0 .../database/drizzle/meta/0000_snapshot.json | 0 .../database/drizzle/meta/_journal.json | 0 {packages => server}/database/index.ts | 0 {packages => server}/database/package.json | 0 {packages => server}/database/schema/users.ts | 0 {packages => server}/database/tsconfig.json | 0 {apps/server => server}/index.ts | 8 +- {apps/server => server}/package.json | 2 +- {apps/server => server}/src/app.ts | 15 +- {apps/server => server}/src/route/apiDoc.ts | 0 {apps/server => server}/src/route/scalar.ts | 0 .../src/services/auth/authService.ts | 0 server/src/services/auth/controllers/login.ts | 25 +++ .../src/services/auth/controllers/logout.ts | 8 + .../src/services/auth/controllers/register.ts | 0 .../services/auth/controllers/verifyToken.ts | 13 ++ .../src/services/auth/lib/createPassword.ts | 0 .../auth/middleware/authMiddleware.ts | 41 ++++ .../src/services/auth/routes/login.ts | 6 +- .../src/services/auth/routes/register.ts | 0 .../src/services/auth/routes/session.ts | 8 +- .../src/services/ocme/ocmeServer.ts | 0 {apps/ocme => server}/tsconfig.json | 0 tsconfig.json | 42 ++--- 71 files changed, 225 insertions(+), 624 deletions(-) delete mode 100644 apps/frontend/src/lib/store/sessionStore.ts delete mode 100644 apps/ocme/index.ts delete mode 100644 apps/ocme/package.json delete mode 100644 apps/ocme/src/app.ts delete mode 100644 apps/server/tsconfig.json rename {apps/frontend => frontend}/.gitignore (100%) rename {apps/frontend => frontend}/README.md (100%) rename {apps/frontend => frontend}/components.json (100%) rename {apps/frontend => frontend}/eslint.config.js (100%) rename {apps/frontend => frontend}/index.html (100%) rename {apps/frontend => frontend}/package.json (100%) rename {apps/frontend => frontend}/public/vite.svg (100%) rename {apps/frontend => frontend}/src/App.tsx (57%) rename {apps/frontend => frontend}/src/assets/react.svg (100%) rename {apps/frontend => frontend}/src/components/LoginForm.tsx (85%) rename {apps/frontend => frontend}/src/components/providers/Providers.tsx (100%) rename {apps/frontend => frontend}/src/components/ui/button.tsx (100%) create mode 100644 frontend/src/lib/hooks/useLogout.ts rename {apps/frontend => frontend}/src/lib/hooks/useSession.ts (51%) create mode 100644 frontend/src/lib/store/sessionStore.ts rename {apps/frontend => frontend}/src/lib/utils.ts (100%) rename {apps/frontend => frontend}/src/main.tsx (100%) rename {apps/frontend => frontend}/src/styles.css (100%) rename {apps/frontend => frontend}/src/vite-env.d.ts (100%) rename {apps/frontend => frontend}/tsconfig.app.json (100%) rename {apps/frontend => frontend}/tsconfig.json (100%) rename {apps/frontend => frontend}/tsconfig.node.json (100%) rename {apps/frontend => frontend}/vite.config.ts (89%) delete mode 100644 lerna.json delete mode 100644 nx.json delete mode 100644 packages/lst-auth/.gitignore delete mode 100644 packages/lst-auth/README.md delete mode 100644 packages/lst-auth/index.ts delete mode 100644 packages/lst-auth/package.json delete mode 100644 packages/lst-auth/routes/login.ts delete mode 100644 packages/lst-auth/test/test.ts delete mode 100644 packages/lst-auth/tsconfig.json delete mode 100644 packages/shared/package.json delete mode 100644 packages/shared/src/index.ts delete mode 100644 packages/shared/src/utils/createPassword.ts delete mode 100644 packages/shared/tsconfig.json delete mode 100644 packages/ui/package.json rename {packages => server}/database/.gitignore (100%) rename {packages => server}/database/README.md (100%) rename {packages => server}/database/drizzle.config.ts (100%) rename {packages => server}/database/drizzle/0000_stormy_thunderbolt.sql (100%) rename {packages => server}/database/drizzle/meta/0000_snapshot.json (100%) rename {packages => server}/database/drizzle/meta/_journal.json (100%) rename {packages => server}/database/index.ts (100%) rename {packages => server}/database/package.json (100%) rename {packages => server}/database/schema/users.ts (100%) rename {packages => server}/database/tsconfig.json (100%) rename {apps/server => server}/index.ts (66%) rename {apps/server => server}/package.json (83%) rename {apps/server => server}/src/app.ts (76%) rename {apps/server => server}/src/route/apiDoc.ts (100%) rename {apps/server => server}/src/route/scalar.ts (100%) rename {apps/server => server}/src/services/auth/authService.ts (100%) create mode 100644 server/src/services/auth/controllers/login.ts create mode 100644 server/src/services/auth/controllers/logout.ts rename {apps/server => server}/src/services/auth/controllers/register.ts (100%) create mode 100644 server/src/services/auth/controllers/verifyToken.ts rename {apps/server => server}/src/services/auth/lib/createPassword.ts (100%) create mode 100644 server/src/services/auth/middleware/authMiddleware.ts rename {apps/server => server}/src/services/auth/routes/login.ts (93%) rename {apps/server => server}/src/services/auth/routes/register.ts (100%) rename {apps/server => server}/src/services/auth/routes/session.ts (81%) rename {apps/server => server}/src/services/ocme/ocmeServer.ts (100%) rename {apps/ocme => server}/tsconfig.json (100%) diff --git a/apps/frontend/src/lib/store/sessionStore.ts b/apps/frontend/src/lib/store/sessionStore.ts deleted file mode 100644 index b4fe2ed..0000000 --- a/apps/frontend/src/lib/store/sessionStore.ts +++ /dev/null @@ -1,20 +0,0 @@ -import {create} from "zustand"; - -type User = { - id: number; - username: string; -}; - -type SessionState = { - user: User | null; - token: string | null; - setSession: (user: SessionState["user"], token: string) => void; - clearSession: () => void; -}; - -export const useSessionStore = create((set) => ({ - user: null, - token: null, - setSession: (user, token) => set({user, token}), - clearSession: () => set({user: null}), -})); diff --git a/apps/ocme/index.ts b/apps/ocme/index.ts deleted file mode 100644 index 5c030ea..0000000 --- a/apps/ocme/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import app from "./src/app"; -const port = process.env.OCME_PORT || 5001; //bun will automatically grab this as well. -Bun.serve({ - port, - fetch: app.fetch, - hostname: "0.0.0.0", -}); - -await Bun.build({ - entrypoints: ["./index.js"], - outdir: "../../dist/ocme", -}); - -console.log(`ocme is running on port ${port}`); diff --git a/apps/ocme/package.json b/apps/ocme/package.json deleted file mode 100644 index 96fb95e..0000000 --- a/apps/ocme/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "lstv2-ocme", - "version": "1.0.0", - "description": "", - "private": true, - "scripts": { - "dev": "bun --watch index.ts", - "build": "bun build ./index.ts" - }, - "devDependencies": { - "typescript": "^5.7.3" - } -} diff --git a/apps/ocme/src/app.ts b/apps/ocme/src/app.ts deleted file mode 100644 index 0b27d08..0000000 --- a/apps/ocme/src/app.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { funnyFunction } from "@shared/lib"; -import { Hono } from "hono"; -import { serveStatic } from "hono/bun"; -import { logger } from "hono/logger"; -//import { expensesRoute } from "./routes/expenses"; - -const app = new Hono(); - -app.use("*", logger()); - -// running the hi function -funnyFunction(); -app.get("/", (c) => { - return c.json({ success: true, message: "hello from bun on the ocmeserver" }); -}); - -app.get("/api", (c) => { - return c.json({ success: true, message: "first api for ocme" }); -}); -//const apiRoute = app.basePath("/api").route("/expenses", expensesRoute); - -app.get("*", serveStatic({ root: "./frontend/dist" })); -app.get("*", serveStatic({ path: "./frontend/dist/index.html" })); - -export default app; - -//export type ApiRoute = typeof apiRoute; diff --git a/apps/server/tsconfig.json b/apps/server/tsconfig.json deleted file mode 100644 index b925aba..0000000 --- a/apps/server/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "outDir": "dist" - }, - "include": ["src", "index.ts"] -} diff --git a/apps/frontend/.gitignore b/frontend/.gitignore similarity index 100% rename from apps/frontend/.gitignore rename to frontend/.gitignore diff --git a/apps/frontend/README.md b/frontend/README.md similarity index 100% rename from apps/frontend/README.md rename to frontend/README.md diff --git a/apps/frontend/components.json b/frontend/components.json similarity index 100% rename from apps/frontend/components.json rename to frontend/components.json diff --git a/apps/frontend/eslint.config.js b/frontend/eslint.config.js similarity index 100% rename from apps/frontend/eslint.config.js rename to frontend/eslint.config.js diff --git a/apps/frontend/index.html b/frontend/index.html similarity index 100% rename from apps/frontend/index.html rename to frontend/index.html diff --git a/apps/frontend/package.json b/frontend/package.json similarity index 100% rename from apps/frontend/package.json rename to frontend/package.json diff --git a/apps/frontend/public/vite.svg b/frontend/public/vite.svg similarity index 100% rename from apps/frontend/public/vite.svg rename to frontend/public/vite.svg diff --git a/apps/frontend/src/App.tsx b/frontend/src/App.tsx similarity index 57% rename from apps/frontend/src/App.tsx rename to frontend/src/App.tsx index cac92da..2f75eac 100644 --- a/apps/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,9 +1,12 @@ import LoginForm from "./components/LoginForm"; +import {Button} from "./components/ui/button"; import {useSession} from "./lib/hooks/useSession"; +import {useLogout} from "./lib/hooks/useLogout"; import "./styles.css"; function App() { const {session, status} = useSession(); + const logout = useLogout(); if (!session || status === "error") { return ( @@ -15,8 +18,12 @@ function App() { return ( <> -

Logged in user: {session.user.username}

+ {/*

Logged in user: {session.user.username}

*/} + <>Session: {JSON.stringify(session)}

Status: {JSON.stringify(status)}

+

+ +

); } diff --git a/apps/frontend/src/assets/react.svg b/frontend/src/assets/react.svg similarity index 100% rename from apps/frontend/src/assets/react.svg rename to frontend/src/assets/react.svg diff --git a/apps/frontend/src/components/LoginForm.tsx b/frontend/src/components/LoginForm.tsx similarity index 85% rename from apps/frontend/src/components/LoginForm.tsx rename to frontend/src/components/LoginForm.tsx index bb37bb1..079168c 100644 --- a/apps/frontend/src/components/LoginForm.tsx +++ b/frontend/src/components/LoginForm.tsx @@ -11,7 +11,7 @@ const LoginForm = () => { const handleLogin = async (e: React.FormEvent) => { e.preventDefault(); - console.log("Form data", {username, password}); + // console.log("Form data", {username, password}); try { const response = await fetch("/api/auth/login", { method: "POST", @@ -21,15 +21,19 @@ const LoginForm = () => { body: JSON.stringify({username, password}), }); - console.log("Response", response); - // if (!response.ok) { // throw new Error("Invalid credentials"); // } const data = await response.json(); - console.log("Response", data); - setSession(data.user, data.token); + console.log("Response", data.data); + // Store token in localStorage + localStorage.setItem("auth_token", data.data.token); + + // Optionally store user info + // localStorage.setItem("user", JSON.stringify(user)); + + setSession(data.data.token); // Refetch the session data to reflect the logged-in state queryClient.invalidateQueries(["session"]); diff --git a/apps/frontend/src/components/providers/Providers.tsx b/frontend/src/components/providers/Providers.tsx similarity index 100% rename from apps/frontend/src/components/providers/Providers.tsx rename to frontend/src/components/providers/Providers.tsx diff --git a/apps/frontend/src/components/ui/button.tsx b/frontend/src/components/ui/button.tsx similarity index 100% rename from apps/frontend/src/components/ui/button.tsx rename to frontend/src/components/ui/button.tsx diff --git a/frontend/src/lib/hooks/useLogout.ts b/frontend/src/lib/hooks/useLogout.ts new file mode 100644 index 0000000..937c512 --- /dev/null +++ b/frontend/src/lib/hooks/useLogout.ts @@ -0,0 +1,12 @@ +import {useSessionStore} from "../store/sessionStore"; + +export const useLogout = () => { + const clearSession = useSessionStore((state) => state.clearSession); + + const logout = () => { + clearSession(); // Clears Zustand state + return "Logged out"; + }; + + return logout; +}; diff --git a/apps/frontend/src/lib/hooks/useSession.ts b/frontend/src/lib/hooks/useSession.ts similarity index 51% rename from apps/frontend/src/lib/hooks/useSession.ts rename to frontend/src/lib/hooks/useSession.ts index cc16ce5..6cd8f8f 100644 --- a/apps/frontend/src/lib/hooks/useSession.ts +++ b/frontend/src/lib/hooks/useSession.ts @@ -3,8 +3,19 @@ import {useSessionStore} from "../store/sessionStore"; import {useEffect} from "react"; const fetchSession = async () => { - const res = await fetch("/api/auth/session", {credentials: "include"}); + const token = localStorage.getItem("auth_token"); + if (!token) { + throw new Error("No token found"); + } + + const res = await fetch("/api/auth/session", { + headers: { + "Content-Type": "application/json", + Authorization: `Bearer ${token}`, + }, + }); + console.log(res); if (!res.ok) { throw new Error("Session not found"); } @@ -13,10 +24,13 @@ const fetchSession = async () => { }; export const useSession = () => { - const {setSession, clearSession} = useSessionStore(); + const {setSession, clearSession, token} = useSessionStore(); + + // Fetch session only if token is available const {data, status, error} = useQuery({ queryKey: ["session"], queryFn: fetchSession, + enabled: !!token, // Prevents query if token is null staleTime: 5 * 60 * 1000, // 5 mins gcTime: 10 * 60 * 1000, // 10 mins refetchOnWindowFocus: true, @@ -24,12 +38,12 @@ export const useSession = () => { useEffect(() => { if (data) { - setSession(data.user, data.token); + setSession(data.token); } if (error) { clearSession(); } }, [data, error]); - return {session: data, status, error}; + return {session: data && token ? {user: data.user, token: data.token} : null, status, error}; }; diff --git a/frontend/src/lib/store/sessionStore.ts b/frontend/src/lib/store/sessionStore.ts new file mode 100644 index 0000000..0683931 --- /dev/null +++ b/frontend/src/lib/store/sessionStore.ts @@ -0,0 +1,36 @@ +import {create} from "zustand"; + +// type User = { +// id: number; +// username: string; +// }; + +type SessionState = { + //user: User | null; + token: string | null; + setSession: (token: string) => void; + clearSession: () => void; +}; + +export const useSessionStore = create((set) => { + // Initialize from localStorage + //const storedUser = localStorage.getItem("user"); + const storedToken = localStorage.getItem("auth_token"); + + return { + //user: storedUser ? JSON.parse(storedUser) : null, + token: storedToken || null, + + setSession: (token) => { + localStorage.setItem("auth_token", token); + //localStorage.setItem("user", JSON.stringify(user)); + set({token}); + }, + + clearSession: () => { + localStorage.removeItem("auth_token"); + //localStorage.removeItem("user"); + set({token: null}); + }, + }; +}); diff --git a/apps/frontend/src/lib/utils.ts b/frontend/src/lib/utils.ts similarity index 100% rename from apps/frontend/src/lib/utils.ts rename to frontend/src/lib/utils.ts diff --git a/apps/frontend/src/main.tsx b/frontend/src/main.tsx similarity index 100% rename from apps/frontend/src/main.tsx rename to frontend/src/main.tsx diff --git a/apps/frontend/src/styles.css b/frontend/src/styles.css similarity index 100% rename from apps/frontend/src/styles.css rename to frontend/src/styles.css diff --git a/apps/frontend/src/vite-env.d.ts b/frontend/src/vite-env.d.ts similarity index 100% rename from apps/frontend/src/vite-env.d.ts rename to frontend/src/vite-env.d.ts diff --git a/apps/frontend/tsconfig.app.json b/frontend/tsconfig.app.json similarity index 100% rename from apps/frontend/tsconfig.app.json rename to frontend/tsconfig.app.json diff --git a/apps/frontend/tsconfig.json b/frontend/tsconfig.json similarity index 100% rename from apps/frontend/tsconfig.json rename to frontend/tsconfig.json diff --git a/apps/frontend/tsconfig.node.json b/frontend/tsconfig.node.json similarity index 100% rename from apps/frontend/tsconfig.node.json rename to frontend/tsconfig.node.json diff --git a/apps/frontend/vite.config.ts b/frontend/vite.config.ts similarity index 89% rename from apps/frontend/vite.config.ts rename to frontend/vite.config.ts index 8ac556f..03c513b 100644 --- a/apps/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -17,7 +17,7 @@ export default defineConfig({ }, server: { proxy: { - "/api": {target: "http://localhost:4000", changeOrigin: true}, + "/api": {target: "http://localhost:3000", changeOrigin: true}, }, }, }); diff --git a/lerna.json b/lerna.json deleted file mode 100644 index b2a8784..0000000 --- a/lerna.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "packages": ["apps/*", "packages/*"], - "version": "independent", - "command": { - "publish": { - "conventionalCommits": true - } - } -} diff --git a/nx.json b/nx.json deleted file mode 100644 index 0967ef4..0000000 --- a/nx.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/package.json b/package.json index ad48da8..c379213 100644 --- a/package.json +++ b/package.json @@ -5,76 +5,46 @@ "main": "index.ts", "scripts": { "dev": "dotenvx run -- bun run -r --parallel --aggregate-output dev", - "dev:all": "concurrently -n 'server,ocme,frontend' -c '#007755,#2f6da3,#c61cb8' 'cd apps/server && bun run dev' 'cd apps/ocme && bun run dev' 'cd apps/frontend && bun run dev'", - "dev:server": "bun --watch apps/server/index.ts", - "dev:ocme": "bun --watch apps/ocme/index.ts", - "dev:frontend": "cd apps/frontend && bunx --bun vite", - "build:server": "nx exec -- rimraf dist/server && cd apps/server && bun build index.js --outdir ../../dist/server", - "build:ocme": "nx exec -- rimraf dist/ocme && cd apps/ocme && bun build index.js --outdir ../../dist/ocme", - "build:front": "nx exec -- rimraf dist/frontend && cd apps/frontend && bun run build", - "start": "cd dist/server && bun run ./index.js", + "dev:all": "concurrently -n 'server,frontend' -c '#007755,#2f6da3' 'cd server && bun run dev' 'cd frontend && bun run dev'", + "dev:server": "bun --env-file .env --watch server/index.ts", + "dev:ocme": "bun --env-file .env --watch ocme/index.ts", + "dev:frontend": "cd frontend && bunx --bun vite", + "build:server": "cd apps/server && bun build index.js --outdir ../../dist/server", + "build:ocme": "rimraf dist/ocme && cd apps/ocme && bun build index.js --outdir ../../dist/ocme", + "build:front": "cd frontend && rimraf frontend/dist && bun run build", + "start": "bun --env-file .env run ./server/index.js", "commit": "cz", - "clean": "rimraf dist/server" + "clean": "rimraf dist/server", + "deploy": "standard-version --conventional-commits" }, - "workspaces": [ - "apps/*", - "packages/*" - ], "keywords": [], "author": "", "license": "ISC", "dependencies": { - "@auth/core": "^0.37.4", "@dotenvx/dotenvx": "^1.35.0", "@hono/zod-openapi": "^0.18.4", - "@shared/lib": "*", + "@scalar/hono-api-reference": "^0.5.174", "@types/bun": "^1.2.2", "axios": "^1.7.9", "bcrypt": "^5.1.1", "compression": "^1.8.0", - "concurrently": "^9.1.2", "cookie": "^1.0.2", "date-fns": "^4.1.0", - "dotenv": "^16.4.7", - "dotenv-expand": "^12.0.1", "hono": "^4.7.1", "http-proxy-middleware": "^3.0.3", "jsonwebtoken": "^9.0.2", - "lst-auth": "*", "zod": "^3.24.2" }, - "peerDependencies": { - "typescript": "^5.0.0" - }, "devDependencies": { "cz-conventional-changelog": "^3.3.0", - "nx": "^20.4.4", "rimraf": "^6.0.1", "standard-version": "^9.5.0", - "typescript": "~5.7.3" + "typescript": "~5.7.3", + "concurrently": "^9.1.2" }, "config": { "commitizen": { "path": "./node_modules/cz-conventional-changelog" } - }, - "nx": { - "targets": { - "build": { - "cache": true, - "inputs": [ - "{projectRoot}/**/*.ts", - "{projectRoot}/tsconfig.json", - { - "externalDependencies": [ - "typescript" - ] - } - ], - "outputs": [ - "{projectRoot}/dist" - ] - } - } } } diff --git a/packages/lst-auth/.gitignore b/packages/lst-auth/.gitignore deleted file mode 100644 index 9b1ee42..0000000 --- a/packages/lst-auth/.gitignore +++ /dev/null @@ -1,175 +0,0 @@ -# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore - -# Logs - -logs -_.log -npm-debug.log_ -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* - -# Caches - -.cache - -# Diagnostic reports (https://nodejs.org/api/report.html) - -report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json - -# Runtime data - -pids -_.pid -_.seed -*.pid.lock - -# Directory for instrumented libs generated by jscoverage/JSCover - -lib-cov - -# Coverage directory used by tools like istanbul - -coverage -*.lcov - -# nyc test coverage - -.nyc_output - -# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) - -.grunt - -# Bower dependency directory (https://bower.io/) - -bower_components - -# node-waf configuration - -.lock-wscript - -# Compiled binary addons (https://nodejs.org/api/addons.html) - -build/Release - -# Dependency directories - -node_modules/ -jspm_packages/ - -# Snowpack dependency directory (https://snowpack.dev/) - -web_modules/ - -# TypeScript cache - -*.tsbuildinfo - -# Optional npm cache directory - -.npm - -# Optional eslint cache - -.eslintcache - -# Optional stylelint cache - -.stylelintcache - -# Microbundle cache - -.rpt2_cache/ -.rts2_cache_cjs/ -.rts2_cache_es/ -.rts2_cache_umd/ - -# Optional REPL history - -.node_repl_history - -# Output of 'npm pack' - -*.tgz - -# Yarn Integrity file - -.yarn-integrity - -# dotenv environment variable files - -.env -.env.development.local -.env.test.local -.env.production.local -.env.local - -# parcel-bundler cache (https://parceljs.org/) - -.parcel-cache - -# Next.js build output - -.next -out - -# Nuxt.js build / generate output - -.nuxt -dist - -# Gatsby files - -# Comment in the public line in if your project uses Gatsby and not Next.js - -# https://nextjs.org/blog/next-9-1#public-directory-support - -# public - -# vuepress build output - -.vuepress/dist - -# vuepress v2.x temp and cache directory - -.temp - -# Docusaurus cache and generated files - -.docusaurus - -# Serverless directories - -.serverless/ - -# FuseBox cache - -.fusebox/ - -# DynamoDB Local files - -.dynamodb/ - -# TernJS port file - -.tern-port - -# Stores VSCode versions used for testing VSCode extensions - -.vscode-test - -# yarn v2 - -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* - -# IntelliJ based IDEs -.idea - -# Finder (MacOS) folder config -.DS_Store diff --git a/packages/lst-auth/README.md b/packages/lst-auth/README.md deleted file mode 100644 index 6b584ea..0000000 --- a/packages/lst-auth/README.md +++ /dev/null @@ -1,15 +0,0 @@ -# lst-auth - -To install dependencies: - -```bash -bun install -``` - -To run: - -```bash -bun run index.ts -``` - -This project was created using `bun init` in bun v1.2.2. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime. diff --git a/packages/lst-auth/index.ts b/packages/lst-auth/index.ts deleted file mode 100644 index e45a35e..0000000 --- a/packages/lst-auth/index.ts +++ /dev/null @@ -1,99 +0,0 @@ -import {Hono, type MiddlewareHandler} from "hono"; -import {basicAuth} from "hono/basic-auth"; - -import {sign, verify} from "jsonwebtoken"; - -const JWT_SECRET = "your-secret-key"; -const EXPIRATION_TIME = "1h"; // Token expires in 1 minute -const REFRESH_THRESHOLD = 30; // Refresh token if it has less than 30 seconds left -const ACCESS_EXPIRATION = "1h"; // 1 minute for access tokens -const REFRESH_EXPIRATION = "7d"; // 7 days for refresh tokens - -const fakeUsers = [ - {id: 1, username: "admin", password: "password123"}, - {id: 2, username: "user", password: "password123"}, - {id: 3, username: "user2", password: "password123"}, -]; -// Hardcoded user credentials (for demonstration purposes) -const users = [{username: "admin", password: "password123"}]; - -// Middleware to check authentication -export const lstVerifyAuth = basicAuth({ - verifyUser: (username, password) => { - const user = users.find((u) => u.username === username && u.password === password); - return !!user; // Return true if user exists, otherwise false - }, -}); - -/** - * Authenticate a user and return a JWT. - */ - -export function login(username: string, password: string): {token: string; user: {id: number; username: string}} { - const user = fakeUsers.find((u) => u.username === username && u.password === password); - if (!user) { - throw new Error("Invalid credentials"); - } - - // Create a JWT - const token = sign({userId: user?.id, username: user?.username}, JWT_SECRET, {expiresIn: EXPIRATION_TIME}); - - return {token, user: {id: user?.id, username: user.username}}; -} - -/** - * Verify a JWT and return the decoded payload. - */ -export function verifyToken(token: string): {userId: number} { - try { - const payload = verify(token, JWT_SECRET) as {userId: number}; - return payload; - } catch (err) { - throw new Error("Invalid token"); - } -} - -export const authMiddleware: MiddlewareHandler = async (c, next) => { - const authHeader = c.req.header("Authorization"); - - if (!authHeader || !authHeader.startsWith("Bearer ")) { - return c.json({error: "Unauthorized"}, 401); - } - - const token = authHeader.split(" ")[1]; - - try { - const decoded = verify(token, JWT_SECRET, {ignoreExpiration: false}) as {userId: number; exp: number}; - - const currentTime = Math.floor(Date.now() / 1000); // Get current timestamp - const timeLeft = decoded.exp - currentTime; - - // If the token has less than REFRESH_THRESHOLD seconds left, refresh it - let newToken = null; - - if (timeLeft < REFRESH_THRESHOLD) { - newToken = sign({userId: decoded.userId}, JWT_SECRET, {expiresIn: EXPIRATION_TIME}); - c.res.headers.set("Authorization", `Bearer ${newToken}`); - } - - c.set("user", {id: decoded.userId}); - await next(); - - // If a new token was generated, send it in response headers - if (newToken) { - console.log("token was refreshed"); - c.res.headers.set("X-Refreshed-Token", newToken); - } - } catch (err) { - return c.json({error: "Invalid token"}, 401); - } -}; - -/** - * Logout (clear the token). - * This is a placeholder function since JWTs are stateless. - * In a real app, you might want to implement token blacklisting. - */ -export function logout(): {message: string} { - return {message: "Logout successful"}; -} diff --git a/packages/lst-auth/package.json b/packages/lst-auth/package.json deleted file mode 100644 index 856146d..0000000 --- a/packages/lst-auth/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "lst-auth", - "module": "index.ts", - "type": "module", - "private": true, - "devDependencies": { - "@types/bun": "latest", - "@types/jsonwebtoken": "^9.0.8" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "dependencies": { - "cookie": "^1.0.2", - "hono": "^4.7.1", - "jsonwebtoken": "^9.0.2" - } -} diff --git a/packages/lst-auth/routes/login.ts b/packages/lst-auth/routes/login.ts deleted file mode 100644 index fb1edb4..0000000 --- a/packages/lst-auth/routes/login.ts +++ /dev/null @@ -1,45 +0,0 @@ -import {Hono} from "hono"; -import {setCookie, getCookie, deleteCookie} from "hono/cookie"; -import {sign, verify} from "jsonwebtoken"; - -const JWT_SECRET = "your-secret-key"; - -const fakeUsers = [ - {id: 1, username: "admin", password: "password123"}, - {id: 2, username: "user", password: "password123"}, - {id: 3, username: "user2", password: "password123"}, -]; -export const authLogin = new Hono().get("/", async (c) => { - // lets get the username and password to check everything - const {username, password} = await c.req.json(); - let user = null; - // make sure we go a username and password - if (!username || !password) { - return c.json({error: "Username and password required"}, 400); - } - - // check the user exist in our db - if (!fakeUsers.includes(username && password)) { - return c.json({error: "Invalid username or password"}, 400); - } - - user = fakeUsers.find((u) => u.username === username && u.password === password); - - // create the token - - const token = sign({userId: user?.id}, JWT_SECRET, {expiresIn: "1h"}); - - setCookie(c, "auth_token", token, { - httpOnly: true, - secure: process.env.NODE_ENV === "production", - maxAge: 3600, //parseInt(process.env.JWT_EXPIRES_IN) * 60 * 1000 || 3600, // expires in 1 hour is not set in env - path: "/", - sameSite: "strict", - }); - - return c.json({ - success: true, - message: "Login successful", - user: {id: user?.id, username: user?.username, token: token}, - }); -}); diff --git a/packages/lst-auth/test/test.ts b/packages/lst-auth/test/test.ts deleted file mode 100644 index 4766932..0000000 --- a/packages/lst-auth/test/test.ts +++ /dev/null @@ -1,10 +0,0 @@ -import app from "../index"; - -const request = new Request("http://localhost/protected", { - headers: { - Authorization: "Basic " + Buffer.from("admin:password12").toString("base64"), - }, -}); - -const response = await app.fetch(request); -console.log(await response.text()); // Should print "You are authenticated!" diff --git a/packages/lst-auth/tsconfig.json b/packages/lst-auth/tsconfig.json deleted file mode 100644 index 238655f..0000000 --- a/packages/lst-auth/tsconfig.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "compilerOptions": { - // Enable latest features - "lib": ["ESNext", "DOM"], - "target": "ESNext", - "module": "ESNext", - "moduleDetection": "force", - "jsx": "react-jsx", - "allowJs": true, - - // Bundler mode - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "noEmit": true, - - // Best practices - "strict": true, - "skipLibCheck": true, - "noFallthroughCasesInSwitch": true, - - // Some stricter flags (disabled by default) - "noUnusedLocals": false, - "noUnusedParameters": false, - "noPropertyAccessFromIndexSignature": false - } -} diff --git a/packages/shared/package.json b/packages/shared/package.json deleted file mode 100644 index aa79810..0000000 --- a/packages/shared/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "@shared/lib", - "version": "0.0.1", - "main": "src/index.js", - "types": "src/index.d.ts", - "module": "src/index.js", - "type": "module", - "scripts": { - "build": "bun run tsc", - "clean": "rm -rf dist" - }, - "dependencies": { - "bun-types": "latest" - }, - "devDependencies": { - "typescript": "^5.7.3" - } -} diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts deleted file mode 100644 index 5519ff7..0000000 --- a/packages/shared/src/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export function funnyFunction() { - setInterval(() => { - console.log("hi"); - }, 1000); -} diff --git a/packages/shared/src/utils/createPassword.ts b/packages/shared/src/utils/createPassword.ts deleted file mode 100644 index e69de29..0000000 diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json deleted file mode 100644 index 5fca610..0000000 --- a/packages/shared/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "compilerOptions": { - "rootDir": "src", - "outDir": "dist", - "declaration": true - }, - "include": ["src"] -} diff --git a/packages/ui/package.json b/packages/ui/package.json deleted file mode 100644 index c8c6cd2..0000000 --- a/packages/ui/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "@shared/ui", - "version": "0.0.1", - "main": "src/index.js", - "types": "src/index.d.ts", - "module": "src/index.js", - "type": "module", - "scripts": { - "build": "bun run tsc", - "clean": "rm -rf dist" - }, - "dependencies": { - "bun-types": "latest" - }, - "devDependencies": { - "typescript": "^5.7.3" - } -} diff --git a/packages/database/.gitignore b/server/database/.gitignore similarity index 100% rename from packages/database/.gitignore rename to server/database/.gitignore diff --git a/packages/database/README.md b/server/database/README.md similarity index 100% rename from packages/database/README.md rename to server/database/README.md diff --git a/packages/database/drizzle.config.ts b/server/database/drizzle.config.ts similarity index 100% rename from packages/database/drizzle.config.ts rename to server/database/drizzle.config.ts diff --git a/packages/database/drizzle/0000_stormy_thunderbolt.sql b/server/database/drizzle/0000_stormy_thunderbolt.sql similarity index 100% rename from packages/database/drizzle/0000_stormy_thunderbolt.sql rename to server/database/drizzle/0000_stormy_thunderbolt.sql diff --git a/packages/database/drizzle/meta/0000_snapshot.json b/server/database/drizzle/meta/0000_snapshot.json similarity index 100% rename from packages/database/drizzle/meta/0000_snapshot.json rename to server/database/drizzle/meta/0000_snapshot.json diff --git a/packages/database/drizzle/meta/_journal.json b/server/database/drizzle/meta/_journal.json similarity index 100% rename from packages/database/drizzle/meta/_journal.json rename to server/database/drizzle/meta/_journal.json diff --git a/packages/database/index.ts b/server/database/index.ts similarity index 100% rename from packages/database/index.ts rename to server/database/index.ts diff --git a/packages/database/package.json b/server/database/package.json similarity index 100% rename from packages/database/package.json rename to server/database/package.json diff --git a/packages/database/schema/users.ts b/server/database/schema/users.ts similarity index 100% rename from packages/database/schema/users.ts rename to server/database/schema/users.ts diff --git a/packages/database/tsconfig.json b/server/database/tsconfig.json similarity index 100% rename from packages/database/tsconfig.json rename to server/database/tsconfig.json diff --git a/apps/server/index.ts b/server/index.ts similarity index 66% rename from apps/server/index.ts rename to server/index.ts index 0161532..cbcc33c 100644 --- a/apps/server/index.ts +++ b/server/index.ts @@ -6,9 +6,9 @@ Bun.serve({ hostname: "0.0.0.0", }); -await Bun.build({ - entrypoints: ["./index.js"], - outdir: "../../dist/server", -}); +// await Bun.build({ +// entrypoints: ["./index.js"], +// outdir: "../../dist/server", +// }); console.log(`server is running on port ${port}`); diff --git a/apps/server/package.json b/server/package.json similarity index 83% rename from apps/server/package.json rename to server/package.json index 5bfd851..0accc8e 100644 --- a/apps/server/package.json +++ b/server/package.json @@ -4,7 +4,7 @@ "description": "", "private": true, "scripts": { - "dev": "bun --watch ./index.ts", + "dev": "bun --env-file ../.env --watch ./index.ts", "build": "bun build ./index.ts" }, "devDependencies": { diff --git a/apps/server/src/app.ts b/server/src/app.ts similarity index 76% rename from apps/server/src/app.ts rename to server/src/app.ts index bf83f66..51a49c6 100644 --- a/apps/server/src/app.ts +++ b/server/src/app.ts @@ -1,6 +1,6 @@ +process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"; import {serveStatic} from "hono/bun"; import {logger} from "hono/logger"; -import {authMiddleware} from "lst-auth"; import {cors} from "hono/cors"; import {OpenAPIHono} from "@hono/zod-openapi"; @@ -10,13 +10,14 @@ import scalar from "./route/scalar"; // services import {ocmeService} from "./services/ocme/ocmeServer"; +console.log(process.env.JWT_SECRET); const app = new OpenAPIHono(); app.use("*", logger()); app.use( "*", cors({ - origin: "http://localhost:5173", + origin: `http://localhost:5173`, allowHeaders: ["X-Custom-Header", "Upgrade-Insecure-Requests"], allowMethods: ["POST", "GET", "OPTIONS"], exposeHeaders: ["Content-Length", "X-Kuma-Revision"], @@ -47,12 +48,12 @@ routes.forEach((route) => { //app.basePath("/api/auth").route("/login", login).route("/session", session).route("/register", register); //auth stuff -app.get("/api/protected", authMiddleware, (c) => { - return c.json({success: true, message: "is authenticated"}); -}); +// app.get("/api/protected", authMiddleware, (c) => { +// return c.json({success: true, message: "is authenticated"}); +// }); -app.get("*", serveStatic({root: "../frontend/dist"})); -app.get("*", serveStatic({path: "../frontend/dist/index.html"})); +app.get("*", serveStatic({root: "./frontend/dist"})); +app.get("*", serveStatic({path: "./frontend/dist/index.html"})); export default app; diff --git a/apps/server/src/route/apiDoc.ts b/server/src/route/apiDoc.ts similarity index 100% rename from apps/server/src/route/apiDoc.ts rename to server/src/route/apiDoc.ts diff --git a/apps/server/src/route/scalar.ts b/server/src/route/scalar.ts similarity index 100% rename from apps/server/src/route/scalar.ts rename to server/src/route/scalar.ts diff --git a/apps/server/src/services/auth/authService.ts b/server/src/services/auth/authService.ts similarity index 100% rename from apps/server/src/services/auth/authService.ts rename to server/src/services/auth/authService.ts diff --git a/server/src/services/auth/controllers/login.ts b/server/src/services/auth/controllers/login.ts new file mode 100644 index 0000000..cd594a6 --- /dev/null +++ b/server/src/services/auth/controllers/login.ts @@ -0,0 +1,25 @@ +import {sign, verify} from "jsonwebtoken"; + +/** + * Authenticate a user and return a JWT. + */ + +const fakeUsers = [ + {id: 1, username: "admin", password: "password123"}, + {id: 2, username: "user", password: "password123"}, + {id: 3, username: "user2", password: "password123"}, +]; + +export function login(username: string, password: string): {token: string; user: {id: number; username: string}} { + const user = fakeUsers.find((u) => u.username === username && u.password === password); + if (!user) { + throw new Error("Invalid credentials"); + } + + // Create a JWT + const token = sign({userId: user?.id, username: user?.username}, process.env.JWT_SECRET, { + expiresIn: process.env.JWT_EXPIRES, + }); + + return {token, user: {id: user?.id, username: user.username}}; +} diff --git a/server/src/services/auth/controllers/logout.ts b/server/src/services/auth/controllers/logout.ts new file mode 100644 index 0000000..dda67b3 --- /dev/null +++ b/server/src/services/auth/controllers/logout.ts @@ -0,0 +1,8 @@ +/** + * Logout (clear the token). + * This is a placeholder function since JWTs are stateless. + * In a real app, you might want to implement token blacklisting. + */ +export function logout(): {message: string} { + return {message: "Logout successful"}; +} diff --git a/apps/server/src/services/auth/controllers/register.ts b/server/src/services/auth/controllers/register.ts similarity index 100% rename from apps/server/src/services/auth/controllers/register.ts rename to server/src/services/auth/controllers/register.ts diff --git a/server/src/services/auth/controllers/verifyToken.ts b/server/src/services/auth/controllers/verifyToken.ts new file mode 100644 index 0000000..50a278d --- /dev/null +++ b/server/src/services/auth/controllers/verifyToken.ts @@ -0,0 +1,13 @@ +import {sign, verify} from "jsonwebtoken"; + +/** + * Verify a JWT and return the decoded payload. + */ +export function verifyToken(token: string): {userId: number} { + try { + const payload = verify(token, process.env.JWT_SECRET) as {userId: number}; + return payload; + } catch (err) { + throw new Error("Invalid token"); + } +} diff --git a/apps/server/src/services/auth/lib/createPassword.ts b/server/src/services/auth/lib/createPassword.ts similarity index 100% rename from apps/server/src/services/auth/lib/createPassword.ts rename to server/src/services/auth/lib/createPassword.ts diff --git a/server/src/services/auth/middleware/authMiddleware.ts b/server/src/services/auth/middleware/authMiddleware.ts new file mode 100644 index 0000000..40edb29 --- /dev/null +++ b/server/src/services/auth/middleware/authMiddleware.ts @@ -0,0 +1,41 @@ +import {type MiddlewareHandler} from "hono"; +import {sign, verify} from "jsonwebtoken"; + +export const authMiddleware: MiddlewareHandler = async (c, next) => { + const authHeader = c.req.header("Authorization"); + + if (!authHeader || !authHeader.startsWith("Bearer ")) { + return c.json({error: "Unauthorized"}, 401); + } + + const token = authHeader.split(" ")[1]; + + try { + const decoded = verify(token, process.env.JWT_SECRET, {ignoreExpiration: false}) as { + userId: number; + exp: number; + }; + + const currentTime = Math.floor(Date.now() / 1000); // Get current timestamp + const timeLeft = decoded.exp - currentTime; + + // If the token has less than REFRESH_THRESHOLD seconds left, refresh it + let newToken = null; + + if (timeLeft < parseInt(process.env.REFRESH_THRESHOLD)) { + newToken = sign({userId: decoded.userId}, process.env.JWT_SECRET, {expiresIn: process.env.EXPIRATION_TIME}); + c.res.headers.set("Authorization", `Bearer ${newToken}`); + } + + c.set("user", {id: decoded.userId}); + await next(); + + // If a new token was generated, send it in response headers + if (newToken) { + console.log("token was refreshed"); + c.res.headers.set("X-Refreshed-Token", newToken); + } + } catch (err) { + return c.json({error: "Invalid token"}, 401); + } +}; diff --git a/apps/server/src/services/auth/routes/login.ts b/server/src/services/auth/routes/login.ts similarity index 93% rename from apps/server/src/services/auth/routes/login.ts rename to server/src/services/auth/routes/login.ts index 1b95435..ecd4414 100644 --- a/apps/server/src/services/auth/routes/login.ts +++ b/server/src/services/auth/routes/login.ts @@ -1,5 +1,5 @@ import {z, createRoute, OpenAPIHono} from "@hono/zod-openapi"; -import {login} from "lst-auth"; +import {login} from "../controllers/login"; const app = new OpenAPIHono(); @@ -76,9 +76,9 @@ app.openapi(route, async (c) => { const {token, user} = login(body.username, body.password); // Set the JWT as an HTTP-only cookie - c.header("Set-Cookie", `auth_token=${token}; HttpOnly; Path=/; SameSite=None; Max-Age=3600`); + // c.header("Set-Cookie", `auth_token=${token}; HttpOnly; Path=/; SameSite=None; Max-Age=3600`); - return c.json({message: "Login successful", user}); + return c.json({message: "Login successful", data: {token, user}}); } catch (err) { return c.json({message: err instanceof Error ? err.message : "Invalid credentials"}, 401); } diff --git a/apps/server/src/services/auth/routes/register.ts b/server/src/services/auth/routes/register.ts similarity index 100% rename from apps/server/src/services/auth/routes/register.ts rename to server/src/services/auth/routes/register.ts diff --git a/apps/server/src/services/auth/routes/session.ts b/server/src/services/auth/routes/session.ts similarity index 81% rename from apps/server/src/services/auth/routes/session.ts rename to server/src/services/auth/routes/session.ts index b4c353a..cc7f186 100644 --- a/apps/server/src/services/auth/routes/session.ts +++ b/server/src/services/auth/routes/session.ts @@ -25,22 +25,22 @@ const route = createRoute({ }); session.openapi(route, async (c) => { const authHeader = c.req.header("Authorization"); - const cookies = c.req.header("cookie"); if (authHeader?.includes("Basic")) { // return c.json({message: "You are a Basic user! Please login to get a token"}, 401); } - if (!authHeader && !cookies) { + if (!authHeader) { return c.json({error: "Unauthorized"}, 401); } - const token = cookies?.split("auth_token=")[1].split(";")[0] || authHeader?.split("Bearer ")[1] || ""; + const token = authHeader?.split("Bearer ")[1] || ""; try { const payload = await verify(token, JWT_SECRET); - return c.json({user: {id: payload.userId, username: payload.username}, token}); + console.log(payload); + return c.json({token}); } catch (err) { return c.json({error: "Invalid or expired token"}, 401); } diff --git a/apps/server/src/services/ocme/ocmeServer.ts b/server/src/services/ocme/ocmeServer.ts similarity index 100% rename from apps/server/src/services/ocme/ocmeServer.ts rename to server/src/services/ocme/ocmeServer.ts diff --git a/apps/ocme/tsconfig.json b/server/tsconfig.json similarity index 100% rename from apps/ocme/tsconfig.json rename to server/tsconfig.json diff --git a/tsconfig.json b/tsconfig.json index aaf4ecc..2cf0702 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,23 +1,23 @@ { - "compilerOptions": { - "lib": ["ESNext"], - "module": "esnext", - "target": "esnext", - "moduleResolution": "bundler", - "moduleDetection": "force", - "allowImportingTsExtensions": true, - "noEmit": true, - "composite": true, - "strict": true, - "downlevelIteration": true, - "skipLibCheck": true, - "jsx": "react-jsx", - "removeComments": true, - "allowSyntheticDefaultImports": true, - "forceConsistentCasingInFileNames": true, - "allowJs": true, - "types": [ - "bun-types" // add Bun global - ] - } + "compilerOptions": { + "lib": ["ESNext"], + "module": "esnext", + "target": "esnext", + "moduleResolution": "bundler", + "moduleDetection": "force", + "allowImportingTsExtensions": true, + "noEmit": true, + "composite": true, + "strict": true, + "downlevelIteration": true, + "skipLibCheck": true, + "jsx": "react-jsx", + "removeComments": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "allowJs": true, + "types": [ + "bun-types" // add Bun global + ] + } }