From fae33f4d47b7d99ada23e9648e3abd45470a69ae Mon Sep 17 00:00:00 2001 From: HimanshuKumarDutt094 Date: Sun, 23 Nov 2025 11:28:43 +0530 Subject: [PATCH 01/29] feat: prisma v7 cherry picking stuff --- cli/src/installers/dependencyVersionMap.ts | 14 ++- cli/src/installers/prisma.ts | 95 ++++++++++++++++--- cli/template/extras/config/prisma.config.ts | 13 +++ .../prisma/schema/base-planetscale.prisma | 1 - cli/template/extras/prisma/schema/base.prisma | 3 +- .../schema/with-auth-planetscale.prisma | 3 +- .../extras/prisma/schema/with-auth.prisma | 3 +- .../with-better-auth-planetscale.prisma | 3 +- .../prisma/schema/with-better-auth.prisma | 3 +- .../extras/src/server/db/db-prisma-mysql.ts | 40 ++++++++ .../src/server/db/db-prisma-planetscale.ts | 10 +- .../src/server/db/db-prisma-postgres.ts | 22 +++++ .../extras/src/server/db/db-prisma-sqlite.ts | 22 +++++ 13 files changed, 200 insertions(+), 32 deletions(-) create mode 100644 cli/template/extras/config/prisma.config.ts create mode 100644 cli/template/extras/src/server/db/db-prisma-mysql.ts create mode 100644 cli/template/extras/src/server/db/db-prisma-postgres.ts create mode 100644 cli/template/extras/src/server/db/db-prisma-sqlite.ts diff --git a/cli/src/installers/dependencyVersionMap.ts b/cli/src/installers/dependencyVersionMap.ts index dd738069f9..06ef9def5d 100644 --- a/cli/src/installers/dependencyVersionMap.ts +++ b/cli/src/installers/dependencyVersionMap.ts @@ -12,9 +12,17 @@ export const dependencyVersionMap = { "better-auth": "^1.3", // Prisma - prisma: "^6.6.0", - "@prisma/client": "^6.6.0", - "@prisma/adapter-planetscale": "^6.6.0", + prisma: "^7.0.0", + "@prisma/client": "^7.0.0", + "@prisma/adapter-planetscale": "^7.0.0", + "@prisma/adapter-pg": "^7.0.0", + "@prisma/adapter-mariadb": "^7.0.0", + "@prisma/adapter-better-sqlite3": "^7.0.0", + pg: "^8.13.1", + "@types/pg": "^8.11.10", + "@types/better-sqlite3": "^7.6.11", + "@types/node": "^22.10.5", + "dotenv-cli": "^8.0.0", // Drizzle "drizzle-kit": "^0.30.5", diff --git a/cli/src/installers/prisma.ts b/cli/src/installers/prisma.ts index fdd4044a69..725202a234 100644 --- a/cli/src/installers/prisma.ts +++ b/cli/src/installers/prisma.ts @@ -2,15 +2,46 @@ import path from "path"; import fs from "fs-extra"; import { PKG_ROOT } from "~/consts.js"; -import { type Installer } from "~/installers/index.js"; +import { type AvailableDependencies } from "~/installers/dependencyVersionMap.js"; +import { type DatabaseProvider, type Installer } from "~/installers/index.js"; import { addPackageDependency } from "~/utils/addPackageDependency.js"; import { addPackageScript } from "~/utils/addPackageScript.js"; +// Provider-specific dependency map +interface ProviderDependencies { + adapter: AvailableDependencies; + driver?: AvailableDependencies; + types: AvailableDependencies[]; +} + +const providerDependencyMap: Record = { + postgres: { + adapter: "@prisma/adapter-pg", + driver: "pg", + types: ["@types/pg"], + }, + mysql: { + adapter: "@prisma/adapter-mariadb", + types: ["@types/node"], + }, + sqlite: { + adapter: "@prisma/adapter-better-sqlite3", + types: ["@types/better-sqlite3"], + }, + planetscale: { + adapter: "@prisma/adapter-planetscale", + driver: "@planetscale/database", + types: ["@types/node"], + }, +}; + export const prismaInstaller: Installer = ({ projectDir, packages, + pkgManager, databaseProvider, }) => { + // Install base Prisma v7 packages addPackageDependency({ projectDir, dependencies: ["prisma"], @@ -21,15 +52,47 @@ export const prismaInstaller: Installer = ({ dependencies: ["@prisma/client"], devMode: false, }); - if (databaseProvider === "planetscale") + + // Install dotenv-cli as dev dependency + addPackageDependency({ + projectDir, + dependencies: ["dotenv-cli"], + devMode: true, + }); + + // Get provider-specific dependencies + const providerDeps = providerDependencyMap[databaseProvider]; + + // Install provider-specific adapter package + addPackageDependency({ + projectDir, + dependencies: [providerDeps.adapter], + devMode: false, + }); + + // Install provider-specific driver package (if required) + if (providerDeps.driver) { addPackageDependency({ projectDir, - dependencies: ["@prisma/adapter-planetscale", "@planetscale/database"], + dependencies: [providerDeps.driver], devMode: false, }); + } + + // Install provider-specific TypeScript types + addPackageDependency({ + projectDir, + dependencies: providerDeps.types, + devMode: true, + }); const extrasDir = path.join(PKG_ROOT, "template/extras"); + // Copy universal prisma.config.ts to project root + const prismaConfigSrc = path.join(extrasDir, "config/prisma.config.ts"); + const prismaConfigDest = path.join(projectDir, "prisma.config.ts"); + fs.copySync(prismaConfigSrc, prismaConfigDest); + const schemaBaseName = packages?.betterAuth.inUse ? "with-better-auth" : packages?.nextAuth.inUse @@ -62,22 +125,26 @@ export const prismaInstaller: Installer = ({ fs.mkdirSync(path.dirname(schemaDest), { recursive: true }); fs.writeFileSync(schemaDest, schemaText); - const clientSrc = path.join( - extrasDir, - databaseProvider === "planetscale" - ? "src/server/db/db-prisma-planetscale.ts" - : "src/server/db/db-prisma.ts" - ); + // Select and copy correct db client template based on provider + const dbClientTemplateMap: Record = { + postgres: "src/server/db/db-prisma-postgres.ts", + mysql: "src/server/db/db-prisma-mysql.ts", + sqlite: "src/server/db/db-prisma-sqlite.ts", + planetscale: "src/server/db/db-prisma-planetscale.ts", + }; + + const clientSrc = path.join(extrasDir, dbClientTemplateMap[databaseProvider]); const clientDest = path.join(projectDir, "src/server/db.ts"); addPackageScript({ projectDir, scripts: { - postinstall: "prisma generate", - "db:push": "prisma db push", - "db:studio": "prisma studio", - "db:generate": "prisma migrate dev", - "db:migrate": "prisma migrate deploy", + "with-env": "dotenv -e .env --", + postinstall: `${pkgManager} run with-env prisma generate`, + "db:push": `${pkgManager} run with-env prisma db push`, + "db:studio": `${pkgManager} run with-env prisma studio`, + "db:generate": `${pkgManager} run with-env prisma migrate dev`, + "db:migrate": `${pkgManager} run with-env prisma migrate deploy`, }, }); diff --git a/cli/template/extras/config/prisma.config.ts b/cli/template/extras/config/prisma.config.ts new file mode 100644 index 0000000000..30c6267884 --- /dev/null +++ b/cli/template/extras/config/prisma.config.ts @@ -0,0 +1,13 @@ +import { defineConfig } from "prisma/config"; + +import { env } from "./src/env"; + +export default defineConfig({ + schema: "prisma/schema.prisma", + migrations: { + path: "prisma/migrations", + }, + datasource: { + url: env.DATABASE_URL, + }, +}); diff --git a/cli/template/extras/prisma/schema/base-planetscale.prisma b/cli/template/extras/prisma/schema/base-planetscale.prisma index d46d9af07c..0d8c1bb238 100644 --- a/cli/template/extras/prisma/schema/base-planetscale.prisma +++ b/cli/template/extras/prisma/schema/base-planetscale.prisma @@ -9,7 +9,6 @@ generator client { datasource db { provider = "mysql" - url = env("DATABASE_URL") // If you have enabled foreign key constraints for your database, remove this line. relationMode = "prisma" diff --git a/cli/template/extras/prisma/schema/base.prisma b/cli/template/extras/prisma/schema/base.prisma index 7b1a4ddd4f..b2e3d04c1e 100644 --- a/cli/template/extras/prisma/schema/base.prisma +++ b/cli/template/extras/prisma/schema/base.prisma @@ -2,13 +2,12 @@ // learn more about it in the docs: https://pris.ly/d/prisma-schema generator client { - provider = "prisma-client-js" + provider = "prisma-client" output = "../generated/prisma" } datasource db { provider = "sqlite" - url = env("DATABASE_URL") } model Post { diff --git a/cli/template/extras/prisma/schema/with-auth-planetscale.prisma b/cli/template/extras/prisma/schema/with-auth-planetscale.prisma index 98798d5e0c..40850aaf76 100644 --- a/cli/template/extras/prisma/schema/with-auth-planetscale.prisma +++ b/cli/template/extras/prisma/schema/with-auth-planetscale.prisma @@ -2,7 +2,7 @@ // learn more about it in the docs: https://pris.ly/d/prisma-schema generator client { - provider = "prisma-client-js" + provider = "prisma-client" output = "../generated/prisma" previewFeatures = ["driverAdapters"] @@ -10,7 +10,6 @@ generator client { datasource db { provider = "mysql" - url = env("DATABASE_URL") // If you have enabled foreign key constraints for your database, remove this line. relationMode = "prisma" diff --git a/cli/template/extras/prisma/schema/with-auth.prisma b/cli/template/extras/prisma/schema/with-auth.prisma index 94a918ef14..973bdc412b 100644 --- a/cli/template/extras/prisma/schema/with-auth.prisma +++ b/cli/template/extras/prisma/schema/with-auth.prisma @@ -2,7 +2,7 @@ // learn more about it in the docs: https://pris.ly/d/prisma-schema generator client { - provider = "prisma-client-js" + provider = "prisma-client" output = "../generated/prisma" } @@ -12,7 +12,6 @@ datasource db { // Further reading: // https://next-auth.js.org/adapters/prisma#create-the-prisma-schema // https://www.prisma.io/docs/reference/api-reference/prisma-schema-reference#string - url = env("DATABASE_URL") } model Post { diff --git a/cli/template/extras/prisma/schema/with-better-auth-planetscale.prisma b/cli/template/extras/prisma/schema/with-better-auth-planetscale.prisma index a008971f46..f3d14be5f4 100644 --- a/cli/template/extras/prisma/schema/with-better-auth-planetscale.prisma +++ b/cli/template/extras/prisma/schema/with-better-auth-planetscale.prisma @@ -2,7 +2,7 @@ // learn more: https://better-auth.com/docs/concepts/database generator client { - provider = "prisma-client-js" + provider = "prisma-client" output = "../generated/prisma" } @@ -13,7 +13,6 @@ generator client { datasource db { provider = "mysql" relationMode = "prisma" - url = env("DATABASE_URL") } model Post { diff --git a/cli/template/extras/prisma/schema/with-better-auth.prisma b/cli/template/extras/prisma/schema/with-better-auth.prisma index 9c0c418698..d8384128cf 100644 --- a/cli/template/extras/prisma/schema/with-better-auth.prisma +++ b/cli/template/extras/prisma/schema/with-better-auth.prisma @@ -2,7 +2,7 @@ // learn more: https://better-auth.com/docs/concepts/database generator client { - provider = "prisma-client-js" + provider = "prisma-client" output = "../generated/prisma" } @@ -12,7 +12,6 @@ generator client { datasource db { provider = "sqlite" - url = env("DATABASE_URL") } model Post { diff --git a/cli/template/extras/src/server/db/db-prisma-mysql.ts b/cli/template/extras/src/server/db/db-prisma-mysql.ts new file mode 100644 index 0000000000..5269e25baf --- /dev/null +++ b/cli/template/extras/src/server/db/db-prisma-mysql.ts @@ -0,0 +1,40 @@ +import { PrismaMariaDb } from "@prisma/adapter-mariadb"; + +import { env } from "~/env"; +import { PrismaClient } from "../../generated/prisma/client"; + +/** + * Parse MySQL connection URL to extract connection parameters + * Format: mysql://username:password@host:port/database + */ +function parseMySQLUrl(url: string) { + const parsed = new URL(url); + return { + host: parsed.hostname, + user: parsed.username, + password: parsed.password, + database: parsed.pathname.slice(1), // Remove leading slash + port: parsed.port ? parseInt(parsed.port, 10) : 3306, + }; +} + +const createPrismaClient = () => { + const connectionParams = parseMySQLUrl(env.DATABASE_URL); + const adapter = new PrismaMariaDb({ + ...connectionParams, + connectionLimit: 5, + }); + return new PrismaClient({ + adapter, + log: + env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"], + }); +}; + +const globalForPrisma = globalThis as unknown as { + prisma: ReturnType | undefined; +}; + +export const db = globalForPrisma.prisma ?? createPrismaClient(); + +if (env.NODE_ENV !== "production") globalForPrisma.prisma = db; diff --git a/cli/template/extras/src/server/db/db-prisma-planetscale.ts b/cli/template/extras/src/server/db/db-prisma-planetscale.ts index 3cc171d9ee..97442c2a56 100644 --- a/cli/template/extras/src/server/db/db-prisma-planetscale.ts +++ b/cli/template/extras/src/server/db/db-prisma-planetscale.ts @@ -1,14 +1,16 @@ import { PrismaPlanetScale } from "@prisma/adapter-planetscale"; import { env } from "~/env"; -import { PrismaClient } from "../../generated/prisma"; +import { PrismaClient } from "../../generated/prisma/client"; -const createPrismaClient = () => - new PrismaClient({ +const createPrismaClient = () => { + const adapter = new PrismaPlanetScale({ url: env.DATABASE_URL }); + return new PrismaClient({ + adapter, log: env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"], - adapter: new PrismaPlanetScale({ url: env.DATABASE_URL }), }); +}; const globalForPrisma = globalThis as unknown as { prisma: ReturnType | undefined; diff --git a/cli/template/extras/src/server/db/db-prisma-postgres.ts b/cli/template/extras/src/server/db/db-prisma-postgres.ts new file mode 100644 index 0000000000..399de79e22 --- /dev/null +++ b/cli/template/extras/src/server/db/db-prisma-postgres.ts @@ -0,0 +1,22 @@ +import { PrismaPg } from "@prisma/adapter-pg"; + +import { env } from "~/env"; +import { PrismaClient } from "../../generated/prisma/client"; + +const createPrismaClient = () => { + const connectionString = env.DATABASE_URL; + const adapter = new PrismaPg({ connectionString }); + return new PrismaClient({ + adapter, + log: + env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"], + }); +}; + +const globalForPrisma = globalThis as unknown as { + prisma: ReturnType | undefined; +}; + +export const db = globalForPrisma.prisma ?? createPrismaClient(); + +if (env.NODE_ENV !== "production") globalForPrisma.prisma = db; diff --git a/cli/template/extras/src/server/db/db-prisma-sqlite.ts b/cli/template/extras/src/server/db/db-prisma-sqlite.ts new file mode 100644 index 0000000000..450d78ffce --- /dev/null +++ b/cli/template/extras/src/server/db/db-prisma-sqlite.ts @@ -0,0 +1,22 @@ +import { PrismaBetterSqlite3 } from "@prisma/adapter-better-sqlite3"; + +import { env } from "~/env"; +import { PrismaClient } from "../../generated/prisma/client"; + +const createPrismaClient = () => { + const connectionString = `${env.DATABASE_URL}`; + const adapter = new PrismaBetterSqlite3({ url: connectionString }); + return new PrismaClient({ + adapter, + log: + env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"], + }); +}; + +const globalForPrisma = globalThis as unknown as { + prisma: ReturnType | undefined; +}; + +export const db = globalForPrisma.prisma ?? createPrismaClient(); + +if (env.NODE_ENV !== "production") globalForPrisma.prisma = db; From abcda507d8d29cf4012fd9a209e4996ce4229f5d Mon Sep 17 00:00:00 2001 From: HimanshuKumarDutt094 Date: Sun, 23 Nov 2025 11:51:57 +0530 Subject: [PATCH 02/29] feat: prisma v7 fix --- cli/src/installers/prisma.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/src/installers/prisma.ts b/cli/src/installers/prisma.ts index 725202a234..0c6d2e0cdf 100644 --- a/cli/src/installers/prisma.ts +++ b/cli/src/installers/prisma.ts @@ -140,7 +140,7 @@ export const prismaInstaller: Installer = ({ projectDir, scripts: { "with-env": "dotenv -e .env --", - postinstall: `${pkgManager} run with-env prisma generate`, + postinstall: `SKIP_ENV_VALIDATION=1 ${pkgManager} run with-env prisma generate`, "db:push": `${pkgManager} run with-env prisma db push`, "db:studio": `${pkgManager} run with-env prisma studio`, "db:generate": `${pkgManager} run with-env prisma migrate dev`, From 66e55c8a43411992cda73607fd5dbc0fdb001ff6 Mon Sep 17 00:00:00 2001 From: HimanshuKumarDutt094 Date: Sun, 23 Nov 2025 12:54:30 +0530 Subject: [PATCH 03/29] fix: postinstall for prisma generate --- cli/src/index.ts | 5 ++++- cli/src/installers/prisma.ts | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cli/src/index.ts b/cli/src/index.ts index 47dce51954..c0df0b2e31 100644 --- a/cli/src/index.ts +++ b/cli/src/index.ts @@ -87,7 +87,10 @@ const main = async () => { if (usePackages.prisma.inUse) { logger.info("Generating Prisma client..."); - await execa("npx", ["prisma", "generate"], { cwd: projectDir }); + await execa(pkgManager, ["run", "with-env", "prisma", "generate"], { + cwd: projectDir, + env: { SKIP_ENV_VALIDATION: "1" }, + }); logger.info("Successfully generated Prisma client!"); } diff --git a/cli/src/installers/prisma.ts b/cli/src/installers/prisma.ts index 0c6d2e0cdf..725202a234 100644 --- a/cli/src/installers/prisma.ts +++ b/cli/src/installers/prisma.ts @@ -140,7 +140,7 @@ export const prismaInstaller: Installer = ({ projectDir, scripts: { "with-env": "dotenv -e .env --", - postinstall: `SKIP_ENV_VALIDATION=1 ${pkgManager} run with-env prisma generate`, + postinstall: `${pkgManager} run with-env prisma generate`, "db:push": `${pkgManager} run with-env prisma db push`, "db:studio": `${pkgManager} run with-env prisma studio`, "db:generate": `${pkgManager} run with-env prisma migrate dev`, From f4a3768b74950125ccb4ed83190ccd054dbf2992 Mon Sep 17 00:00:00 2001 From: HimanshuKumarDutt094 Date: Sun, 23 Nov 2025 13:13:57 +0530 Subject: [PATCH 04/29] fix: remove driver adapter --- cli/template/extras/prisma/schema/base-planetscale.prisma | 5 ++--- .../extras/prisma/schema/with-auth-planetscale.prisma | 2 -- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/cli/template/extras/prisma/schema/base-planetscale.prisma b/cli/template/extras/prisma/schema/base-planetscale.prisma index 0d8c1bb238..2cebeee506 100644 --- a/cli/template/extras/prisma/schema/base-planetscale.prisma +++ b/cli/template/extras/prisma/schema/base-planetscale.prisma @@ -2,9 +2,8 @@ // learn more about it in the docs: https://pris.ly/d/prisma-schema generator client { - provider = "prisma-client-js" - previewFeatures = ["driverAdapters"] - output = "../generated/prisma" + provider = "prisma-client" + output = "../generated/prisma" } datasource db { diff --git a/cli/template/extras/prisma/schema/with-auth-planetscale.prisma b/cli/template/extras/prisma/schema/with-auth-planetscale.prisma index 40850aaf76..75fed2faa0 100644 --- a/cli/template/extras/prisma/schema/with-auth-planetscale.prisma +++ b/cli/template/extras/prisma/schema/with-auth-planetscale.prisma @@ -4,8 +4,6 @@ generator client { provider = "prisma-client" output = "../generated/prisma" - - previewFeatures = ["driverAdapters"] } datasource db { From 40564c968acabdd1ec5f2256ed4be08e8c6ad998 Mon Sep 17 00:00:00 2001 From: HimanshuKumarDutt094 Date: Sat, 22 Nov 2025 16:59:33 +0530 Subject: [PATCH 05/29] bump:better-auth 1.4, fix: drizzle better-auth db schemas --- cli/package.json | 2 +- cli/src/installers/dependencyVersionMap.ts | 2 +- .../schema-drizzle/with-better-auth-mysql.ts | 152 +++++++------- .../with-better-auth-planetscale.ts | 149 +++++++------- .../with-better-auth-postgres.ts | 137 +++++++------ .../schema-drizzle/with-better-auth-sqlite.ts | 191 +++++++++--------- 6 files changed, 333 insertions(+), 300 deletions(-) diff --git a/cli/package.json b/cli/package.json index 5b40bfb4ea..bba1804f93 100644 --- a/cli/package.json +++ b/cli/package.json @@ -78,7 +78,7 @@ "@types/fs-extra": "^11.0.4", "@types/gradient-string": "^1.1.6", "@types/node": "^20.14.10", - "better-auth": "^1.3", + "better-auth": "^1.4.0", "drizzle-kit": "^0.30.5", "drizzle-orm": "^0.41.0", "mysql2": "^3.11.0", diff --git a/cli/src/installers/dependencyVersionMap.ts b/cli/src/installers/dependencyVersionMap.ts index 06ef9def5d..cea77e506b 100644 --- a/cli/src/installers/dependencyVersionMap.ts +++ b/cli/src/installers/dependencyVersionMap.ts @@ -9,7 +9,7 @@ export const dependencyVersionMap = { "@auth/drizzle-adapter": "^1.7.2", // Better-Auth - "better-auth": "^1.3", + "better-auth": "^1.4.0", // Prisma prisma: "^7.0.0", diff --git a/cli/template/extras/src/server/db/schema-drizzle/with-better-auth-mysql.ts b/cli/template/extras/src/server/db/schema-drizzle/with-better-auth-mysql.ts index f4357c066e..cc29d470ad 100644 --- a/cli/template/extras/src/server/db/schema-drizzle/with-better-auth-mysql.ts +++ b/cli/template/extras/src/server/db/schema-drizzle/with-better-auth-mysql.ts @@ -1,30 +1,22 @@ import { relations } from "drizzle-orm"; -import { - boolean, - index, - mysqlTable, - mysqlTableCreator, - text, - timestamp, - varchar, -} from "drizzle-orm/mysql-core"; +import { index, mysqlTableCreator } from "drizzle-orm/mysql-core"; export const createTable = mysqlTableCreator((name) => `project1_${name}`); export const posts = createTable( "post", (d) => ({ - id: d.bigint({ mode: "number" }).primaryKey().autoincrement(), - name: d.varchar({ length: 256 }), + id: d.bigint("id", { mode: "number" }).primaryKey().autoincrement(), + name: d.varchar("name", { length: 256 }), createdById: d - .varchar({ length: 255 }) + .varchar("created_by_id", { length: 255 }) .notNull() .references(() => user.id), - createdAt: d - .timestamp() - .$defaultFn(() => /* @__PURE__ */ new Date()) + createdAt: d.timestamp("created_at", { fsp: 3 }).defaultNow().notNull(), + updatedAt: d + .timestamp("updated_at", { fsp: 3 }) + .$onUpdate(() => /* @__PURE__ */ new Date()) .notNull(), - updatedAt: d.timestamp().onUpdateNow(), }), (t) => [ index("created_by_idx").on(t.createdById), @@ -32,65 +24,83 @@ export const posts = createTable( ] ); -export const user = mysqlTable("user", { - id: varchar("id", { length: 36 }).primaryKey(), - name: text("name").notNull(), - email: varchar("email", { length: 255 }).notNull().unique(), - emailVerified: boolean("email_verified") - .$defaultFn(() => false) +export const user = createTable("user", (d) => ({ + id: d.varchar("id", { length: 36 }).primaryKey(), + name: d.varchar("name", { length: 255 }).notNull(), + email: d.varchar("email", { length: 255 }).notNull().unique(), + emailVerified: d.boolean("email_verified").default(false).notNull(), + image: d.text("image"), + createdAt: d.timestamp("created_at", { fsp: 3 }).defaultNow().notNull(), + updatedAt: d + .timestamp("updated_at", { fsp: 3 }) + .defaultNow() + .$onUpdate(() => /* @__PURE__ */ new Date()) .notNull(), - image: text("image"), - createdAt: timestamp("created_at") - .$defaultFn(() => /* @__PURE__ */ new Date()) - .notNull(), - updatedAt: timestamp("updated_at") - .$defaultFn(() => /* @__PURE__ */ new Date()) - .notNull(), -}); +})); -export const session = mysqlTable("session", { - id: varchar("id", { length: 36 }).primaryKey(), - expiresAt: timestamp("expires_at").notNull(), - token: varchar("token", { length: 255 }).notNull().unique(), - createdAt: timestamp("created_at").notNull(), - updatedAt: timestamp("updated_at").notNull(), - ipAddress: text("ip_address"), - userAgent: text("user_agent"), - userId: varchar("user_id", { length: 36 }) - .notNull() - .references(() => user.id, { onDelete: "cascade" }), -}); +export const session = createTable( + "session", + (d) => ({ + id: d.varchar("id", { length: 36 }).primaryKey(), + expiresAt: d.timestamp("expires_at", { fsp: 3 }).notNull(), + token: d.varchar("token", { length: 255 }).notNull().unique(), + createdAt: d.timestamp("created_at", { fsp: 3 }).defaultNow().notNull(), + updatedAt: d + .timestamp("updated_at", { fsp: 3 }) + .$onUpdate(() => /* @__PURE__ */ new Date()) + .notNull(), + ipAddress: d.text("ip_address"), + userAgent: d.text("user_agent"), + userId: d + .varchar("user_id", { length: 36 }) + .notNull() + .references(() => user.id, { onDelete: "cascade" }), + }), + (table) => [index("session_user_id_idx").on(table.userId)] +); -export const account = mysqlTable("account", { - id: varchar("id", { length: 36 }).primaryKey(), - accountId: text("account_id").notNull(), - providerId: text("provider_id").notNull(), - userId: varchar("user_id", { length: 36 }) - .notNull() - .references(() => user.id, { onDelete: "cascade" }), - 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 account = createTable( + "account", + (d) => ({ + id: d.varchar("id", { length: 36 }).primaryKey(), + accountId: d.text("account_id").notNull(), + providerId: d.text("provider_id").notNull(), + userId: d + .varchar("user_id", { length: 36 }) + .notNull() + .references(() => user.id, { onDelete: "cascade" }), + accessToken: d.text("access_token"), + refreshToken: d.text("refresh_token"), + idToken: d.text("id_token"), + accessTokenExpiresAt: d.timestamp("access_token_expires_at", { fsp: 3 }), + refreshTokenExpiresAt: d.timestamp("refresh_token_expires_at", { fsp: 3 }), + scope: d.text("scope"), + password: d.text("password"), + createdAt: d.timestamp("created_at", { fsp: 3 }).defaultNow().notNull(), + updatedAt: d + .timestamp("updated_at", { fsp: 3 }) + .$onUpdate(() => /* @__PURE__ */ new Date()) + .notNull(), + }), + (table) => [index("account_user_id_idx").on(table.userId)] +); -export const verification = mysqlTable("verification", { - id: varchar("id", { length: 36 }).primaryKey(), - identifier: text("identifier").notNull(), - value: text("value").notNull(), - expiresAt: timestamp("expires_at").notNull(), - createdAt: timestamp("created_at").$defaultFn( - () => /* @__PURE__ */ new Date() - ), - updatedAt: timestamp("updated_at").$defaultFn( - () => /* @__PURE__ */ new Date() - ), -}); +export const verification = createTable( + "verification", + (d) => ({ + id: d.varchar("id", { length: 36 }).primaryKey(), + identifier: d.varchar("identifier", { length: 255 }).notNull(), + value: d.text("value").notNull(), + expiresAt: d.timestamp("expires_at", { fsp: 3 }).notNull(), + createdAt: d.timestamp("created_at", { fsp: 3 }).defaultNow().notNull(), + updatedAt: d + .timestamp("updated_at", { fsp: 3 }) + .defaultNow() + .$onUpdate(() => /* @__PURE__ */ new Date()) + .notNull(), + }), + (table) => [index("verification_identifier_idx").on(table.identifier)] +); export const usersRelations = relations(user, ({ many }) => ({ accounts: many(account), diff --git a/cli/template/extras/src/server/db/schema-drizzle/with-better-auth-planetscale.ts b/cli/template/extras/src/server/db/schema-drizzle/with-better-auth-planetscale.ts index f4357c066e..e23c73dcf3 100644 --- a/cli/template/extras/src/server/db/schema-drizzle/with-better-auth-planetscale.ts +++ b/cli/template/extras/src/server/db/schema-drizzle/with-better-auth-planetscale.ts @@ -1,30 +1,19 @@ import { relations } from "drizzle-orm"; -import { - boolean, - index, - mysqlTable, - mysqlTableCreator, - text, - timestamp, - varchar, -} from "drizzle-orm/mysql-core"; +import { index, mysqlTableCreator } from "drizzle-orm/mysql-core"; export const createTable = mysqlTableCreator((name) => `project1_${name}`); export const posts = createTable( "post", (d) => ({ - id: d.bigint({ mode: "number" }).primaryKey().autoincrement(), - name: d.varchar({ length: 256 }), - createdById: d - .varchar({ length: 255 }) - .notNull() - .references(() => user.id), - createdAt: d - .timestamp() - .$defaultFn(() => /* @__PURE__ */ new Date()) + id: d.bigint("id", { mode: "number" }).primaryKey().autoincrement(), + name: d.varchar("name", { length: 256 }), + createdById: d.varchar("created_by_id", { length: 255 }).notNull(), + createdAt: d.timestamp("created_at", { fsp: 3 }).defaultNow().notNull(), + updatedAt: d + .timestamp("updated_at", { fsp: 3 }) + .$onUpdate(() => /* @__PURE__ */ new Date()) .notNull(), - updatedAt: d.timestamp().onUpdateNow(), }), (t) => [ index("created_by_idx").on(t.createdById), @@ -32,65 +21,77 @@ export const posts = createTable( ] ); -export const user = mysqlTable("user", { - id: varchar("id", { length: 36 }).primaryKey(), - name: text("name").notNull(), - email: varchar("email", { length: 255 }).notNull().unique(), - emailVerified: boolean("email_verified") - .$defaultFn(() => false) +export const user = createTable("user", (d) => ({ + id: d.varchar("id", { length: 36 }).primaryKey(), + name: d.varchar("name", { length: 255 }).notNull(), + email: d.varchar("email", { length: 255 }).notNull().unique(), + emailVerified: d.boolean("email_verified").default(false).notNull(), + image: d.text("image"), + createdAt: d.timestamp("created_at", { fsp: 3 }).defaultNow().notNull(), + updatedAt: d + .timestamp("updated_at", { fsp: 3 }) + .defaultNow() + .$onUpdate(() => /* @__PURE__ */ new Date()) .notNull(), - image: text("image"), - createdAt: timestamp("created_at") - .$defaultFn(() => /* @__PURE__ */ new Date()) - .notNull(), - updatedAt: timestamp("updated_at") - .$defaultFn(() => /* @__PURE__ */ new Date()) - .notNull(), -}); +})); -export const session = mysqlTable("session", { - id: varchar("id", { length: 36 }).primaryKey(), - expiresAt: timestamp("expires_at").notNull(), - token: varchar("token", { length: 255 }).notNull().unique(), - createdAt: timestamp("created_at").notNull(), - updatedAt: timestamp("updated_at").notNull(), - ipAddress: text("ip_address"), - userAgent: text("user_agent"), - userId: varchar("user_id", { length: 36 }) - .notNull() - .references(() => user.id, { onDelete: "cascade" }), -}); +export const session = createTable( + "session", + (d) => ({ + id: d.varchar("id", { length: 36 }).primaryKey(), + expiresAt: d.timestamp("expires_at", { fsp: 3 }).notNull(), + token: d.varchar("token", { length: 255 }).notNull().unique(), + createdAt: d.timestamp("created_at", { fsp: 3 }).defaultNow().notNull(), + updatedAt: d + .timestamp("updated_at", { fsp: 3 }) + .$onUpdate(() => /* @__PURE__ */ new Date()) + .notNull(), + ipAddress: d.text("ip_address"), + userAgent: d.text("user_agent"), + userId: d.varchar("user_id", { length: 36 }).notNull(), + }), + (table) => [index("session_user_id_idx").on(table.userId)] +); -export const account = mysqlTable("account", { - id: varchar("id", { length: 36 }).primaryKey(), - accountId: text("account_id").notNull(), - providerId: text("provider_id").notNull(), - userId: varchar("user_id", { length: 36 }) - .notNull() - .references(() => user.id, { onDelete: "cascade" }), - 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 account = createTable( + "account", + (d) => ({ + id: d.varchar("id", { length: 36 }).primaryKey(), + accountId: d.text("account_id").notNull(), + providerId: d.text("provider_id").notNull(), + userId: d.varchar("user_id", { length: 36 }).notNull(), + accessToken: d.text("access_token"), + refreshToken: d.text("refresh_token"), + idToken: d.text("id_token"), + accessTokenExpiresAt: d.timestamp("access_token_expires_at", { fsp: 3 }), + refreshTokenExpiresAt: d.timestamp("refresh_token_expires_at", { fsp: 3 }), + scope: d.text("scope"), + password: d.text("password"), + createdAt: d.timestamp("created_at", { fsp: 3 }).defaultNow().notNull(), + updatedAt: d + .timestamp("updated_at", { fsp: 3 }) + .$onUpdate(() => /* @__PURE__ */ new Date()) + .notNull(), + }), + (table) => [index("account_user_id_idx").on(table.userId)] +); -export const verification = mysqlTable("verification", { - id: varchar("id", { length: 36 }).primaryKey(), - identifier: text("identifier").notNull(), - value: text("value").notNull(), - expiresAt: timestamp("expires_at").notNull(), - createdAt: timestamp("created_at").$defaultFn( - () => /* @__PURE__ */ new Date() - ), - updatedAt: timestamp("updated_at").$defaultFn( - () => /* @__PURE__ */ new Date() - ), -}); +export const verification = createTable( + "verification", + (d) => ({ + id: d.varchar("id", { length: 36 }).primaryKey(), + identifier: d.varchar("identifier", { length: 255 }).notNull(), + value: d.text("value").notNull(), + expiresAt: d.timestamp("expires_at", { fsp: 3 }).notNull(), + createdAt: d.timestamp("created_at", { fsp: 3 }).defaultNow().notNull(), + updatedAt: d + .timestamp("updated_at", { fsp: 3 }) + .defaultNow() + .$onUpdate(() => /* @__PURE__ */ new Date()) + .notNull(), + }), + (table) => [index("verification_identifier_idx").on(table.identifier)] +); export const usersRelations = relations(user, ({ many }) => ({ accounts: many(account), diff --git a/cli/template/extras/src/server/db/schema-drizzle/with-better-auth-postgres.ts b/cli/template/extras/src/server/db/schema-drizzle/with-better-auth-postgres.ts index 22da05f95b..da29eab7e5 100644 --- a/cli/template/extras/src/server/db/schema-drizzle/with-better-auth-postgres.ts +++ b/cli/template/extras/src/server/db/schema-drizzle/with-better-auth-postgres.ts @@ -1,12 +1,5 @@ import { relations } from "drizzle-orm"; -import { - boolean, - index, - pgTable, - pgTableCreator, - text, - timestamp, -} from "drizzle-orm/pg-core"; +import { index, pgTableCreator } from "drizzle-orm/pg-core"; export const createTable = pgTableCreator((name) => `pg-drizzle_${name}`); @@ -31,65 +24,83 @@ export const posts = createTable( ] ); -export const user = pgTable("user", { - id: text("id").primaryKey(), - name: text("name").notNull(), - email: text("email").notNull().unique(), - emailVerified: boolean("email_verified") - .$defaultFn(() => false) +export const user = createTable("user", (d) => ({ + id: d.text("id").primaryKey(), + name: d.text("name").notNull(), + email: d.text("email").notNull().unique(), + emailVerified: d.boolean("email_verified").default(false).notNull(), + image: d.text("image"), + createdAt: d.timestamp("created_at").defaultNow().notNull(), + updatedAt: d + .timestamp("updated_at") + .defaultNow() + .$onUpdate(() => /* @__PURE__ */ new Date()) .notNull(), - image: text("image"), - createdAt: timestamp("created_at") - .$defaultFn(() => /* @__PURE__ */ new Date()) - .notNull(), - updatedAt: timestamp("updated_at") - .$defaultFn(() => /* @__PURE__ */ new Date()) - .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, { onDelete: "cascade" }), -}); +export const session = createTable( + "session", + (d) => ({ + id: d.text("id").primaryKey(), + expiresAt: d.timestamp("expires_at").notNull(), + token: d.text("token").notNull().unique(), + createdAt: d.timestamp("created_at").defaultNow().notNull(), + updatedAt: d + .timestamp("updated_at") + .$onUpdate(() => /* @__PURE__ */ new Date()) + .notNull(), + ipAddress: d.text("ip_address"), + userAgent: d.text("user_agent"), + userId: d + .text("user_id") + .notNull() + .references(() => user.id, { onDelete: "cascade" }), + }), + (table) => [index("session_user_id_idx").on(table.userId)] +); -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, { onDelete: "cascade" }), - 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 account = createTable( + "account", + (d) => ({ + id: d.text("id").primaryKey(), + accountId: d.text("account_id").notNull(), + providerId: d.text("provider_id").notNull(), + userId: d + .text("user_id") + .notNull() + .references(() => user.id, { onDelete: "cascade" }), + accessToken: d.text("access_token"), + refreshToken: d.text("refresh_token"), + idToken: d.text("id_token"), + accessTokenExpiresAt: d.timestamp("access_token_expires_at"), + refreshTokenExpiresAt: d.timestamp("refresh_token_expires_at"), + scope: d.text("scope"), + password: d.text("password"), + createdAt: d.timestamp("created_at").defaultNow().notNull(), + updatedAt: d + .timestamp("updated_at") + .$onUpdate(() => /* @__PURE__ */ new Date()) + .notNull(), + }), + (table) => [index("account_user_id_idx").on(table.userId)] +); -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").$defaultFn( - () => /* @__PURE__ */ new Date() - ), - updatedAt: timestamp("updated_at").$defaultFn( - () => /* @__PURE__ */ new Date() - ), -}); +export const verification = createTable( + "verification", + (d) => ({ + id: d.text("id").primaryKey(), + identifier: d.text("identifier").notNull(), + value: d.text("value").notNull(), + expiresAt: d.timestamp("expires_at").notNull(), + createdAt: d.timestamp("created_at").defaultNow().notNull(), + updatedAt: d + .timestamp("updated_at") + .defaultNow() + .$onUpdate(() => /* @__PURE__ */ new Date()) + .notNull(), + }), + (table) => [index("verification_identifier_idx").on(table.identifier)] +); export const userRelations = relations(user, ({ many }) => ({ account: many(account), diff --git a/cli/template/extras/src/server/db/schema-drizzle/with-better-auth-sqlite.ts b/cli/template/extras/src/server/db/schema-drizzle/with-better-auth-sqlite.ts index 81855863cb..a367300470 100644 --- a/cli/template/extras/src/server/db/schema-drizzle/with-better-auth-sqlite.ts +++ b/cli/template/extras/src/server/db/schema-drizzle/with-better-auth-sqlite.ts @@ -1,25 +1,31 @@ import { relations, sql } from "drizzle-orm"; -import { index, sqliteTable } from "drizzle-orm/sqlite-core"; +import { index, sqliteTableCreator } from "drizzle-orm/sqlite-core"; /** - * Multi-project schema prefix helper + * This is an example of how to use the multi-project schema feature of Drizzle ORM. Use the same + * database instance for multiple projects. + * + * @see https://orm.drizzle.team/docs/goodies#multi-project-schema */ +export const createTable = sqliteTableCreator((name) => `project1_${name}`); -// Posts example table -export const posts = sqliteTable( +export const posts = createTable( "post", (d) => ({ - id: d.integer({ mode: "number" }).primaryKey({ autoIncrement: true }), - name: d.text({ length: 256 }), + id: d.integer("id", { mode: "number" }).primaryKey({ autoIncrement: true }), + name: d.text("name", { length: 256 }), createdById: d - .text({ length: 255 }) + .text("created_by_id", { length: 255 }) .notNull() .references(() => user.id), createdAt: d - .integer({ mode: "timestamp" }) - .default(sql`(unixepoch())`) + .integer("created_at", { mode: "timestamp_ms" }) + .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) .notNull(), - updatedAt: d.integer({ mode: "timestamp" }).$onUpdate(() => new Date()), + updatedAt: d + .integer("updated_at", { mode: "timestamp_ms" }) + .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) + .$onUpdate(() => new Date()), }), (t) => [ index("created_by_idx").on(t.createdById), @@ -28,107 +34,112 @@ export const posts = sqliteTable( ); // Better Auth core tables -export const user = sqliteTable("user", (d) => ({ - id: d - .text({ length: 255 }) - .notNull() - .primaryKey() - .$defaultFn(() => crypto.randomUUID()), - name: d.text({ length: 255 }), - email: d.text({ length: 255 }).notNull().unique(), - emailVerified: d.integer({ mode: "boolean" }).default(false), - image: d.text({ length: 255 }), +export const user = createTable("user", (d) => ({ + id: d.text("id").primaryKey(), + name: d.text("name").notNull(), + email: d.text("email").notNull().unique(), + emailVerified: d + .integer("email_verified", { mode: "boolean" }) + .default(false) + .notNull(), + image: d.text("image"), createdAt: d - .integer({ mode: "timestamp" }) - .default(sql`(unixepoch())`) + .integer("created_at", { mode: "timestamp_ms" }) + .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) + .notNull(), + updatedAt: d + .integer("updated_at", { mode: "timestamp_ms" }) + .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) + .$onUpdate(() => new Date()) .notNull(), - updatedAt: d.integer({ mode: "timestamp" }).$onUpdate(() => new Date()), -})); - -export const userRelations = relations(user, ({ many }) => ({ - account: many(account), - session: many(session), })); -export const account = sqliteTable( - "account", +export const session = createTable( + "session", (d) => ({ - id: d - .text({ length: 255 }) - .notNull() - .primaryKey() - .$defaultFn(() => crypto.randomUUID()), - userId: d - .text({ length: 255 }) - .notNull() - .references(() => user.id), - accountId: d.text({ length: 255 }).notNull(), - providerId: d.text({ length: 255 }).notNull(), - accessToken: d.text(), - refreshToken: d.text(), - accessTokenExpiresAt: d.integer({ mode: "timestamp" }), - refreshTokenExpiresAt: d.integer({ mode: "timestamp" }), - scope: d.text({ length: 255 }), - idToken: d.text(), - password: d.text(), + id: d.text("id").primaryKey(), + expiresAt: d.integer("expires_at", { mode: "timestamp_ms" }).notNull(), + token: d.text("token").notNull().unique(), createdAt: d - .integer({ mode: "timestamp" }) - .default(sql`(unixepoch())`) + .integer("created_at", { mode: "timestamp_ms" }) + .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) + .notNull(), + updatedAt: d + .integer("updated_at", { mode: "timestamp_ms" }) + .$onUpdate(() => /* @__PURE__ */ new Date()) .notNull(), - updatedAt: d.integer({ mode: "timestamp" }).$onUpdate(() => new Date()), + ipAddress: d.text("ip_address"), + userAgent: d.text("user_agent"), + userId: d + .text("user_id") + .notNull() + .references(() => user.id, { onDelete: "cascade" }), }), - (t) => [index("account_user_id_idx").on(t.userId)] + (table) => [index("session_user_id_idx").on(table.userId)] ); -export const accountRelations = relations(account, ({ one }) => ({ - user: one(user, { fields: [account.userId], references: [user.id] }), -})); - -export const session = sqliteTable( - "session", +export const account = createTable( + "account", (d) => ({ - id: d - .text({ length: 255 }) - .notNull() - .primaryKey() - .$defaultFn(() => crypto.randomUUID()), + id: d.text("id").primaryKey(), + accountId: d.text("account_id").notNull(), + providerId: d.text("provider_id").notNull(), userId: d - .text({ length: 255 }) + .text("user_id") .notNull() - .references(() => user.id), - token: d.text({ length: 255 }).notNull().unique(), - expiresAt: d.integer({ mode: "timestamp" }).notNull(), - ipAddress: d.text({ length: 255 }), - userAgent: d.text({ length: 255 }), + .references(() => user.id, { onDelete: "cascade" }), + accessToken: d.text("access_token"), + refreshToken: d.text("refresh_token"), + idToken: d.text("id_token"), + accessTokenExpiresAt: d.integer("access_token_expires_at", { + mode: "timestamp_ms", + }), + refreshTokenExpiresAt: d.integer("refresh_token_expires_at", { + mode: "timestamp_ms", + }), + scope: d.text("scope"), + password: d.text("password"), createdAt: d - .integer({ mode: "timestamp" }) - .default(sql`(unixepoch())`) + .integer("created_at", { mode: "timestamp_ms" }) + .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) + .notNull(), + updatedAt: d + .integer("updated_at", { mode: "timestamp_ms" }) + .$onUpdate(() => /* @__PURE__ */ new Date()) .notNull(), - updatedAt: d.integer({ mode: "timestamp" }).$onUpdate(() => new Date()), }), - (t) => [index("session_user_id_idx").on(t.userId)] + (table) => [index("account_user_id_idx").on(table.userId)] ); -export const sessionRelations = relations(session, ({ one }) => ({ - user: one(user, { fields: [session.userId], references: [user.id] }), -})); - -export const verification = sqliteTable( +export const verification = createTable( "verification", (d) => ({ - id: d - .text({ length: 255 }) - .notNull() - .primaryKey() - .$defaultFn(() => crypto.randomUUID()), - identifier: d.text({ length: 255 }).notNull(), - value: d.text({ length: 255 }).notNull(), - expiresAt: d.integer({ mode: "timestamp" }).notNull(), + id: d.text("id").primaryKey(), + identifier: d.text("identifier").notNull(), + value: d.text("value").notNull(), + expiresAt: d.integer("expires_at", { mode: "timestamp_ms" }).notNull(), createdAt: d - .integer({ mode: "timestamp" }) - .default(sql`(unixepoch())`) + .integer("created_at", { mode: "timestamp_ms" }) + .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) + .notNull(), + updatedAt: d + .integer("updated_at", { mode: "timestamp_ms" }) + .default(sql`(cast(unixepoch('subsecond') * 1000 as integer))`) + .$onUpdate(() => /* @__PURE__ */ new Date()) .notNull(), - updatedAt: d.integer({ mode: "timestamp" }).$onUpdate(() => new Date()), }), - (t) => [index("verification_identifier_idx").on(t.identifier)] + (table) => [index("verification_identifier_idx").on(table.identifier)] ); + +export const userRelations = relations(user, ({ many }) => ({ + account: many(account), + session: many(session), +})); + +export const sessionRelations = relations(session, ({ one }) => ({ + user: one(user, { fields: [session.userId], references: [user.id] }), +})); + +export const accountRelations = relations(account, ({ one }) => ({ + user: one(user, { fields: [account.userId], references: [user.id] }), +})); From 46a5c4a92a63df5a569a04b7886b4425568490b5 Mon Sep 17 00:00:00 2001 From: HimanshuKumarDutt094 Date: Sat, 15 Nov 2025 18:12:07 +0530 Subject: [PATCH 06/29] update eslint config --- cli/src/installers/eslint.ts | 6 +++--- cli/template/extras/config/_eslint.base.js | 7 +++++-- cli/template/extras/config/_eslint.drizzle.js | 7 +++++-- 3 files changed, 13 insertions(+), 7 deletions(-) diff --git a/cli/src/installers/eslint.ts b/cli/src/installers/eslint.ts index e92637d7d8..439e9ce22a 100644 --- a/cli/src/installers/eslint.ts +++ b/cli/src/installers/eslint.ts @@ -53,9 +53,9 @@ export const dynamicEslintInstaller: Installer = ({ projectDir, packages }) => { addPackageScript({ projectDir, scripts: { - lint: "next lint", - "lint:fix": "next lint --fix", - check: "next lint && tsc --noEmit", + lint: "eslint .", + "lint:fix": "eslint --fix .", + check: "eslint . && tsc --noEmit", "format:write": 'prettier --write "**/*.{ts,tsx,js,jsx,mdx}" --cache', "format:check": 'prettier --check "**/*.{ts,tsx,js,jsx,mdx}" --cache', }, diff --git a/cli/template/extras/config/_eslint.base.js b/cli/template/extras/config/_eslint.base.js index 9106304137..443d2d405b 100644 --- a/cli/template/extras/config/_eslint.base.js +++ b/cli/template/extras/config/_eslint.base.js @@ -1,5 +1,7 @@ import { FlatCompat } from "@eslint/eslintrc"; import tseslint from 'typescript-eslint'; +import nextCoreWebVitals from "eslint-config-next/core-web-vitals"; +import nextTypescript from "eslint-config-next/typescript"; const compat = new FlatCompat({ baseDirectory: import.meta.dirname, @@ -9,13 +11,14 @@ export default tseslint.config( { ignores: ['.next'] }, - ...compat.extends("next/core-web-vitals"), { files: ['**/*.ts', '**/*.tsx'], extends: [ ...tseslint.configs.recommended, ...tseslint.configs.recommendedTypeChecked, - ...tseslint.configs.stylisticTypeChecked + ...tseslint.configs.stylisticTypeChecked, + ...nextCoreWebVitals, + ...nextTypescript, ], rules: { "@typescript-eslint/array-type": "off", diff --git a/cli/template/extras/config/_eslint.drizzle.js b/cli/template/extras/config/_eslint.drizzle.js index 54096635b9..f712a8ccec 100644 --- a/cli/template/extras/config/_eslint.drizzle.js +++ b/cli/template/extras/config/_eslint.drizzle.js @@ -1,4 +1,6 @@ import { FlatCompat } from "@eslint/eslintrc"; +import nextCoreWebVitals from "eslint-config-next/core-web-vitals"; +import nextTypescript from "eslint-config-next/typescript"; import tseslint from 'typescript-eslint'; // @ts-ignore -- no types for this plugin import drizzle from "eslint-plugin-drizzle"; @@ -11,7 +13,6 @@ export default tseslint.config( { ignores: ['.next'] }, - ...compat.extends("next/core-web-vitals"), { files: ['**/*.ts', '**/*.tsx'], plugins: { @@ -20,7 +21,9 @@ export default tseslint.config( extends: [ ...tseslint.configs.recommended, ...tseslint.configs.recommendedTypeChecked, - ...tseslint.configs.stylisticTypeChecked + ...tseslint.configs.stylisticTypeChecked, + ...nextCoreWebVitals, + ...nextTypescript ], rules: { "@typescript-eslint/array-type": "off", From 1f0e04698da6b07160282dfd52afd442005d81e8 Mon Sep 17 00:00:00 2001 From: HimanshuKumarDutt094 Date: Sat, 15 Nov 2025 17:29:49 +0530 Subject: [PATCH 07/29] bump: astro ,run format and lint fix using newer stuff --- cli/src/installers/tailwind.ts | 2 +- www/package.json | 14 +++++------ .../landingPage/ClipboardSelect.tsx | 24 ++++++++++++------- .../components/navigation/LanguageSelect.tsx | 24 ++++++++++++------- .../components/navigation/OnThisPageLinks.tsx | 18 +++++++------- .../components/navigation/githubIcon.astro | 4 ++-- www/src/utils/fetchGithub.ts | 11 ++++++--- 7 files changed, 57 insertions(+), 40 deletions(-) diff --git a/cli/src/installers/tailwind.ts b/cli/src/installers/tailwind.ts index 1fa5505b97..e88597190a 100644 --- a/cli/src/installers/tailwind.ts +++ b/cli/src/installers/tailwind.ts @@ -8,7 +8,7 @@ import { addPackageDependency } from "~/utils/addPackageDependency.js"; export const tailwindInstaller: Installer = ({ projectDir }) => { addPackageDependency({ projectDir, - dependencies: ["tailwindcss", "postcss", "@tailwindcss/postcss"], + dependencies: ["tailwindcss", "@tailwindcss/postcss"], devMode: true, }); diff --git a/www/package.json b/www/package.json index b7e3b0e23c..6c7da2e3e4 100644 --- a/www/package.json +++ b/www/package.json @@ -16,10 +16,10 @@ }, "dependencies": { "@algolia/client-search": "^5.21.0", - "@astrojs/check": "^0.9.4", - "@astrojs/mdx": "^4.2.1", - "@astrojs/sitemap": "^3.3.0", - "@astrojs/vercel": "^8.1.3", + "@astrojs/check": "^0.9.5", + "@astrojs/mdx": "^4.3.10", + "@astrojs/sitemap": "^3.6.0", + "@astrojs/vercel": "^9.0.0", "@docsearch/css": "^3.9.0", "@docsearch/react": "^3.9.0", "@fontsource-variable/inter": "^5.2.5", @@ -39,14 +39,14 @@ "zod": "^3.24.2" }, "devDependencies": { - "@astrojs/react": "^4.2.1", - "@astrojs/tailwind": "^6.0.1", + "@astrojs/react": "^4.4.2", + "@astrojs/tailwind": "^6.0.2", "@types/node": "^20.14.10", "@types/react": "^19.0.12", "@types/react-dom": "^19.0.4", "@types/react-typist": "^2.0.6", "@types/treeify": "^1.0.3", - "astro": "^5.5.4", + "astro": "^5.15.7", "prettier": "^3.5.3", "prettier-plugin-astro": "^0.14.1", "prettier-plugin-tailwindcss": "^0.6.11", diff --git a/www/src/components/landingPage/ClipboardSelect.tsx b/www/src/components/landingPage/ClipboardSelect.tsx index 30087341a4..0e70f3d38f 100644 --- a/www/src/components/landingPage/ClipboardSelect.tsx +++ b/www/src/components/landingPage/ClipboardSelect.tsx @@ -1,4 +1,10 @@ -import { Menu, Transition } from "@headlessui/react"; +import { + Menu, + MenuButton, + MenuItem, + MenuItems, + Transition, +} from "@headlessui/react"; import clsx from "clsx"; import { Fragment, useState } from "react"; @@ -42,7 +48,7 @@ export default function ClipboardSelect() {
- + - + - {commands.map(({ manager, command }) => ( - - {({ active }) => { + + {({ focus }) => { return ( ); }} - + ))} - +
diff --git a/www/src/components/navigation/LanguageSelect.tsx b/www/src/components/navigation/LanguageSelect.tsx index 8e7d159ad3..a1cf2f5e47 100644 --- a/www/src/components/navigation/LanguageSelect.tsx +++ b/www/src/components/navigation/LanguageSelect.tsx @@ -1,4 +1,10 @@ -import { Listbox, Transition } from "@headlessui/react"; +import { + Listbox, + ListboxButton, + ListboxOption, + ListboxOptions, + Transition, +} from "@headlessui/react"; import clsx from "clsx"; import { Fragment } from "react"; @@ -21,7 +27,7 @@ export default function LanguageSelect({ language }: LanguageSelectProps) {
- + - + - {Object.entries(KNOWN_LANGUAGES).map(([code, name]) => ( - + className={({ selected, focus }) => `focus-none relative cursor-pointer bg-t3-purple-200/50 px-4 py-2 text-slate-900 outline-none hover:bg-t3-purple-300/75 dark:bg-t3-purple-200/10 dark:text-t3-purple-100 dark:hover:bg-t3-purple-200/20 ${ selected && "bg-t3-purple-400/75 dark:bg-t3-purple-400/20" - } ${active && "bg-t3-purple-300/75 dark:bg-t3-purple-200/20"}` + } ${focus && "bg-t3-purple-300/75 dark:bg-t3-purple-200/20"}` } value={code} > @@ -71,9 +77,9 @@ export default function LanguageSelect({ language }: LanguageSelectProps) { {name} )} - + ))} - +
diff --git a/www/src/components/navigation/OnThisPageLinks.tsx b/www/src/components/navigation/OnThisPageLinks.tsx index 17f1bae505..d7802d1ac2 100644 --- a/www/src/components/navigation/OnThisPageLinks.tsx +++ b/www/src/components/navigation/OnThisPageLinks.tsx @@ -1,4 +1,4 @@ -import { Menu } from "@headlessui/react"; +import { Menu, MenuButton, MenuItem, MenuItems } from "@headlessui/react"; import { type MarkdownHeading } from "astro"; import clsx from "clsx"; import { useEffect, useMemo, useState } from "react"; @@ -80,7 +80,7 @@ export default function OnThisPageLinks({ {({ open }) => (
- + On this page - +
-
    {headingWithIsVisible.map((heading) => (
  • - - {({ active }) => ( + + {({ focus }) => ( )} - +
  • ))}
-
+
)} diff --git a/www/src/components/navigation/githubIcon.astro b/www/src/components/navigation/githubIcon.astro index 478e6382d2..b6e85eb7ad 100644 --- a/www/src/components/navigation/githubIcon.astro +++ b/www/src/components/navigation/githubIcon.astro @@ -2,7 +2,7 @@ import { getIsRtlFromUrl, getLanguageFromURL } from "../../languages"; import { fetchGithub } from "../../utils/fetchGithub"; -let githubStars = 25000; +let githubStars = 28000; try { const fetchedStars = await fetchGithub( @@ -13,7 +13,7 @@ try { }, ).then((data) => data?.stargazers_count); - githubStars = fetchedStars ?? 25000; + githubStars = fetchedStars ?? 28000; } catch (e) { console.error("unable to fetch from github", e); } diff --git a/www/src/utils/fetchGithub.ts b/www/src/utils/fetchGithub.ts index 6684272565..928ab2a0b0 100644 --- a/www/src/utils/fetchGithub.ts +++ b/www/src/utils/fetchGithub.ts @@ -35,7 +35,8 @@ export const fetchGithub = async ( > | null> => { const { throwIfNotOk = true, throwIfNoAuth = true, fetchType } = opts; - const schema = fetchType === "commits" ? commitsSchema : repoSchema; + const schema: z.ZodType = + fetchType === "commits" ? commitsSchema : repoSchema; const token = import.meta.env.PUBLIC_GITHUB_TOKEN as string | undefined; @@ -59,7 +60,9 @@ export const fetchGithub = async ( return null; } - return parsed.data; + return parsed.data as z.infer< + T extends "repo" ? typeof repoSchema : typeof commitsSchema + >; } const auth = `Basic ${Buffer.from(token, "binary").toString("base64")}`; @@ -98,5 +101,7 @@ export const fetchGithub = async ( return null; } - return parsed.data; + return parsed.data as z.infer< + T extends "repo" ? typeof repoSchema : typeof commitsSchema + >; }; From 0cd88f7f5f30c3d6f842f4ffce64910bd76200ee Mon Sep 17 00:00:00 2001 From: HimanshuKumarDutt094 Date: Sat, 15 Nov 2025 16:52:58 +0530 Subject: [PATCH 08/29] fix: add type submit, upgrade env,next config to ts,upgrade zod to v4 using latest files --- cli/template/base/package.json | 4 ++-- cli/template/base/tsconfig.json | 3 ++- cli/template/extras/src/app/page/with-better-auth-trpc-tw.tsx | 2 ++ cli/template/extras/src/app/page/with-better-auth-trpc.tsx | 2 ++ cli/template/extras/src/app/page/with-better-auth-tw.tsx | 2 ++ cli/template/extras/src/app/page/with-better-auth.tsx | 2 ++ 6 files changed, 12 insertions(+), 3 deletions(-) diff --git a/cli/template/base/package.json b/cli/template/base/package.json index e6dc26aa5b..061239690c 100644 --- a/cli/template/base/package.json +++ b/cli/template/base/package.json @@ -4,8 +4,8 @@ "type": "module", "private": true, "scripts": { - "dev": "next dev --turbo", - "build": "next build", + "dev": "next dev --turbopack", + "build": "next build --turbopack", "start": "next start", "preview": "next build && next start", "typecheck": "tsc --noEmit" diff --git a/cli/template/base/tsconfig.json b/cli/template/base/tsconfig.json index 3eb759e7e2..eff597eb19 100644 --- a/cli/template/base/tsconfig.json +++ b/cli/template/base/tsconfig.json @@ -20,7 +20,7 @@ "noEmit": true, "module": "ESNext", "moduleResolution": "Bundler", - "jsx": "preserve", + "jsx": "react-jsx", "plugins": [{ "name": "next" }], "incremental": true, @@ -36,6 +36,7 @@ "**/*.tsx", "**/*.cjs", "**/*.js", + ".next/dev/types/**/*.ts", ".next/types/**/*.ts" ], "exclude": ["node_modules", "generated"] diff --git a/cli/template/extras/src/app/page/with-better-auth-trpc-tw.tsx b/cli/template/extras/src/app/page/with-better-auth-trpc-tw.tsx index cf5f9a7426..34c5c23470 100644 --- a/cli/template/extras/src/app/page/with-better-auth-trpc-tw.tsx +++ b/cli/template/extras/src/app/page/with-better-auth-trpc-tw.tsx @@ -58,6 +58,7 @@ export default async function Home() { {!session ? (