refactor: organize imports and improve template utility modules

This commit is contained in:
Mauricio Siu
2025-03-01 14:45:50 -06:00
parent 37ca8f41f5
commit 5568629839
9 changed files with 320 additions and 41 deletions

View File

@@ -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

View File

@@ -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"
}
},

View File

@@ -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
}
]
}

View File

@@ -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",

View File

@@ -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")

View File

@@ -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",

View File

@@ -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"),
});

View File

@@ -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({

54
pnpm-lock.yaml generated
View File

@@ -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