diff --git a/drizzle.config.ts b/drizzle.config.ts index bb9afba..2082e96 100644 --- a/drizzle.config.ts +++ b/drizzle.config.ts @@ -3,7 +3,7 @@ import { defineConfig } from "drizzle-kit"; export default defineConfig({ out: "./drizzle", - schema: "./src/db/schema.ts", + schema: "./src/db/schema", dialect: "postgresql", dbCredentials: { url: process.env.DATABASE_URL!, diff --git a/drizzle/0000_bright_meltdown.sql b/drizzle/0000_pretty_banshee.sql similarity index 57% rename from drizzle/0000_bright_meltdown.sql rename to drizzle/0000_pretty_banshee.sql index 46b6792..52d3c12 100644 --- a/drizzle/0000_bright_meltdown.sql +++ b/drizzle/0000_pretty_banshee.sql @@ -1,4 +1,6 @@ -CREATE TABLE "account" ( +CREATE SCHEMA "auth"; +--> statement-breakpoint +CREATE TABLE "auth"."account" ( "id" text PRIMARY KEY NOT NULL, "account_id" text NOT NULL, "provider_id" text NOT NULL, @@ -14,14 +16,14 @@ CREATE TABLE "account" ( "updated_at" timestamp NOT NULL ); --> statement-breakpoint -CREATE TABLE "rate_limit" ( +CREATE TABLE "auth"."rate_limit" ( "id" text PRIMARY KEY NOT NULL, "key" text, "count" integer, "last_request" integer ); --> statement-breakpoint -CREATE TABLE "session" ( +CREATE TABLE "auth"."session" ( "id" text PRIMARY KEY NOT NULL, "expires_at" timestamp NOT NULL, "token" text NOT NULL, @@ -33,7 +35,7 @@ CREATE TABLE "session" ( CONSTRAINT "session_token_unique" UNIQUE("token") ); --> statement-breakpoint -CREATE TABLE "user" ( +CREATE TABLE "auth"."user" ( "id" text PRIMARY KEY NOT NULL, "name" text NOT NULL, "email" text NOT NULL, @@ -44,7 +46,7 @@ CREATE TABLE "user" ( CONSTRAINT "user_email_unique" UNIQUE("email") ); --> statement-breakpoint -CREATE TABLE "verification" ( +CREATE TABLE "auth"."verification" ( "id" text PRIMARY KEY NOT NULL, "identifier" text NOT NULL, "value" text NOT NULL, @@ -53,5 +55,15 @@ CREATE TABLE "verification" ( "updated_at" timestamp ); --> statement-breakpoint -ALTER TABLE "account" ADD CONSTRAINT "account_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint -ALTER TABLE "session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE no action ON UPDATE no action; \ No newline at end of file +CREATE TABLE "note" ( + "id" text PRIMARY KEY NOT NULL, + "title" text, + "content" text, + "createdAt" timestamp DEFAULT now(), + "updatedAt" timestamp, + "ownerId" text NOT NULL +); +--> statement-breakpoint +ALTER TABLE "auth"."account" ADD CONSTRAINT "account_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "auth"."user"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "auth"."session" ADD CONSTRAINT "session_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "auth"."user"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "note" ADD CONSTRAINT "note_ownerId_user_id_fk" FOREIGN KEY ("ownerId") REFERENCES "auth"."user"("id") ON DELETE no action ON UPDATE no action; \ No newline at end of file diff --git a/drizzle/meta/0000_snapshot.json b/drizzle/meta/0000_snapshot.json index c71cc88..be10320 100644 --- a/drizzle/meta/0000_snapshot.json +++ b/drizzle/meta/0000_snapshot.json @@ -1,12 +1,12 @@ { - "id": "e9e52dc2-cfab-453f-8e23-57a32259b8e9", + "id": "806f9895-fec6-43da-9c78-46e599e611e8", "prevId": "00000000-0000-0000-0000-000000000000", "version": "7", "dialect": "postgresql", "tables": { - "public.account": { + "auth.account": { "name": "account", - "schema": "", + "schema": "auth", "columns": { "id": { "name": "id", @@ -93,6 +93,7 @@ "name": "account_user_id_user_id_fk", "tableFrom": "account", "tableTo": "user", + "schemaTo": "auth", "columnsFrom": [ "user_id" ], @@ -109,9 +110,9 @@ "checkConstraints": {}, "isRLSEnabled": false }, - "public.rate_limit": { + "auth.rate_limit": { "name": "rate_limit", - "schema": "", + "schema": "auth", "columns": { "id": { "name": "id", @@ -146,9 +147,9 @@ "checkConstraints": {}, "isRLSEnabled": false }, - "public.session": { + "auth.session": { "name": "session", - "schema": "", + "schema": "auth", "columns": { "id": { "name": "id", @@ -205,6 +206,7 @@ "name": "session_user_id_user_id_fk", "tableFrom": "session", "tableTo": "user", + "schemaTo": "auth", "columnsFrom": [ "user_id" ], @@ -229,9 +231,9 @@ "checkConstraints": {}, "isRLSEnabled": false }, - "public.user": { + "auth.user": { "name": "user", - "schema": "", + "schema": "auth", "columns": { "id": { "name": "id", @@ -292,9 +294,9 @@ "checkConstraints": {}, "isRLSEnabled": false }, - "public.verification": { + "auth.verification": { "name": "verification", - "schema": "", + "schema": "auth", "columns": { "id": { "name": "id", @@ -340,10 +342,77 @@ "policies": {}, "checkConstraints": {}, "isRLSEnabled": false + }, + "public.note": { + "name": "note", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "ownerId": { + "name": "ownerId", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "note_ownerId_user_id_fk": { + "name": "note_ownerId_user_id_fk", + "tableFrom": "note", + "tableTo": "user", + "schemaTo": "auth", + "columnsFrom": [ + "ownerId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false } }, "enums": {}, - "schemas": {}, + "schemas": { + "auth": "auth" + }, "sequences": {}, "roles": {}, "policies": {}, diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 901f83a..0c15f9e 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -5,8 +5,8 @@ { "idx": 0, "version": "7", - "when": 1736964339376, - "tag": "0000_bright_meltdown", + "when": 1736970092723, + "tag": "0000_pretty_banshee", "breakpoints": true } ] diff --git a/src/api/note/note.controller.ts b/src/api/note/note.controller.ts index 9086a64..f916bdb 100644 --- a/src/api/note/note.controller.ts +++ b/src/api/note/note.controller.ts @@ -1,25 +1,141 @@ -import { Memo } from "./note.model"; +import { and, eq, notExists } from "drizzle-orm"; +import { db } from "../../db"; +import { note } from "../../db/schema/note"; +import { CreateNote } from "./note.model"; -export class Note { - constructor( - public data: Memo[] = [ - { - data: "Moonhalo", - }, - ] - ) {} - - add(note: Memo) { - this.data.push(note); - - return this.data; +export class NoteController { + async createNote(new_note: CreateNote, ownerId: string) { + const new_note_data = { ...new_note, ownerId: ownerId }; + const result = await db + .insert(note) + .values(new_note_data) + .returning({ + id: note.id, + title: note.title, + content: note.content, + createdAt: note.createdAt, + updatedAt: note.updatedAt, + }) + .execute(); + return { + success: true, + data: result, + message: "Note created successfully", + error: null, + }; } - remove(index: number) { - return this.data.splice(index, 1); + async getOwnerNotes(ownerId: string, limit:number=10, offset:number=0) { + const result = await db + .select({ + id: note.id, + title: note.title, + content: note.content, + createdAt: note.createdAt, + updatedAt: note.updatedAt, + }) + .from(note) + .where(and(eq(note.ownerId, ownerId), notExists(note.deletedAt))) + .limit(limit).offset(offset) + .execute(); + return { + success: true, + data: result, + message: "", + error: null, + }; } - update(index: number, note: Partial) { - return (this.data[index] = { ...this.data[index], ...note }); + async getNoteById(noteId: string, ownerId: string) { + const result = await db + .select({ + id: note.id, + title: note.title, + content: note.content, + createdAt: note.createdAt, + updatedAt: note.updatedAt, + }) + .from(note) + .where( + and( + eq(note.id, noteId), + eq(note.ownerId, ownerId), + notExists(note.deletedAt) + ) + ) + .execute(); + return { + success: true, + data: result, + message: "", + error: null, + }; + } + + async updateNoteById( + noteId: string, + updated_note: CreateNote, + ownerId: string + ) { + const new_note_data = { ...updated_note, updatedAt: new Date() }; + const result = await db + .update(note) + .set(new_note_data) + .where( + and( + eq(note.id, noteId), + eq(note.ownerId, ownerId), + notExists(note.deletedAt) + ) + ) + .returning({ + id: note.id, + title: note.title, + content: note.content, + createdAt: note.createdAt, + updatedAt: note.updatedAt, + }) + .execute(); + + return { + success: true, + data: result, + message: "Note updated successfully", + error: null, + }; + } + + async deleteNoteById(noteId: string, ownerId: string) { + await db + .update(note) + .set({ deletedAt: new Date() }) + .where( + and( + eq(note.id, noteId), + eq(note.ownerId, ownerId), + notExists(note.deletedAt) + ) + ) + .execute(); + return { + success: true, + data: null, + message: "Note deleted successfully", + error: null, + }; + } + + async deleteAllNotes(ownerId: string) { + await db + .update(note) + .set({ deletedAt: new Date() }) + .where(and(eq(note.ownerId, ownerId), notExists(note.deletedAt))) + .execute(); + return { + success: true, + data: null, + message: "Notes deleted successfully", + error: null, + }; } } diff --git a/src/api/note/note.model.ts b/src/api/note/note.model.ts index 41889b3..472a915 100644 --- a/src/api/note/note.model.ts +++ b/src/api/note/note.model.ts @@ -1,7 +1,37 @@ +import { createSelectSchema } from "drizzle-typebox"; import { t } from "elysia"; +import { note } from "../../db/schema/note"; +import { InferInsertModel, InferSelectModel } from "drizzle-orm"; -export const memoSchema = t.Object({ - data: t.String(), -}); -export type Memo = typeof memoSchema.static; +export const SelectNoteSchema = createSelectSchema(note); + +export const NoteSchema = t.Omit(SelectNoteSchema, ["deletedAt", "ownerId"]); + +export type Note = InferSelectModel; +export type CreateNote = Pick< + InferInsertModel, + "title" | "content" +>; +export const createNoteSchema = t.Pick(NoteSchema, [ + "title", + "content", +]); + +export const successGetNoteResponse = t.Object({ + success:t.Boolean({default:true}), + data: t.Array(NoteSchema), + error: t.Null(), + message: t.String() +}, { + description:"Success" +}) + +export const successDeleteNoteResponse = t.Object({ + success:t.Boolean({default:true}), + data: t.Null(), + error: t.Null(), + message: t.String({default:"Note deletion succesful"}) +}, { + description:"Success" +}) \ No newline at end of file diff --git a/src/api/note/note.route.ts b/src/api/note/note.route.ts index c2f624b..4ce9366 100644 --- a/src/api/note/note.route.ts +++ b/src/api/note/note.route.ts @@ -1,44 +1,129 @@ -import { Elysia, t } from "elysia"; -import { Note } from "./note.controller"; -import { memoSchema } from "./note.model"; +import { Elysia, error, t } from "elysia"; +import { createNoteSchema, NoteSchema, successDeleteNoteResponse, successGetNoteResponse } from "./note.model"; +import { NoteController } from "./note.controller"; +import { userMiddleware } from "../../middlewares/auth-middleware"; +import { commonResponses } from "../../lib/utils/common"; -export const note = new Elysia({ prefix: "/note" }) - .decorate("note", new Note()) +export const noteRouter = new Elysia({ + prefix: "/note", + name: "CRUD Operations for Notes", + "analytic":true, + tags: ["Note"], + detail: { + description: "Notes CRUD operations", + }, +}) + .decorate("note", new NoteController()) .model({ - memo: t.Omit(memoSchema, ["author"]), - }) - .get("/", ({ note }) => note.data) - .put("/", ({ note, body: { data } }) => note.add({ data }), { - body: "memo", + note: NoteSchema, }) + .derive(({ request }) => userMiddleware(request)) .get( - "/:index", - ({ note, params: { index }, error }) => { - return note.data[index] ?? error(404, "Not Found :("); + "", + async ({ note, user, query}) => { + return await note.getOwnerNotes(user.id, query.limit, query.offset); }, { - params: t.Object({ - index: t.Number(), + query:t.Object({ + limit: t.Optional(t.Number()), + offset: t.Optional(t.Number()) }), + response:{ + 200: successGetNoteResponse, + ...commonResponses + }, + detail:{ + "description":"Get all notes of the user", + "summary":"Get all notes" + } } ) - .guard({ - params: t.Object({ - index: t.Number(), - }), - }) - .delete("/:index", ({ note, params: { index }, error }) => { - if (index in note.data) return note.remove(index); - - return error(422); - }) - .patch( - "/:index", - ({ note, params: { index }, body: { data }, error }) => { - if (index in note.data) return note.update(index, { data }); - return error(422); + .get( + ":id", + async ({ note, user, params:{id} }) => { + return await note.getNoteById(id, user.id); }, { - body: "memo", + params:t.Object({ + id: t.String(), + }), + response: { + 200: successGetNoteResponse, + ...commonResponses + }, + detail:{ + "description":"Get a note by Id", + "summary":"Get a note" + } } - ); + ) + .post( + "", + async ({ body, note, user }) => { + return await note.createNote(body, user.id); + }, + { + body: createNoteSchema, + response: { + 200: successGetNoteResponse, + ...commonResponses + }, + detail:{ + "description":"Create a new note", + "summary":"Create a note" + } + } + ).patch( + ":id", + async ({ body, note, user, params:{id} }) => { + return await note.updateNoteById(id, body, user.id); + }, + { + body: createNoteSchema, + params:t.Object({ + id: t.String(), + }), + response: { + 200: successGetNoteResponse, + ...commonResponses + }, + detail:{ + "description":"Update a note by Id", + "summary":"Update a note" + } + } + ).delete( + ":id", + async ({ note, user, params:{id} }) => { + return await note.deleteNoteById(id, user.id); + }, + { + params:t.Object({ + id: t.String(), + }), + response: { + 200: successDeleteNoteResponse, + ...commonResponses + }, + detail:{ + "description":"Delete a note by Id", + "summary":"Delete a note" + } + } + ) + .delete( + "", + async ({ note, user }) => { + return await note.deleteAllNotes(user.id); + }, + { + response: { + 200: successDeleteNoteResponse, + ...commonResponses + }, + detail:{ + "description":"Delete all notes of an user", + "summary":"Delete all notes" + } + } + ) diff --git a/src/db/schema.ts b/src/db/schema.ts deleted file mode 100644 index 1de748d..0000000 --- a/src/db/schema.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { pgTable, text, integer, timestamp, boolean } from "drizzle-orm/pg-core"; - -export const user = pgTable("user", { - id: text("id").primaryKey(), - name: text('name').notNull(), - email: text('email').notNull().unique(), - emailVerified: boolean('email_verified').notNull(), - image: text('image'), - createdAt: timestamp('created_at').notNull(), - updatedAt: timestamp('updated_at').notNull() - }); - -export const session = pgTable("session", { - id: text("id").primaryKey(), - expiresAt: timestamp('expires_at').notNull(), - token: text('token').notNull().unique(), - createdAt: timestamp('created_at').notNull(), - updatedAt: timestamp('updated_at').notNull(), - ipAddress: text('ip_address'), - userAgent: text('user_agent'), - userId: text('user_id').notNull().references(()=> user.id) - }); - -export const account = pgTable("account", { - id: text("id").primaryKey(), - accountId: text('account_id').notNull(), - providerId: text('provider_id').notNull(), - userId: text('user_id').notNull().references(()=> user.id), - accessToken: text('access_token'), - refreshToken: text('refresh_token'), - idToken: text('id_token'), - accessTokenExpiresAt: timestamp('access_token_expires_at'), - refreshTokenExpiresAt: timestamp('refresh_token_expires_at'), - scope: text('scope'), - password: text('password'), - createdAt: timestamp('created_at').notNull(), - updatedAt: timestamp('updated_at').notNull() - }); - -export const verification = pgTable("verification", { - id: text("id").primaryKey(), - identifier: text('identifier').notNull(), - value: text('value').notNull(), - expiresAt: timestamp('expires_at').notNull(), - createdAt: timestamp('created_at'), - updatedAt: timestamp('updated_at') - }); - -export const rateLimit = pgTable("rate_limit", { - id: text("id").primaryKey(), - key: text('key'), - count: integer('count'), - lastRequest: integer('last_request') - }); diff --git a/src/db/schema/auth.ts b/src/db/schema/auth.ts new file mode 100644 index 0000000..c68d842 --- /dev/null +++ b/src/db/schema/auth.ts @@ -0,0 +1,56 @@ +import { text, integer, timestamp, boolean, pgSchema } from "drizzle-orm/pg-core"; + +export const authSchema = pgSchema('auth'); + +export const user = authSchema.table("user", { + id: text("id").primaryKey(), + name: text('name').notNull(), + email: text('email').notNull().unique(), + emailVerified: boolean('email_verified').notNull(), + image: text('image'), + createdAt: timestamp('created_at').notNull(), + updatedAt: timestamp('updated_at').notNull() +}); + +export const session = authSchema.table("session", { + id: text("id").primaryKey(), + expiresAt: timestamp('expires_at').notNull(), + token: text('token').notNull().unique(), + createdAt: timestamp('created_at').notNull(), + updatedAt: timestamp('updated_at').notNull(), + ipAddress: text('ip_address'), + userAgent: text('user_agent'), + userId: text('user_id').notNull().references(() => user.id) +}); + +export const account = authSchema.table("account", { + id: text("id").primaryKey(), + accountId: text('account_id').notNull(), + providerId: text('provider_id').notNull(), + userId: text('user_id').notNull().references(() => user.id), + accessToken: text('access_token'), + refreshToken: text('refresh_token'), + idToken: text('id_token'), + accessTokenExpiresAt: timestamp('access_token_expires_at'), + refreshTokenExpiresAt: timestamp('refresh_token_expires_at'), + scope: text('scope'), + password: text('password'), + createdAt: timestamp('created_at').notNull(), + updatedAt: timestamp('updated_at').notNull() +}); + +export const verification = authSchema.table("verification", { + id: text("id").primaryKey(), + identifier: text('identifier').notNull(), + value: text('value').notNull(), + expiresAt: timestamp('expires_at').notNull(), + createdAt: timestamp('created_at'), + updatedAt: timestamp('updated_at') +}); + +export const rateLimit = authSchema.table("rate_limit", { + id: text("id").primaryKey(), + key: text('key'), + count: integer('count'), + lastRequest: integer('last_request') +}); diff --git a/src/db/schema/note.ts b/src/db/schema/note.ts new file mode 100644 index 0000000..fd19f7a --- /dev/null +++ b/src/db/schema/note.ts @@ -0,0 +1,13 @@ +import { pgTable, text, timestamp } from "drizzle-orm/pg-core"; +import { createId } from '@paralleldrive/cuid2' +import { user } from "./auth"; + +export const note = pgTable("note", { + id: text("id").primaryKey().$defaultFn(()=> `note_${createId()}`), + title: text("title"), + content: text("content"), + createdAt: timestamp().notNull().defaultNow(), + updatedAt: timestamp(), + deletedAt: timestamp(), + ownerId: text().notNull().references(() => user.id) +}) \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 70d2a18..78d18e2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,9 +3,8 @@ import { swagger } from "@elysiajs/swagger"; import { opentelemetry } from "@elysiajs/opentelemetry"; import { serverTiming } from "@elysiajs/server-timing"; import { cors } from '@elysiajs/cors' -import { note } from "./api/note/note.route"; +import { noteRouter } from "./api/note/note.route"; import { betterAuthView } from "./lib/auth/auth-view"; -import { userMiddleware, userInfo } from "./middlewares/auth-middleware"; import { getBaseConfig, validateEnv } from "./lib/utils/env"; const baseConfig = getBaseConfig() @@ -23,10 +22,8 @@ const app = new Elysia() if (code === "NOT_FOUND") return "Not Found :("; console.error(error); }) - .derive(({ request }) => userMiddleware(request)) .all("/api/auth/*", betterAuthView) - .use(note) - .get("/user", ({ user, session }) => userInfo(user, session)) + .use(noteRouter) .get("/", () => `${baseConfig.SERVICE_NAME} Server is Running`) validateEnv(); diff --git a/src/lib/auth/auth.ts b/src/lib/auth/auth.ts index bb65fdb..bb5a527 100644 --- a/src/lib/auth/auth.ts +++ b/src/lib/auth/auth.ts @@ -2,7 +2,7 @@ import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { db } from "../../db/index"; import { openAPI } from "better-auth/plugins" -import { user, account, verification, session } from "../../db/schema"; +import { user, account, verification, session, rateLimit } from "../../db/schema/auth"; import { sendMail } from "../mail/mail"; import { renderToStaticMarkup } from "react-dom/server"; import { createElement } from "react"; @@ -15,7 +15,8 @@ export const auth = betterAuth({ user: user, session: session, account: account, - verification: verification + verification: verification, + rateLimit: rateLimit, } }), rateLimit: { diff --git a/src/lib/utils/common.ts b/src/lib/utils/common.ts new file mode 100644 index 0000000..083efe1 --- /dev/null +++ b/src/lib/utils/common.ts @@ -0,0 +1,82 @@ +import { t } from "elysia"; + +export const commonResponses = { + 400: t.Object( + { + data: t.Null(), + success: t.Boolean({ default: false }), + message: t.String({ default: "Bad Request" }), + error: t.String({ + default: "Missing parameters, or invalid parameters.", + }), + }, + { + description: + "Bad Request. Usually due to missing parameters, or invalid parameters.", + } + ), + 401: t.Object( + { + data: t.Null(), + success: t.Boolean({ default: false }), + message: t.String({ default: "Unauthorized" }), + error: t.String({ + default: "User needs to sign in to access this resource", + }), + }, + { + description: "Unauthorized. Due to missing or invalid authentication.", + } + ), + 403: t.Object( + { + data: t.Null(), + success: t.Boolean({ default: false }), + message: t.String({ default: "Forbidden" }), + error: t.String({ + default: "User does not have permission to access this resource", + }), + }, + { + description: + "Forbidden. You do not have permission to access this resource or to perform this action.", + } + ), + 404: t.Object( + { + data: t.Null(), + success: t.Boolean({ default: false }), + message: t.String({ default: "Not Found" }), + error: t.String({ default: "Requested resource has not found" }), + }, + { + description: "Not Found. The requested resource was not found.", + } + ), + 429: t.Object( + { + data: t.Null(), + success: t.Boolean({ default: false }), + message: t.String({ default: "Too Many Requests" }), + error: t.String({ + default: "RUser has exceeded the rate limit. Try again later.", + }), + }, + { + description: + "Too Many Requests. You have exceeded the rate limit. Try again later.", + } + ), + 500: t.Object( + { + data: t.Null(), + success: t.Boolean({ default: false }), + message: t.String({ default: "Internal Server Error" }), + error: t.String({ default: "Server faced an error" }), + }, + { + description: + "Internal Server Error. This is a problem with the server that you cannot fix.", + } + ), +}; diff --git a/src/middlewares/auth-middleware.ts b/src/middlewares/auth-middleware.ts index 1cadaaa..ece7db6 100644 --- a/src/middlewares/auth-middleware.ts +++ b/src/middlewares/auth-middleware.ts @@ -1,15 +1,13 @@ import { Session, User } from "better-auth/types"; import { auth } from "../lib/auth/auth"; +import { error } from "elysia"; // user middleware (compute user and session and pass to routes) export const userMiddleware = async (request: Request) => { const session = await auth.api.getSession({ headers: request.headers }); if (!session) { - return { - user: null, - session: null, - }; + return error("Unauthorized", 401); } return {