init
This commit is contained in:
@@ -0,0 +1,2 @@
|
|||||||
|
node_modules
|
||||||
|
*.db
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
.env
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"name": "backend",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"dev": "tsx src/index.ts"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"type": "module",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bcrypt": "^6.0.0",
|
||||||
|
"@types/cors": "^2.8.19",
|
||||||
|
"@types/express": "^5.0.6",
|
||||||
|
"@types/express-session": "^1.19.0",
|
||||||
|
"@types/node": "^26.4.1",
|
||||||
|
"@types/passport": "^1.0.17",
|
||||||
|
"@types/passport-local": "^1.0.38",
|
||||||
|
"tsx": "^4.23.13",
|
||||||
|
"typescript": "^7.0.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"bcrypt": "^6.0.0",
|
||||||
|
"cors": "^2.8.6",
|
||||||
|
"database": "workspace:*",
|
||||||
|
"dotenv": "^17.4.2",
|
||||||
|
"express": "^5.2.1",
|
||||||
|
"express-session": "^1.19.0",
|
||||||
|
"passport": "^0.7.0",
|
||||||
|
"passport-local": "^1.0.0",
|
||||||
|
"zod": "^4.5.4"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import type { Request, Response, NextFunction } from "express";
|
||||||
|
import { prisma } from "database";
|
||||||
|
import schemas from "../utils/schemas.js";
|
||||||
|
|
||||||
|
export async function createPost(
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction,
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const body = schemas.posts.create.parse(req.body);
|
||||||
|
|
||||||
|
const post = await prisma.post.create({
|
||||||
|
data: {
|
||||||
|
...body,
|
||||||
|
userId: req.user!.id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(201).json(post);
|
||||||
|
} catch (e) {
|
||||||
|
next(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function fetchPost(
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction,
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const slug = schemas.posts.get.parse(req.params.slug);
|
||||||
|
const post = await prisma.post.findFirst({
|
||||||
|
where: {
|
||||||
|
slug,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (post) {
|
||||||
|
res.status(200).json(post);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
res.status(404).json({ message: "Could not find post with that slug" });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
next(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getAllPosts(
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction,
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const posts = await prisma.post.findMany();
|
||||||
|
res.status(200).json(posts);
|
||||||
|
} catch (e) {
|
||||||
|
next(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function deletePost(
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction,
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const slug = schemas.posts.delete.parse(req.params.slug);
|
||||||
|
|
||||||
|
await prisma.post.findFirst({
|
||||||
|
where: {
|
||||||
|
slug,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
res.sendStatus(204);
|
||||||
|
} catch (e) {
|
||||||
|
next(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
import type { Request, Response, NextFunction } from "express";
|
||||||
|
import bcrypt from "bcrypt";
|
||||||
|
import schemas from "../utils/schemas.js";
|
||||||
|
import passport from "passport";
|
||||||
|
import { prisma } from "database";
|
||||||
|
|
||||||
|
export async function register(
|
||||||
|
req: Request,
|
||||||
|
res: Response,
|
||||||
|
next: NextFunction,
|
||||||
|
) {
|
||||||
|
try {
|
||||||
|
const body = schemas.users.registration.parse(req.body);
|
||||||
|
|
||||||
|
const email = body.email;
|
||||||
|
const passwordHash = await bcrypt.hash(body.password, 12);
|
||||||
|
const user = await prisma.user.create({
|
||||||
|
data: {
|
||||||
|
email,
|
||||||
|
password: passwordHash,
|
||||||
|
name: body.name,
|
||||||
|
},
|
||||||
|
select: {
|
||||||
|
id: true,
|
||||||
|
email: true,
|
||||||
|
name: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
req.login(user, (err) => {
|
||||||
|
if (err) return next(err);
|
||||||
|
res.status(201).json({ user });
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
next(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function login(req: Request, res: Response, next: NextFunction) {
|
||||||
|
try {
|
||||||
|
passport.authenticate(
|
||||||
|
"local",
|
||||||
|
(
|
||||||
|
err: unknown,
|
||||||
|
user: Express.User | false,
|
||||||
|
info?: { message?: string },
|
||||||
|
) => {
|
||||||
|
if (err) return next(err);
|
||||||
|
|
||||||
|
if (!user) {
|
||||||
|
return res.status(401).json({
|
||||||
|
error: info?.message ?? "Incorrect email or password",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
req.login(user, (loginErr) => {
|
||||||
|
if (loginErr) return next(loginErr);
|
||||||
|
res.json({ id: user.id, email: user.email, name: user.name });
|
||||||
|
});
|
||||||
|
},
|
||||||
|
)(req, res, next);
|
||||||
|
} catch (e) {
|
||||||
|
next(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getUser(req: Request, res: Response, next: NextFunction) {
|
||||||
|
const user = req.user;
|
||||||
|
res.status(200).json({
|
||||||
|
id: user?.id,
|
||||||
|
email: user?.email,
|
||||||
|
name: user?.name,
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
import express, {
|
||||||
|
type Request,
|
||||||
|
type Response,
|
||||||
|
type NextFunction,
|
||||||
|
} from "express";
|
||||||
|
import cors from "cors";
|
||||||
|
import session from "express-session";
|
||||||
|
import passport from "passport";
|
||||||
|
import bcrypt from "bcrypt";
|
||||||
|
import env from "./utils/env.js";
|
||||||
|
import { Strategy as LocalStrategy } from "passport-local";
|
||||||
|
import { prisma } from "database";
|
||||||
|
import { ZodError } from "zod";
|
||||||
|
|
||||||
|
// routes
|
||||||
|
import usersRoute from "./routers/users.js";
|
||||||
|
import postsRoute from "./routers/posts.js";
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
|
||||||
|
// passport strategy
|
||||||
|
passport.use(
|
||||||
|
new LocalStrategy(
|
||||||
|
{ usernameField: "email" },
|
||||||
|
async (email, password, done) => {
|
||||||
|
try {
|
||||||
|
const user = await prisma.user.findFirst({
|
||||||
|
where: {
|
||||||
|
email,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!user) return done(null, false, { message: "Bad credentials" });
|
||||||
|
|
||||||
|
const ok = await bcrypt.compare(password, user.password);
|
||||||
|
return ok
|
||||||
|
? done(null, user)
|
||||||
|
: done(null, false, { message: "Bad credentials" });
|
||||||
|
} catch (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
passport.serializeUser((user, done) => done(null, user.id));
|
||||||
|
passport.deserializeUser(async (id: number, done) => {
|
||||||
|
const user = await prisma.user.findFirst({
|
||||||
|
where: {
|
||||||
|
id,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
done(null, user ?? false);
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(express.urlencoded({ extended: false }));
|
||||||
|
app.use(
|
||||||
|
session({
|
||||||
|
secret: env.SESSION_SECRET,
|
||||||
|
resave: false,
|
||||||
|
saveUninitialized: false,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
app.use(passport.session());
|
||||||
|
app.use(express.json());
|
||||||
|
if (env.NODE_ENV === "production") {
|
||||||
|
app.use(
|
||||||
|
cors({
|
||||||
|
origin: "blog.alexav.gg",
|
||||||
|
credentials: true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
app.get("/", (req: Request, res: Response) => {
|
||||||
|
res.status(200).json({
|
||||||
|
status: 200,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
app.use("/users", usersRoute);
|
||||||
|
app.use("/posts", postsRoute);
|
||||||
|
|
||||||
|
app.use(
|
||||||
|
(err: Error | ZodError, req: Request, res: Response, next: NextFunction) => {
|
||||||
|
if (err instanceof ZodError) {
|
||||||
|
res.status(400).json({
|
||||||
|
status: 400,
|
||||||
|
message: "Malformed request body",
|
||||||
|
issues: err.issues,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.log(err);
|
||||||
|
res.status(500).json({
|
||||||
|
status: 500,
|
||||||
|
message:
|
||||||
|
"Sorry, an unexpected error occurred while performing that action",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
app.listen(3000, () => {
|
||||||
|
console.log("Server started");
|
||||||
|
});
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { Router } from "express";
|
||||||
|
import {
|
||||||
|
createPost,
|
||||||
|
fetchPost,
|
||||||
|
getAllPosts,
|
||||||
|
deletePost,
|
||||||
|
} from "../controllers/posts.js";
|
||||||
|
import { requireAuth } from "../utils/auth.js";
|
||||||
|
|
||||||
|
const router: Router = Router();
|
||||||
|
|
||||||
|
router.post("/create", requireAuth, createPost);
|
||||||
|
router.get("/:slug", fetchPost);
|
||||||
|
router.get("/", getAllPosts);
|
||||||
|
router.delete("/:slug", requireAuth, deletePost);
|
||||||
|
|
||||||
|
export default router;
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { Router } from "express";
|
||||||
|
import { requireAuth } from "../utils/auth.js";
|
||||||
|
import { register, login, getUser } from "../controllers/users.js";
|
||||||
|
|
||||||
|
const router: Router = Router();
|
||||||
|
|
||||||
|
router.post("/login", login);
|
||||||
|
router.post("/logout", (req, res, next) => {
|
||||||
|
req.logout((err) => (err ? next(err) : res.redirect("/")));
|
||||||
|
});
|
||||||
|
router.post("/register", register);
|
||||||
|
router.get("/@me", requireAuth, getUser);
|
||||||
|
|
||||||
|
export default router;
|
||||||
Vendored
+13
@@ -0,0 +1,13 @@
|
|||||||
|
import { User as PrismaUser } from "database";
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
namespace Express {
|
||||||
|
interface User {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
email: string;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {};
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import type { Request, Response, NextFunction } from "express";
|
||||||
|
|
||||||
|
export function requireAuth(req: Request, res: Response, next: NextFunction) {
|
||||||
|
if (req.isAuthenticated()) return next();
|
||||||
|
res.status(401).json({ error: "Not logged in" });
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import "dotenv/config";
|
||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
const env = z.object({
|
||||||
|
NODE_ENV: z.enum(["production", "development"]).default("production"),
|
||||||
|
PORT: z.coerce.number().default(3000),
|
||||||
|
DATABASE_URL: z.string().default("file:../../dev.db"),
|
||||||
|
SESSION_SECRET: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default env.parse(process.env);
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
|
||||||
|
export default {
|
||||||
|
users: {
|
||||||
|
registration: z.object({
|
||||||
|
name: z.string().min(1),
|
||||||
|
email: z.email().min(1),
|
||||||
|
password: z.string().min(8),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
posts: {
|
||||||
|
create: z.object({
|
||||||
|
title: z.string().min(1),
|
||||||
|
slug: z.string().min(1),
|
||||||
|
description: z.string().min(1),
|
||||||
|
content: z.string().min(1),
|
||||||
|
}),
|
||||||
|
delete: z.string(),
|
||||||
|
get: z.string().min(1),
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
// Visit https://aka.ms/tsconfig to read more about this file
|
||||||
|
"compilerOptions": {
|
||||||
|
// File Layout
|
||||||
|
"rootDir": "./src",
|
||||||
|
"outDir": "./dist",
|
||||||
|
|
||||||
|
// Environment Settings
|
||||||
|
// See also https://aka.ms/tsconfig/module
|
||||||
|
"module": "nodenext",
|
||||||
|
"target": "esnext",
|
||||||
|
// For nodejs:
|
||||||
|
"lib": ["esnext"],
|
||||||
|
"types": ["node"],
|
||||||
|
// and npm install -D @types/node
|
||||||
|
|
||||||
|
// Other Outputs
|
||||||
|
"sourceMap": true,
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
|
||||||
|
// Stricter Typechecking Options
|
||||||
|
"noUncheckedIndexedAccess": true,
|
||||||
|
"exactOptionalPropertyTypes": true,
|
||||||
|
|
||||||
|
// Style Options
|
||||||
|
// "noImplicitReturns": true,
|
||||||
|
// "noImplicitOverride": true,
|
||||||
|
// "noUnusedLocals": true,
|
||||||
|
// "noUnusedParameters": true,
|
||||||
|
// "noFallthroughCasesInSwitch": true,
|
||||||
|
// "noPropertyAccessFromIndexSignature": true,
|
||||||
|
|
||||||
|
// Recommended Options
|
||||||
|
"strict": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noUncheckedSideEffectImports": true,
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"skipLibCheck": true
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"name": "blog",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"devEngines": {
|
||||||
|
"packageManager": {
|
||||||
|
"name": "pnpm",
|
||||||
|
"version": "^11.9.0",
|
||||||
|
"onFail": "download"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "module"
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
node_modules
|
||||||
|
# Keep environment variables out of version control
|
||||||
|
.env
|
||||||
|
|
||||||
|
/src/generated/prisma
|
||||||
|
dist/*
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"name": "database",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"default": "./dist/index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"db:generate": "prisma generate",
|
||||||
|
"db:migrate": "prisma migrate dev",
|
||||||
|
"db:deploy": "prisma migrate deploy",
|
||||||
|
"db:studio": "prisma studio",
|
||||||
|
"db:format": "prisma format",
|
||||||
|
"build": "tsc"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"type": "module",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^26.4.1",
|
||||||
|
"tsx": "^4.23.13",
|
||||||
|
"typescript": "^7.0.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@prisma/adapter-better-sqlite3": "^7.10.0",
|
||||||
|
"@prisma/client": "7.10.0",
|
||||||
|
"dotenv": "^17.4.2",
|
||||||
|
"prisma": "7.10.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "User" (
|
||||||
|
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
"email" TEXT NOT NULL,
|
||||||
|
"name" TEXT NOT NULL,
|
||||||
|
"password" TEXT NOT NULL
|
||||||
|
);
|
||||||
|
|
||||||
|
-- CreateIndex
|
||||||
|
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
-- CreateTable
|
||||||
|
CREATE TABLE "Post" (
|
||||||
|
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
"title" TEXT NOT NULL,
|
||||||
|
"description" TEXT NOT NULL,
|
||||||
|
"content" TEXT NOT NULL,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATETIME NOT NULL,
|
||||||
|
"userId" INTEGER,
|
||||||
|
CONSTRAINT "Post_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||||
|
);
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
Warnings:
|
||||||
|
|
||||||
|
- Added the required column `slug` to the `Post` table without a default value. This is not possible if the table is not empty.
|
||||||
|
|
||||||
|
*/
|
||||||
|
-- RedefineTables
|
||||||
|
PRAGMA defer_foreign_keys=ON;
|
||||||
|
PRAGMA foreign_keys=OFF;
|
||||||
|
CREATE TABLE "new_Post" (
|
||||||
|
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
|
||||||
|
"title" TEXT NOT NULL,
|
||||||
|
"description" TEXT NOT NULL,
|
||||||
|
"slug" TEXT NOT NULL,
|
||||||
|
"content" TEXT NOT NULL,
|
||||||
|
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
"updatedAt" DATETIME NOT NULL,
|
||||||
|
"userId" INTEGER,
|
||||||
|
CONSTRAINT "Post_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||||
|
);
|
||||||
|
INSERT INTO "new_Post" ("content", "createdAt", "description", "id", "title", "updatedAt", "userId") SELECT "content", "createdAt", "description", "id", "title", "updatedAt", "userId" FROM "Post";
|
||||||
|
DROP TABLE "Post";
|
||||||
|
ALTER TABLE "new_Post" RENAME TO "Post";
|
||||||
|
PRAGMA foreign_keys=ON;
|
||||||
|
PRAGMA defer_foreign_keys=OFF;
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
# Please do not edit this file manually
|
||||||
|
# It should be added in your version-control system (e.g., Git)
|
||||||
|
provider = "sqlite"
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
generator client {
|
||||||
|
provider = "prisma-client"
|
||||||
|
output = "../src/generated/prisma"
|
||||||
|
}
|
||||||
|
|
||||||
|
datasource db {
|
||||||
|
provider = "sqlite"
|
||||||
|
}
|
||||||
|
|
||||||
|
model User {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
email String @unique
|
||||||
|
name String
|
||||||
|
password String
|
||||||
|
posts Post[]
|
||||||
|
}
|
||||||
|
|
||||||
|
model Post {
|
||||||
|
id Int @id @default(autoincrement())
|
||||||
|
title String
|
||||||
|
description String
|
||||||
|
slug String
|
||||||
|
content String
|
||||||
|
|
||||||
|
createdAt DateTime @default(now())
|
||||||
|
updatedAt DateTime @updatedAt
|
||||||
|
|
||||||
|
user User? @relation(fields: [userId], references: [id])
|
||||||
|
userId Int?
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
import "dotenv/config";
|
||||||
|
import { defineConfig, env } from "prisma/config";
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
schema: "prisma/schema.prisma",
|
||||||
|
migrations: {
|
||||||
|
path: "prisma/migrations",
|
||||||
|
},
|
||||||
|
datasource: {
|
||||||
|
url: env("DATABASE_URL"),
|
||||||
|
},
|
||||||
|
});
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import "dotenv/config";
|
||||||
|
import { PrismaClient } from "./generated/prisma/client.js";
|
||||||
|
import { PrismaBetterSqlite3 } from "@prisma/adapter-better-sqlite3";
|
||||||
|
|
||||||
|
const adapter = new PrismaBetterSqlite3({
|
||||||
|
url: process.env["DATABASE_URL"] as string,
|
||||||
|
});
|
||||||
|
|
||||||
|
const globalForPrisma = globalThis as typeof globalThis & {
|
||||||
|
prisma?: PrismaClient;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const prisma: PrismaClient =
|
||||||
|
globalForPrisma.prisma ??
|
||||||
|
new PrismaClient({
|
||||||
|
adapter,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV !== "production") {
|
||||||
|
globalForPrisma.prisma = prisma;
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
export { prisma } from "./client.js";
|
||||||
|
export * from "./generated/prisma/client.js";
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
// Visit https://aka.ms/tsconfig to read more about this file
|
||||||
|
"compilerOptions": {
|
||||||
|
// File Layout
|
||||||
|
"rootDir": "./src",
|
||||||
|
"outDir": "./dist",
|
||||||
|
|
||||||
|
// Environment Settings
|
||||||
|
// See also https://aka.ms/tsconfig/module
|
||||||
|
"module": "nodenext",
|
||||||
|
"target": "esnext",
|
||||||
|
// For nodejs:
|
||||||
|
"lib": ["esnext"],
|
||||||
|
"types": ["node"],
|
||||||
|
// and npm install -D @types/node
|
||||||
|
|
||||||
|
// Other Outputs
|
||||||
|
"sourceMap": true,
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
|
||||||
|
// Stricter Typechecking Options
|
||||||
|
"noUncheckedIndexedAccess": true,
|
||||||
|
"exactOptionalPropertyTypes": true,
|
||||||
|
|
||||||
|
// Style Options
|
||||||
|
// "noImplicitReturns": true,
|
||||||
|
// "noImplicitOverride": true,
|
||||||
|
// "noUnusedLocals": true,
|
||||||
|
// "noUnusedParameters": true,
|
||||||
|
// "noFallthroughCasesInSwitch": true,
|
||||||
|
// "noPropertyAccessFromIndexSignature": true,
|
||||||
|
|
||||||
|
// Recommended Options
|
||||||
|
"strict": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"noUncheckedSideEffectImports": true,
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"skipLibCheck": true
|
||||||
|
},
|
||||||
|
"include": ["src"]
|
||||||
|
}
|
||||||
Generated
+3033
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,9 @@
|
|||||||
|
packages:
|
||||||
|
- "apps/*"
|
||||||
|
- "packages/*"
|
||||||
|
allowBuilds:
|
||||||
|
"@prisma/engines": true
|
||||||
|
bcrypt: true
|
||||||
|
better-sqlite3: true
|
||||||
|
esbuild: false
|
||||||
|
prisma: true
|
||||||
Reference in New Issue
Block a user