From 55686298391eade54406b439c81caa63f6b50442 Mon Sep 17 00:00:00 2001 From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> Date: Sat, 1 Mar 2025 14:45:50 -0600 Subject: [PATCH] refactor: organize imports and improve template utility modules --- apps/dokploy/drizzle/0066_yielding_echo.sql | 35 +++- apps/dokploy/drizzle/meta/0066_snapshot.json | 177 ++++++++++++++++++- apps/dokploy/drizzle/meta/_journal.json | 7 + apps/dokploy/package.json | 2 +- packages/server/auth-schema.ts | 36 ++++ packages/server/package.json | 2 +- packages/server/src/db/schema/account.ts | 37 +++- packages/server/src/lib/auth.ts | 11 +- pnpm-lock.yaml | 54 ++++-- 9 files changed, 320 insertions(+), 41 deletions(-) diff --git a/apps/dokploy/drizzle/0066_yielding_echo.sql b/apps/dokploy/drizzle/0066_yielding_echo.sql index 4fd42538..a8a2501a 100644 --- a/apps/dokploy/drizzle/0066_yielding_echo.sql +++ b/apps/dokploy/drizzle/0066_yielding_echo.sql @@ -72,7 +72,8 @@ CREATE TABLE "invitation" ( "role" text, "status" text NOT NULL, "expires_at" timestamp NOT NULL, - "inviter_id" text NOT NULL + "inviter_id" text NOT NULL, + "team_id" text ); --> statement-breakpoint CREATE TABLE "member" ( @@ -81,7 +82,6 @@ CREATE TABLE "member" ( "user_id" text NOT NULL, "role" text NOT NULL, "created_at" timestamp NOT NULL, - "token" text NOT NULL, "canCreateProjects" boolean DEFAULT false NOT NULL, "canAccessToSSHKeys" boolean DEFAULT false NOT NULL, "canCreateServices" boolean DEFAULT false NOT NULL, @@ -92,7 +92,8 @@ CREATE TABLE "member" ( "canAccessToGitProviders" boolean DEFAULT false NOT NULL, "canAccessToTraefikFiles" boolean DEFAULT false NOT NULL, "accesedProjects" text[] DEFAULT ARRAY[]::text[] NOT NULL, - "accesedServices" text[] DEFAULT ARRAY[]::text[] NOT NULL + "accesedServices" text[] DEFAULT ARRAY[]::text[] NOT NULL, + "team_id" text ); --> statement-breakpoint CREATE TABLE "organization" ( @@ -121,6 +122,30 @@ CREATE TABLE "two_factor" ( "backup_codes" text NOT NULL, "user_id" text NOT NULL ); + +CREATE TABLE "apikey" ( + "id" text PRIMARY KEY NOT NULL, + "name" text, + "start" text, + "prefix" text, + "key" text NOT NULL, + "user_id" text NOT NULL, + "refill_interval" integer, + "refill_amount" integer, + "last_refill_at" timestamp, + "enabled" boolean, + "rate_limit_enabled" boolean, + "rate_limit_time_window" integer, + "rate_limit_max" integer, + "request_count" integer, + "remaining" integer, + "last_request" timestamp, + "expires_at" timestamp, + "created_at" timestamp NOT NULL, + "updated_at" timestamp NOT NULL, + "permissions" text, + "metadata" text +); --> statement-breakpoint ALTER TABLE "certificate" ALTER COLUMN "adminId" SET NOT NULL;--> statement-breakpoint ALTER TABLE "notification" ALTER COLUMN "adminId" SET NOT NULL;--> statement-breakpoint @@ -134,9 +159,7 @@ ALTER TABLE "member" ADD CONSTRAINT "member_organization_id_organization_id_fk" ALTER TABLE "member" ADD CONSTRAINT "member_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action;--> statement-breakpoint ALTER TABLE "organization" ADD CONSTRAINT "organization_owner_id_user_temp_id_fk" FOREIGN KEY ("owner_id") REFERENCES "public"."user_temp"("id") ON DELETE no action ON UPDATE no action; ALTER TABLE "two_factor" ADD CONSTRAINT "two_factor_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint - - - +ALTER TABLE "apikey" ADD CONSTRAINT "apikey_user_id_user_temp_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user_temp"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint -- Data Migration diff --git a/apps/dokploy/drizzle/meta/0066_snapshot.json b/apps/dokploy/drizzle/meta/0066_snapshot.json index 2264814c..55804f0c 100644 --- a/apps/dokploy/drizzle/meta/0066_snapshot.json +++ b/apps/dokploy/drizzle/meta/0066_snapshot.json @@ -4295,6 +4295,159 @@ "checkConstraints": {}, "isRLSEnabled": false }, + "public.apikey": { + "name": "apikey", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "start": { + "name": "start", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "prefix": { + "name": "prefix", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "refill_interval": { + "name": "refill_interval", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "refill_amount": { + "name": "refill_amount", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "last_refill_at": { + "name": "last_refill_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "rate_limit_enabled": { + "name": "rate_limit_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "rate_limit_time_window": { + "name": "rate_limit_time_window", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "rate_limit_max": { + "name": "rate_limit_max", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "request_count": { + "name": "request_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "remaining": { + "name": "remaining", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "last_request": { + "name": "last_request", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "permissions": { + "name": "permissions", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "apikey_user_id_user_temp_id_fk": { + "name": "apikey_user_id_user_temp_id_fk", + "tableFrom": "apikey", + "tableTo": "user_temp", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, "public.invitation": { "name": "invitation", "schema": "", @@ -4340,6 +4493,13 @@ "type": "text", "primaryKey": false, "notNull": true + }, + "team_id": { + "name": "team_id", + "type": "text", + "primaryKey": false, + "notNull": false + } }, "indexes": {}, @@ -4411,6 +4571,12 @@ "primaryKey": false, "notNull": true }, + "team_id": { + "name": "team_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, "canCreateProjects": { "name": "canCreateProjects", "type": "boolean", @@ -4487,13 +4653,6 @@ "primaryKey": false, "notNull": true, "default": "ARRAY[]::text[]" - }, - "token": { - "name": "token", - "type": "text", - "primaryKey": false, - "notNull": true, - "default": "''" } }, "indexes": {}, @@ -4508,7 +4667,7 @@ "columnsTo": [ "id" ], - "onDelete": "no action", + "onDelete": "cascade", "onUpdate": "no action" }, "member_user_id_user_temp_id_fk": { @@ -4521,7 +4680,7 @@ "columnsTo": [ "id" ], - "onDelete": "no action", + "onDelete": "cascade", "onUpdate": "no action" } }, diff --git a/apps/dokploy/drizzle/meta/_journal.json b/apps/dokploy/drizzle/meta/_journal.json index 8bf49b3a..29a356e0 100644 --- a/apps/dokploy/drizzle/meta/_journal.json +++ b/apps/dokploy/drizzle/meta/_journal.json @@ -470,6 +470,13 @@ "when": 1739426913392, "tag": "0066_yielding_echo", "breakpoints": true + }, + { + "idx": 67, + "version": "7", + "when": 1740860314823, + "tag": "0067_goofy_red_skull", + "breakpoints": true } ] } \ No newline at end of file diff --git a/apps/dokploy/package.json b/apps/dokploy/package.json index 5f59efec..a1626fc4 100644 --- a/apps/dokploy/package.json +++ b/apps/dokploy/package.json @@ -36,7 +36,7 @@ "test": "vitest --config __test__/vitest.config.ts" }, "dependencies": { - "better-auth": "1.1.16", + "better-auth": "beta", "bl": "6.0.11", "rotating-file-stream": "3.2.3", "qrcode": "^1.5.3", diff --git a/packages/server/auth-schema.ts b/packages/server/auth-schema.ts index b9b682fb..a5829046 100644 --- a/packages/server/auth-schema.ts +++ b/packages/server/auth-schema.ts @@ -1,3 +1,11 @@ +// import { +// pgTable, +// text, +// integer, +// timestamp, +// boolean, +// } from "drizzle-orm/pg-core"; + // export const users_temp = pgTable("users_temp", { // id: text("id").primaryKey(), // name: text("name").notNull(), @@ -52,6 +60,32 @@ // updatedAt: timestamp("updated_at"), // }); +// export const apikey = pgTable("apikey", { +// id: text("id").primaryKey(), +// name: text("name"), +// start: text("start"), +// prefix: text("prefix"), +// key: text("key").notNull(), +// userId: text("user_id") +// .notNull() +// .references(() => user.id, { onDelete: "cascade" }), +// refillInterval: integer("refill_interval"), +// refillAmount: integer("refill_amount"), +// lastRefillAt: timestamp("last_refill_at"), +// enabled: boolean("enabled"), +// rateLimitEnabled: boolean("rate_limit_enabled"), +// rateLimitTimeWindow: integer("rate_limit_time_window"), +// rateLimitMax: integer("rate_limit_max"), +// requestCount: integer("request_count"), +// remaining: integer("remaining"), +// lastRequest: timestamp("last_request"), +// expiresAt: timestamp("expires_at"), +// createdAt: timestamp("created_at").notNull(), +// updatedAt: timestamp("updated_at").notNull(), +// permissions: text("permissions"), +// metadata: text("metadata"), +// }); + // export const twoFactor = pgTable("two_factor", { // id: text("id").primaryKey(), // secret: text("secret").notNull(), @@ -79,6 +113,7 @@ // .notNull() // .references(() => user.id, { onDelete: "cascade" }), // role: text("role").notNull(), +// teamId: text("team_id"), // createdAt: timestamp("created_at").notNull(), // }); @@ -89,6 +124,7 @@ // .references(() => organization.id, { onDelete: "cascade" }), // email: text("email").notNull(), // role: text("role"), +// teamId: text("team_id"), // status: text("status").notNull(), // expiresAt: timestamp("expires_at").notNull(), // inviterId: text("inviter_id") diff --git a/packages/server/package.json b/packages/server/package.json index dbc24375..bd2d9ed0 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -32,7 +32,7 @@ "@oslojs/encoding":"1.1.0", "@oslojs/crypto":"1.0.1", "drizzle-dbml-generator":"0.10.0", - "better-auth":"1.1.16", + "better-auth":"beta", "rotating-file-stream": "3.2.3", "@faker-js/faker": "^8.4.1", "@lucia-auth/adapter-drizzle": "1.0.7", diff --git a/packages/server/src/db/schema/account.ts b/packages/server/src/db/schema/account.ts index 9d55016d..e5f2dab7 100644 --- a/packages/server/src/db/schema/account.ts +++ b/packages/server/src/db/schema/account.ts @@ -1,5 +1,11 @@ import { relations, sql } from "drizzle-orm"; -import { boolean, pgTable, text, timestamp } from "drizzle-orm/pg-core"; +import { + boolean, + integer, + pgTable, + text, + timestamp, +} from "drizzle-orm/pg-core"; import { nanoid } from "nanoid"; import { projects } from "./project"; import { server } from "./server"; @@ -87,7 +93,7 @@ export const member = pgTable("member", { .references(() => users_temp.id, { onDelete: "cascade" }), role: text("role").notNull().$type<"owner" | "member" | "admin">(), createdAt: timestamp("created_at").notNull(), - + teamId: text("team_id"), // Permissions canCreateProjects: boolean("canCreateProjects").notNull().default(false), canAccessToSSHKeys: boolean("canAccessToSSHKeys").notNull().default(false), @@ -135,6 +141,7 @@ export const invitation = pgTable("invitation", { inviterId: text("inviter_id") .notNull() .references(() => users_temp.id, { onDelete: "cascade" }), + teamId: text("team_id"), }); export const invitationRelations = relations(invitation, ({ one }) => ({ @@ -152,3 +159,29 @@ export const twoFactor = pgTable("two_factor", { .notNull() .references(() => users_temp.id, { onDelete: "cascade" }), }); + +export const apikey = pgTable("apikey", { + id: text("id").primaryKey(), + name: text("name"), + start: text("start"), + prefix: text("prefix"), + key: text("key").notNull(), + userId: text("user_id") + .notNull() + .references(() => users_temp.id, { onDelete: "cascade" }), + refillInterval: integer("refill_interval"), + refillAmount: integer("refill_amount"), + lastRefillAt: timestamp("last_refill_at"), + enabled: boolean("enabled"), + rateLimitEnabled: boolean("rate_limit_enabled"), + rateLimitTimeWindow: integer("rate_limit_time_window"), + rateLimitMax: integer("rate_limit_max"), + requestCount: integer("request_count"), + remaining: integer("remaining"), + lastRequest: timestamp("last_request"), + expiresAt: timestamp("expires_at"), + createdAt: timestamp("created_at").notNull(), + updatedAt: timestamp("updated_at").notNull(), + permissions: text("permissions"), + metadata: text("metadata"), +}); diff --git a/packages/server/src/lib/auth.ts b/packages/server/src/lib/auth.ts index 24e23bfd..bebcd54e 100644 --- a/packages/server/src/lib/auth.ts +++ b/packages/server/src/lib/auth.ts @@ -2,14 +2,14 @@ import type { IncomingMessage } from "node:http"; import * as bcrypt from "bcrypt"; import { betterAuth } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; -import { organization, twoFactor } from "better-auth/plugins"; +import { organization, twoFactor, apiKey } from "better-auth/plugins"; import { and, desc, eq } from "drizzle-orm"; import { db } from "../db"; import * as schema from "../db/schema"; import { sendEmail } from "../verification/send-verification-email"; import { IS_CLOUD } from "../constants"; -const { handler, api } = betterAuth({ +export const auth = betterAuth({ database: drizzleAdapter(db, { provider: "pg", schema: schema, @@ -126,6 +126,7 @@ const { handler, api } = betterAuth({ }, plugins: [ + apiKey(), twoFactor(), organization({ async sendInvitationEmail(data, _request) { @@ -144,9 +145,9 @@ const { handler, api } = betterAuth({ ], }); -export const auth = { - handler, -}; +// export const auth = { +// handler, +// }; export const validateRequest = async (request: IncomingMessage) => { const session = await api.getSession({ diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ee68b399..6e1c088b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -239,8 +239,8 @@ importers: specifier: 5.1.1 version: 5.1.1(encoding@0.1.13) better-auth: - specifier: 1.1.16 - version: 1.1.16 + specifier: beta + version: 1.2.0-beta.18(typescript@5.5.3) bl: specifier: 6.0.11 version: 6.0.11 @@ -580,8 +580,8 @@ importers: specifier: 5.1.1 version: 5.1.1(encoding@0.1.13) better-auth: - specifier: 1.1.16 - version: 1.1.16 + specifier: beta + version: 1.2.0-beta.18(typescript@5.5.3) bl: specifier: 6.0.11 version: 6.0.11 @@ -769,8 +769,8 @@ packages: '@better-auth/utils@0.2.3': resolution: {integrity: sha512-Ap1GaSmo6JYhJhxJOpUB0HobkKPTNzfta+bLV89HfpyCAHN7p8ntCrmNFHNAVD0F6v0mywFVEUg1FUhNCc81Rw==} - '@better-fetch/fetch@1.1.12': - resolution: {integrity: sha512-B3bfloI/2UBQWIATRN6qmlORrvx3Mp0kkNjmXLv0b+DtbtR+pP4/I5kQA/rDUv+OReLywCCldf6co4LdDmh8JA==} + '@better-fetch/fetch@1.1.15': + resolution: {integrity: sha512-0Bl8YYj1f8qCTNHeSn5+1DWv2hy7rLBrQ8rS8Y9XYloiwZEfc3k4yspIG0llRxafxqhGCwlGRg+F8q1HZRCMXA==} '@biomejs/biome@1.9.4': resolution: {integrity: sha512-1rkd7G70+o9KkTn5KLmDYXihGoTaIGO9PIIN2ZB7UJxFrWw04CZHPYiMRjYsaDvVV7hP1dYNRLxSANLaBFGpog==} @@ -3879,11 +3879,11 @@ packages: before-after-hook@2.2.3: resolution: {integrity: sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==} - better-auth@1.1.16: - resolution: {integrity: sha512-Xc5pxafKZw4QVU8WYfkV2z4Hd8KCXXbphrgOpe2gA/EfanysLBhE1G/F7cEi5e0bW2pGR+vw6gf0ARHA7VFihg==} + better-auth@1.2.0-beta.18: + resolution: {integrity: sha512-gEjNxmrkFiATTSTcE47rkyTT9vMFMLTjtLNun4W0IWmeqfi4pIbbWpo97foY1DNXXRDkDuajquoD58dzAatQxQ==} - better-call@0.3.3: - resolution: {integrity: sha512-N4lDVm0NGmFfDJ0XMQ4O83Zm/3dPlvIQdxvwvgSLSkjFX5PM4GUYSVAuxNzXN27QZMHDkrJTWUqxBrm4tPC3eA==} + better-call@1.0.3: + resolution: {integrity: sha512-DUKImKoDIy5UtCvQbHTg0wuBRse6gu1Yvznn7+1B3I5TeY8sclRPFce0HI+4WF2bcb+9PqmkET8nXZubrHQh9A==} binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} @@ -6567,6 +6567,9 @@ packages: set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + set-cookie-parser@2.7.1: + resolution: {integrity: sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==} + set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -7114,6 +7117,14 @@ packages: v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + valibot@1.0.0-beta.15: + resolution: {integrity: sha512-BKy8XosZkDHWmYC+cJG74LBzP++Gfntwi33pP3D3RKztz2XV9jmFWnkOi21GoqARP8wAWARwhV6eTr1JcWzjGw==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true + victory-vendor@36.9.2: resolution: {integrity: sha512-PnpQQMuxlwYdocC8fIJqVXvkeViHYzotI+NJrCuav0ZYFoq912ZHBk3mCeuj+5/VpodOjPe1z0Fk2ihgzlXqjQ==} @@ -7383,7 +7394,7 @@ snapshots: dependencies: uncrypto: 0.1.3 - '@better-fetch/fetch@1.1.12': {} + '@better-fetch/fetch@1.1.15': {} '@biomejs/biome@1.9.4': optionalDependencies: @@ -10543,27 +10554,30 @@ snapshots: before-after-hook@2.2.3: {} - better-auth@1.1.16: + better-auth@1.2.0-beta.18(typescript@5.5.3): dependencies: '@better-auth/utils': 0.2.3 - '@better-fetch/fetch': 1.1.12 + '@better-fetch/fetch': 1.1.15 '@noble/ciphers': 0.6.0 '@noble/hashes': 1.7.1 '@simplewebauthn/browser': 13.1.0 '@simplewebauthn/server': 13.1.1 - better-call: 0.3.3 + better-call: 1.0.3 defu: 6.1.4 jose: 5.9.6 kysely: 0.27.5 nanostores: 0.11.3 + valibot: 1.0.0-beta.15(typescript@5.5.3) zod: 3.24.1 + transitivePeerDependencies: + - typescript - better-call@0.3.3: + better-call@1.0.3: dependencies: - '@better-fetch/fetch': 1.1.12 + '@better-fetch/fetch': 1.1.15 rou3: 0.5.1 + set-cookie-parser: 2.7.1 uncrypto: 0.1.3 - zod: 3.24.1 binary-extensions@2.3.0: {} @@ -13338,6 +13352,8 @@ snapshots: set-blocking@2.0.0: {} + set-cookie-parser@2.7.1: {} + set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -13970,6 +13986,10 @@ snapshots: v8-compile-cache-lib@3.0.1: optional: true + valibot@1.0.0-beta.15(typescript@5.5.3): + optionalDependencies: + typescript: 5.5.3 + victory-vendor@36.9.2: dependencies: '@types/d3-array': 3.2.1