Skip to content

Commit 8780248

Browse files
committed
feat(auth): implement script-only auth and db modules for admin user creation
- Added `auth-for-script.ts` and `db.ts` to provide minimal, script-compatible instances of authentication and database access, avoiding server-only imports. - Updated `create-admin.ts` to utilize the new script-only modules for creating the initial admin user, enhancing compatibility with tsx execution. - Added `server-only` dependency to `package.json` and updated `pnpm-lock.yaml` accordingly.
1 parent 5b053fd commit 8780248

File tree

5 files changed

+75
-5
lines changed

5 files changed

+75
-5
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@
114114
"react-scan": "^0.4.3",
115115
"recharts": "2.15.4",
116116
"schema-dts": "^1.1.5",
117+
"server-only": "^0.0.1",
117118
"sonner": "^2.0.7",
118119
"tailwind-merge": "^3.4.0",
119120
"tw-animate-css": "^1.4.0",

pnpm-lock.yaml

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

scripts/create-admin.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,26 @@ import "dotenv/config";
22

33
import { eq } from "drizzle-orm";
44

5-
import { auth } from "@/auth";
6-
import { db } from "@/db";
75
import { user } from "@/db/schema/auth";
86

7+
import { auth } from "./lib/auth-for-script";
8+
import { db } from "./lib/db";
9+
910
// ============================================================================
1011
// Create Admin User Script
1112
// ============================================================================
1213
// This script creates the initial admin user for the Portal application.
13-
// It uses Better Auth's signUpEmail API to create the user, then directly
14-
// updates the database to set the role to "admin" (since we don't have
15-
// an admin yet to use the admin API's setRole method).
14+
// It uses script-only db and auth (scripts/lib/) so it can run under tsx
15+
// without pulling in "server-only" modules. It calls Better Auth's signUpEmail
16+
// then updates the user role to "admin" in the database.
1617
//
1718
// Usage:
1819
// pnpm create-admin
1920
//
2021
// Environment Variables:
22+
// DATABASE_URL - Required. PostgreSQL connection string.
23+
// BETTER_AUTH_SECRET - Required. Same secret as the app.
24+
// BETTER_AUTH_URL - Optional (default: http://localhost:3000).
2125
// ADMIN_EMAIL - Email for the admin user (default: "admin@portal.com")
2226
// ADMIN_PASSWORD - Password for the admin user (default: "admin123")
2327
// ADMIN_NAME - Name for the admin user (default: "Admin User")

scripts/lib/auth-for-script.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* Minimal Better Auth instance for scripts (create-admin, etc.).
3+
* Does not import "server-only" or the full auth config, so it can run under tsx.
4+
* Only includes what signUpEmail needs: database adapter, basePath, baseURL, secret.
5+
*/
6+
import "dotenv/config";
7+
8+
import { betterAuth } from "better-auth";
9+
import { drizzleAdapter } from "better-auth/adapters/drizzle";
10+
11+
import { db } from "./db";
12+
import { schema } from "@/db/schema";
13+
14+
const baseURL = process.env.BETTER_AUTH_URL ?? "http://localhost:3000";
15+
const secret = process.env.BETTER_AUTH_SECRET;
16+
17+
if (!secret) {
18+
throw new Error(
19+
"BETTER_AUTH_SECRET is required. Set it in .env or pass it when running the script."
20+
);
21+
}
22+
23+
export const auth = betterAuth({
24+
database: drizzleAdapter(db, { provider: "pg", schema }),
25+
basePath: "/api/auth",
26+
baseURL,
27+
secret,
28+
emailAndPassword: {
29+
enabled: true,
30+
},
31+
});

scripts/lib/db.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* Script-only database client.
3+
* Does not import "server-only", so it can be used by tsx scripts (create-admin, etc.)
4+
* without pulling in Next.js server-only modules.
5+
*/
6+
import "dotenv/config";
7+
8+
import { drizzle } from "drizzle-orm/node-postgres";
9+
import { Pool } from "pg";
10+
11+
import { keys } from "@/db/keys";
12+
import { relations } from "@/db/relations";
13+
import { schema } from "@/db/schema";
14+
15+
const env = keys();
16+
const connectionString = env.DATABASE_URL;
17+
18+
if (!connectionString) {
19+
throw new Error(
20+
"DATABASE_URL is required. Set it in .env or pass it when running the script."
21+
);
22+
}
23+
24+
const pool = new Pool({ connectionString });
25+
26+
export const db = drizzle({ client: pool, schema, relations });

0 commit comments

Comments
 (0)