create-stackkit-app 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -7
- package/dist/lib/create-project.js +88 -5
- package/dist/lib/template-composer.js +1 -1
- package/modules/auth/better-auth-express/adapters/mongoose-mongodb.ts +13 -0
- package/modules/auth/better-auth-express/adapters/prisma-mongodb.ts +15 -0
- package/modules/auth/better-auth-express/adapters/prisma-postgresql.ts +15 -0
- package/modules/auth/better-auth-express/files/schemas/prisma-mongodb-schema.prisma +72 -0
- package/modules/auth/better-auth-express/files/schemas/prisma-postgresql-schema.prisma +72 -0
- package/modules/auth/better-auth-express/module.json +26 -3
- package/modules/auth/better-auth-nextjs/adapters/mongoose-mongodb.ts +24 -0
- package/modules/auth/better-auth-nextjs/adapters/prisma-mongodb.ts +26 -0
- package/modules/auth/better-auth-nextjs/adapters/prisma-postgresql.ts +26 -0
- package/modules/auth/better-auth-nextjs/files/schemas/prisma-mongodb-schema.prisma +72 -0
- package/modules/auth/better-auth-nextjs/files/schemas/prisma-postgresql-schema.prisma +72 -0
- package/modules/auth/better-auth-nextjs/module.json +26 -5
- package/modules/auth/better-auth-react/module.json +7 -5
- package/modules/auth/clerk-express/module.json +23 -8
- package/modules/auth/clerk-nextjs/module.json +51 -14
- package/modules/auth/clerk-react/module.json +17 -7
- package/modules/database/mongoose-mongodb/module.json +44 -6
- package/modules/database/prisma-mongodb/files/prisma/schema.prisma +1 -1
- package/modules/database/prisma-mongodb/module.json +28 -4
- package/modules/database/prisma-postgresql/files/prisma/schema.prisma +1 -1
- package/modules/database/prisma-postgresql/module.json +28 -4
- package/package.json +1 -1
- package/templates/express/.env.example +11 -0
- package/templates/express/eslint.config.cjs +42 -0
- package/templates/express/package.json +38 -0
- package/templates/express/src/app.ts +69 -0
- package/templates/express/src/config/env.ts +23 -0
- package/templates/{bases/express-base → express}/src/middlewares/error.middleware.ts +9 -3
- package/templates/{bases/nextjs-base → nextjs}/app/page.tsx +5 -5
- package/templates/react-vite/.env.example +2 -0
- package/templates/react-vite/README.md +85 -0
- package/templates/{bases/react-vite-base → react-vite}/index.html +1 -0
- package/templates/{bases/react-vite-base → react-vite}/package.json +18 -3
- package/templates/react-vite/src/api/client.ts +47 -0
- package/templates/react-vite/src/api/services/user.service.ts +26 -0
- package/templates/react-vite/src/components/ErrorBoundary.tsx +51 -0
- package/templates/react-vite/src/components/Layout.tsx +13 -0
- package/templates/react-vite/src/components/Loading.tsx +8 -0
- package/templates/react-vite/src/components/SEO.tsx +49 -0
- package/templates/react-vite/src/config/constants.ts +5 -0
- package/templates/react-vite/src/hooks/index.ts +64 -0
- package/templates/react-vite/src/index.css +1 -0
- package/templates/react-vite/src/lib/queryClient.ts +12 -0
- package/templates/react-vite/src/main.tsx +22 -0
- package/templates/react-vite/src/pages/About.tsx +74 -0
- package/templates/react-vite/src/pages/Home.tsx +45 -0
- package/templates/react-vite/src/pages/NotFound.tsx +24 -0
- package/templates/react-vite/src/pages/UserProfile.tsx +40 -0
- package/templates/react-vite/src/router.tsx +33 -0
- package/templates/react-vite/src/types/api.ts +20 -0
- package/templates/react-vite/src/utils/helpers.ts +51 -0
- package/templates/react-vite/src/utils/storage.ts +35 -0
- package/templates/react-vite/src/vite-env.d.ts +11 -0
- package/templates/{bases/react-vite-base → react-vite}/template.json +2 -1
- package/templates/react-vite/vite.config.ts +13 -0
- package/modules/database/drizzle-postgresql/files/drizzle.config.ts +0 -10
- package/modules/database/drizzle-postgresql/files/lib/db.ts +0 -7
- package/modules/database/drizzle-postgresql/files/lib/schema.ts +0 -8
- package/modules/database/drizzle-postgresql/module.json +0 -34
- package/templates/bases/express-base/.env.example +0 -2
- package/templates/bases/express-base/package.json +0 -23
- package/templates/bases/express-base/src/app.ts +0 -34
- package/templates/bases/express-base/src/config/env.ts +0 -14
- package/templates/bases/react-vite-base/README.md +0 -73
- package/templates/bases/react-vite-base/src/App.css +0 -42
- package/templates/bases/react-vite-base/src/App.tsx +0 -35
- package/templates/bases/react-vite-base/src/index.css +0 -68
- package/templates/bases/react-vite-base/src/main.tsx +0 -10
- package/templates/bases/react-vite-base/vite.config.ts +0 -7
- /package/templates/{bases/express-base → express}/src/server.ts +0 -0
- /package/templates/{bases/express-base → express}/template.json +0 -0
- /package/templates/{bases/express-base → express}/tsconfig.json +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/README.md +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/app/favicon.ico +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/app/globals.css +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/app/layout.tsx +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/eslint.config.mjs +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/next.config.ts +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/package.json +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/postcss.config.mjs +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/public/file.svg +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/public/globe.svg +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/public/next.svg +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/public/vercel.svg +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/public/window.svg +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/template.json +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/tsconfig.json +0 -0
- /package/templates/{bases/react-vite-base → react-vite}/eslint.config.js +0 -0
- /package/templates/{bases/react-vite-base → react-vite}/public/vite.svg +0 -0
- /package/templates/{bases/react-vite-base → react-vite}/src/assets/react.svg +0 -0
- /package/templates/{bases/react-vite-base → react-vite}/tsconfig.app.json +0 -0
- /package/templates/{bases/react-vite-base → react-vite}/tsconfig.json +0 -0
- /package/templates/{bases/react-vite-base → react-vite}/tsconfig.node.json +0 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# create-stackkit-app
|
|
2
2
|
|
|
3
|
-
Create production-ready projects with
|
|
3
|
+
Create production-ready projects with your preferred stack in seconds.
|
|
4
4
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
|
@@ -9,12 +9,31 @@ npx create-stackkit-app my-app
|
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
Interactive wizard helps you choose:
|
|
12
|
-
- Framework
|
|
13
|
-
- Database
|
|
14
|
-
- Authentication
|
|
15
|
-
-
|
|
16
|
-
|
|
12
|
+
- **Framework**: Next.js, Express, or React + Vite
|
|
13
|
+
- **Database**: Prisma (PostgreSQL/MongoDB), Mongoose (MongoDB)
|
|
14
|
+
- **Authentication**: Better Auth, Clerk
|
|
15
|
+
- **Package manager**: pnpm, npm, or yarn
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Create project
|
|
21
|
+
npx create-stackkit-app my-app
|
|
22
|
+
|
|
23
|
+
# Navigate and run
|
|
24
|
+
cd my-app
|
|
25
|
+
npm run dev
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Features
|
|
29
|
+
|
|
30
|
+
- TypeScript configured
|
|
31
|
+
- ESLint + Prettier set up
|
|
32
|
+
- Tailwind CSS included
|
|
33
|
+
- Database client configured
|
|
34
|
+
- Auth flows ready (if selected)
|
|
35
|
+
- Environment variables templated
|
|
17
36
|
|
|
18
37
|
## Documentation
|
|
19
38
|
|
|
20
|
-
|
|
39
|
+
Full documentation available at [stackkit.dev](https://stackkit.dev) or [GitHub](https://github.com/tariqul420/stackkit)
|
|
@@ -167,11 +167,11 @@ async function composeTemplate(config, targetDir) {
|
|
|
167
167
|
await copyBaseFramework(templatesDir, targetDir, config.framework);
|
|
168
168
|
// 2. Merge database configuration
|
|
169
169
|
if (config.database !== 'none') {
|
|
170
|
-
await mergeDatabaseConfig(templatesDir, targetDir, config.database);
|
|
170
|
+
await mergeDatabaseConfig(templatesDir, targetDir, config.database, config.framework);
|
|
171
171
|
}
|
|
172
172
|
// 3. Merge auth configuration
|
|
173
173
|
if (config.auth !== 'none') {
|
|
174
|
-
await mergeAuthConfig(templatesDir, targetDir, config.framework, config.auth);
|
|
174
|
+
await mergeAuthConfig(templatesDir, targetDir, config.framework, config.auth, config.database);
|
|
175
175
|
}
|
|
176
176
|
// 4. Update package.json with project name
|
|
177
177
|
const packageJsonPath = path_1.default.join(targetDir, 'package.json');
|
|
@@ -186,7 +186,7 @@ async function composeTemplate(config, targetDir) {
|
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
188
|
async function copyBaseFramework(templatesDir, targetDir, framework) {
|
|
189
|
-
const baseDir = path_1.default.join(templatesDir,
|
|
189
|
+
const baseDir = path_1.default.join(templatesDir, framework);
|
|
190
190
|
if (!(await fs_extra_1.default.pathExists(baseDir))) {
|
|
191
191
|
throw new Error(`Base template not found for framework: ${framework}\n` + `Expected at: ${baseDir}`);
|
|
192
192
|
}
|
|
@@ -197,7 +197,7 @@ async function copyBaseFramework(templatesDir, targetDir, framework) {
|
|
|
197
197
|
},
|
|
198
198
|
});
|
|
199
199
|
}
|
|
200
|
-
async function mergeDatabaseConfig(templatesDir, targetDir, database) {
|
|
200
|
+
async function mergeDatabaseConfig(templatesDir, targetDir, database, framework) {
|
|
201
201
|
// Use modules directory (sibling to templates)
|
|
202
202
|
const modulesDir = path_1.default.join(templatesDir, '..', 'modules');
|
|
203
203
|
const dbModulePath = path_1.default.join(modulesDir, 'database', database);
|
|
@@ -239,8 +239,16 @@ async function mergeDatabaseConfig(templatesDir, targetDir, database) {
|
|
|
239
239
|
envVars[envVar.key] = envVar.value;
|
|
240
240
|
}
|
|
241
241
|
await mergeEnvFile(targetDir, envVars);
|
|
242
|
+
// Apply framework-specific patches from database module
|
|
243
|
+
if (moduleData.frameworkPatches) {
|
|
244
|
+
const frameworkKey = framework === 'react-vite' ? 'react' : framework;
|
|
245
|
+
const patches = moduleData.frameworkPatches[frameworkKey];
|
|
246
|
+
if (patches) {
|
|
247
|
+
await applyFrameworkPatches(targetDir, patches);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
242
250
|
}
|
|
243
|
-
async function mergeAuthConfig(templatesDir, targetDir, framework, auth) {
|
|
251
|
+
async function mergeAuthConfig(templatesDir, targetDir, framework, auth, database = 'none') {
|
|
244
252
|
// Use modules directory (sibling to templates)
|
|
245
253
|
const modulesDir = path_1.default.join(templatesDir, '..', 'modules');
|
|
246
254
|
// Auth modules are now named with framework suffix
|
|
@@ -300,6 +308,47 @@ async function mergeAuthConfig(templatesDir, targetDir, framework, auth) {
|
|
|
300
308
|
}
|
|
301
309
|
}
|
|
302
310
|
}
|
|
311
|
+
// Handle database-specific adapters and schemas
|
|
312
|
+
if (database !== 'none' && moduleData.databaseAdapters) {
|
|
313
|
+
const adapterConfig = moduleData.databaseAdapters[database];
|
|
314
|
+
if (adapterConfig) {
|
|
315
|
+
// Copy adapter file
|
|
316
|
+
if (adapterConfig.adapter) {
|
|
317
|
+
const adapterSource = path_1.default.join(authModulePath, adapterConfig.adapter);
|
|
318
|
+
const adapterFileName = path_1.default.basename(adapterConfig.adapter);
|
|
319
|
+
// Determine destination based on framework
|
|
320
|
+
let adapterDest;
|
|
321
|
+
if (framework === 'nextjs') {
|
|
322
|
+
adapterDest = path_1.default.join(targetDir, 'lib', 'auth.ts');
|
|
323
|
+
}
|
|
324
|
+
else if (framework === 'express') {
|
|
325
|
+
adapterDest = path_1.default.join(targetDir, 'src', 'auth.ts');
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
adapterDest = path_1.default.join(targetDir, 'src', 'lib', 'auth.ts');
|
|
329
|
+
}
|
|
330
|
+
if (await fs_extra_1.default.pathExists(adapterSource)) {
|
|
331
|
+
await fs_extra_1.default.ensureDir(path_1.default.dirname(adapterDest));
|
|
332
|
+
await fs_extra_1.default.copy(adapterSource, adapterDest, { overwrite: true });
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
// Copy schema file if it exists
|
|
336
|
+
if (adapterConfig.schema && adapterConfig.schemaDestination) {
|
|
337
|
+
const schemaSource = path_1.default.join(authModulePath, adapterConfig.schema);
|
|
338
|
+
const schemaDest = path_1.default.join(targetDir, adapterConfig.schemaDestination);
|
|
339
|
+
if (await fs_extra_1.default.pathExists(schemaSource)) {
|
|
340
|
+
await fs_extra_1.default.ensureDir(path_1.default.dirname(schemaDest));
|
|
341
|
+
await fs_extra_1.default.copy(schemaSource, schemaDest, { overwrite: true });
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
// Merge adapter-specific dependencies
|
|
345
|
+
if (adapterConfig.dependencies) {
|
|
346
|
+
await mergePackageJson(targetDir, {
|
|
347
|
+
dependencies: adapterConfig.dependencies,
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
303
352
|
// Merge package.json with module dependencies
|
|
304
353
|
await mergePackageJson(targetDir, {
|
|
305
354
|
dependencies: moduleData.dependencies,
|
|
@@ -426,6 +475,40 @@ async function initGit(cwd) {
|
|
|
426
475
|
throw new Error('Git initialization failed');
|
|
427
476
|
}
|
|
428
477
|
}
|
|
478
|
+
async function applyFrameworkPatches(targetDir, patches) {
|
|
479
|
+
for (const [filename, patchConfig] of Object.entries(patches)) {
|
|
480
|
+
const filePath = path_1.default.join(targetDir, filename);
|
|
481
|
+
if (await fs_extra_1.default.pathExists(filePath)) {
|
|
482
|
+
const fileContent = await fs_extra_1.default.readJson(filePath);
|
|
483
|
+
if (patchConfig.merge) {
|
|
484
|
+
// Deep merge configuration
|
|
485
|
+
const merged = deepMerge(fileContent, patchConfig.merge);
|
|
486
|
+
await fs_extra_1.default.writeJson(filePath, merged, { spaces: 2 });
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
function deepMerge(target, source) {
|
|
492
|
+
const output = { ...target };
|
|
493
|
+
for (const key in source) {
|
|
494
|
+
if (source[key] && typeof source[key] === 'object' && !Array.isArray(source[key])) {
|
|
495
|
+
if (target[key]) {
|
|
496
|
+
output[key] = deepMerge(target[key], source[key]);
|
|
497
|
+
}
|
|
498
|
+
else {
|
|
499
|
+
output[key] = source[key];
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
else if (Array.isArray(source[key])) {
|
|
503
|
+
// For arrays, merge uniquely
|
|
504
|
+
output[key] = Array.from(new Set([...(target[key] || []), ...source[key]]));
|
|
505
|
+
}
|
|
506
|
+
else {
|
|
507
|
+
output[key] = source[key];
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
return output;
|
|
511
|
+
}
|
|
429
512
|
function showNextSteps(config) {
|
|
430
513
|
console.log(chalk_1.default.green.bold(`\n✓ Created ${config.projectName}\n`));
|
|
431
514
|
console.log(chalk_1.default.bold('Next steps:'));
|
|
@@ -17,7 +17,7 @@ class TemplateComposer {
|
|
|
17
17
|
const configs = [];
|
|
18
18
|
const filesToCopy = [];
|
|
19
19
|
// 1. Load base framework template
|
|
20
|
-
const baseConfig = await this.loadConfig(path_1.default.join(this.templatesDir,
|
|
20
|
+
const baseConfig = await this.loadConfig(path_1.default.join(this.templatesDir, framework));
|
|
21
21
|
configs.push(baseConfig);
|
|
22
22
|
// Copy base files
|
|
23
23
|
const baseFiles = await this.getBaseFiles(framework);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { betterAuth } from 'better-auth';
|
|
2
|
+
import { mongodbAdapter } from 'better-auth/adapters/mongodb';
|
|
3
|
+
import { client } from './db';
|
|
4
|
+
|
|
5
|
+
export const auth = betterAuth({
|
|
6
|
+
database: mongodbAdapter(client),
|
|
7
|
+
emailAndPassword: {
|
|
8
|
+
enabled: true,
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export type Session = typeof auth.$Infer.Session;
|
|
13
|
+
export type User = typeof auth.$Infer.User;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { prismaAdapter } from '@better-auth/prisma';
|
|
2
|
+
import { betterAuth } from 'better-auth';
|
|
3
|
+
import { prisma } from './db';
|
|
4
|
+
|
|
5
|
+
export const auth = betterAuth({
|
|
6
|
+
database: prismaAdapter(prisma, {
|
|
7
|
+
provider: 'mongodb',
|
|
8
|
+
}),
|
|
9
|
+
emailAndPassword: {
|
|
10
|
+
enabled: true,
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export type Session = typeof auth.$Infer.Session;
|
|
15
|
+
export type User = typeof auth.$Infer.User;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { prismaAdapter } from '@better-auth/prisma';
|
|
2
|
+
import { betterAuth } from 'better-auth';
|
|
3
|
+
import { prisma } from './db';
|
|
4
|
+
|
|
5
|
+
export const auth = betterAuth({
|
|
6
|
+
database: prismaAdapter(prisma, {
|
|
7
|
+
provider: 'postgresql',
|
|
8
|
+
}),
|
|
9
|
+
emailAndPassword: {
|
|
10
|
+
enabled: true,
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export type Session = typeof auth.$Infer.Session;
|
|
15
|
+
export type User = typeof auth.$Infer.User;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
generator client {
|
|
2
|
+
provider = "prisma-client-js"
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
datasource db {
|
|
6
|
+
provider = "mongodb"
|
|
7
|
+
url = env("DATABASE_URL")
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Better Auth models for MongoDB
|
|
11
|
+
model User {
|
|
12
|
+
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
13
|
+
name String
|
|
14
|
+
email String
|
|
15
|
+
emailVerified Boolean @default(false)
|
|
16
|
+
image String?
|
|
17
|
+
createdAt DateTime @default(now())
|
|
18
|
+
updatedAt DateTime @updatedAt
|
|
19
|
+
sessions Session[]
|
|
20
|
+
accounts Account[]
|
|
21
|
+
role String @default("USER")
|
|
22
|
+
|
|
23
|
+
@@unique([email])
|
|
24
|
+
@@map("user")
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
model Session {
|
|
28
|
+
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
29
|
+
expiresAt DateTime
|
|
30
|
+
token String @unique
|
|
31
|
+
createdAt DateTime @default(now())
|
|
32
|
+
updatedAt DateTime @updatedAt
|
|
33
|
+
ipAddress String?
|
|
34
|
+
userAgent String?
|
|
35
|
+
userId String @db.ObjectId
|
|
36
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
37
|
+
|
|
38
|
+
@@index([userId])
|
|
39
|
+
@@map("session")
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
model Account {
|
|
43
|
+
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
44
|
+
accountId String
|
|
45
|
+
providerId String
|
|
46
|
+
userId String @db.ObjectId
|
|
47
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
48
|
+
accessToken String?
|
|
49
|
+
refreshToken String?
|
|
50
|
+
idToken String?
|
|
51
|
+
accessTokenExpiresAt DateTime?
|
|
52
|
+
refreshTokenExpiresAt DateTime?
|
|
53
|
+
scope String?
|
|
54
|
+
password String?
|
|
55
|
+
createdAt DateTime @default(now())
|
|
56
|
+
updatedAt DateTime @updatedAt
|
|
57
|
+
|
|
58
|
+
@@index([userId])
|
|
59
|
+
@@map("account")
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
model Verification {
|
|
63
|
+
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
64
|
+
identifier String
|
|
65
|
+
value String
|
|
66
|
+
expiresAt DateTime
|
|
67
|
+
createdAt DateTime @default(now())
|
|
68
|
+
updatedAt DateTime @updatedAt
|
|
69
|
+
|
|
70
|
+
@@index([identifier])
|
|
71
|
+
@@map("verification")
|
|
72
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
generator client {
|
|
2
|
+
provider = "prisma-client-js"
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
datasource db {
|
|
6
|
+
provider = "postgresql"
|
|
7
|
+
url = env("DATABASE_URL")
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Better Auth models for PostgreSQL
|
|
11
|
+
model User {
|
|
12
|
+
id String @id @default(cuid())
|
|
13
|
+
name String
|
|
14
|
+
email String
|
|
15
|
+
emailVerified Boolean @default(false)
|
|
16
|
+
image String?
|
|
17
|
+
createdAt DateTime @default(now())
|
|
18
|
+
updatedAt DateTime @updatedAt
|
|
19
|
+
sessions Session[]
|
|
20
|
+
accounts Account[]
|
|
21
|
+
role String @default("USER")
|
|
22
|
+
|
|
23
|
+
@@unique([email])
|
|
24
|
+
@@map("user")
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
model Session {
|
|
28
|
+
id String @id @default(cuid())
|
|
29
|
+
expiresAt DateTime
|
|
30
|
+
token String @unique
|
|
31
|
+
createdAt DateTime @default(now())
|
|
32
|
+
updatedAt DateTime @updatedAt
|
|
33
|
+
ipAddress String?
|
|
34
|
+
userAgent String?
|
|
35
|
+
userId String
|
|
36
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
37
|
+
|
|
38
|
+
@@index([userId])
|
|
39
|
+
@@map("session")
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
model Account {
|
|
43
|
+
id String @id @default(cuid())
|
|
44
|
+
accountId String
|
|
45
|
+
providerId String
|
|
46
|
+
userId String
|
|
47
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
48
|
+
accessToken String?
|
|
49
|
+
refreshToken String?
|
|
50
|
+
idToken String?
|
|
51
|
+
accessTokenExpiresAt DateTime?
|
|
52
|
+
refreshTokenExpiresAt DateTime?
|
|
53
|
+
scope String?
|
|
54
|
+
password String?
|
|
55
|
+
createdAt DateTime @default(now())
|
|
56
|
+
updatedAt DateTime @updatedAt
|
|
57
|
+
|
|
58
|
+
@@index([userId])
|
|
59
|
+
@@map("account")
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
model Verification {
|
|
63
|
+
id String @id @default(cuid())
|
|
64
|
+
identifier String
|
|
65
|
+
value String
|
|
66
|
+
expiresAt DateTime
|
|
67
|
+
createdAt DateTime @default(now())
|
|
68
|
+
updatedAt DateTime @updatedAt
|
|
69
|
+
|
|
70
|
+
@@index([identifier])
|
|
71
|
+
@@map("verification")
|
|
72
|
+
}
|
|
@@ -1,11 +1,34 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "auth",
|
|
2
|
+
"name": "better-auth-express",
|
|
3
3
|
"displayName": "Better Auth (Express)",
|
|
4
4
|
"description": "Modern authentication with Better Auth for Express",
|
|
5
5
|
"category": "auth",
|
|
6
6
|
"supportedFrameworks": ["express"],
|
|
7
|
-
"
|
|
8
|
-
"
|
|
7
|
+
"databaseAdapters": {
|
|
8
|
+
"prisma-postgresql": {
|
|
9
|
+
"adapter": "adapters/prisma-postgresql.ts",
|
|
10
|
+
"schema": "files/schemas/prisma-postgresql-schema.prisma",
|
|
11
|
+
"schemaDestination": "prisma/schema.prisma",
|
|
12
|
+
"dependencies": {
|
|
13
|
+
"better-auth": "^1.1.4",
|
|
14
|
+
"@better-auth/prisma": "^1.1.4"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"prisma-mongodb": {
|
|
18
|
+
"adapter": "adapters/prisma-mongodb.ts",
|
|
19
|
+
"schema": "files/schemas/prisma-mongodb-schema.prisma",
|
|
20
|
+
"schemaDestination": "prisma/schema.prisma",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"better-auth": "^1.1.4",
|
|
23
|
+
"@better-auth/prisma": "^1.1.4"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"mongoose-mongodb": {
|
|
27
|
+
"adapter": "adapters/mongoose-mongodb.ts",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"better-auth": "^1.1.4"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
9
32
|
},
|
|
10
33
|
"envVars": [
|
|
11
34
|
{
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { client } from '@/lib/db';
|
|
2
|
+
import { betterAuth } from 'better-auth';
|
|
3
|
+
import { mongodbAdapter } from 'better-auth/adapters/mongodb';
|
|
4
|
+
|
|
5
|
+
export const auth = betterAuth({
|
|
6
|
+
database: mongodbAdapter(client),
|
|
7
|
+
emailAndPassword: {
|
|
8
|
+
enabled: true,
|
|
9
|
+
},
|
|
10
|
+
socialProviders: {
|
|
11
|
+
// Uncomment to add OAuth providers
|
|
12
|
+
// google: {
|
|
13
|
+
// clientId: process.env.GOOGLE_CLIENT_ID!,
|
|
14
|
+
// clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
|
|
15
|
+
// },
|
|
16
|
+
// github: {
|
|
17
|
+
// clientId: process.env.GITHUB_CLIENT_ID!,
|
|
18
|
+
// clientSecret: process.env.GITHUB_CLIENT_SECRET!,
|
|
19
|
+
// },
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export type Session = typeof auth.$Infer.Session;
|
|
24
|
+
export type User = typeof auth.$Infer.User;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { prisma } from '@/lib/db';
|
|
2
|
+
import { prismaAdapter } from '@better-auth/prisma';
|
|
3
|
+
import { betterAuth } from 'better-auth';
|
|
4
|
+
|
|
5
|
+
export const auth = betterAuth({
|
|
6
|
+
database: prismaAdapter(prisma, {
|
|
7
|
+
provider: 'mongodb',
|
|
8
|
+
}),
|
|
9
|
+
emailAndPassword: {
|
|
10
|
+
enabled: true,
|
|
11
|
+
},
|
|
12
|
+
socialProviders: {
|
|
13
|
+
// Uncomment to add OAuth providers
|
|
14
|
+
// google: {
|
|
15
|
+
// clientId: process.env.GOOGLE_CLIENT_ID!,
|
|
16
|
+
// clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
|
|
17
|
+
// },
|
|
18
|
+
// github: {
|
|
19
|
+
// clientId: process.env.GITHUB_CLIENT_ID!,
|
|
20
|
+
// clientSecret: process.env.GITHUB_CLIENT_SECRET!,
|
|
21
|
+
// },
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export type Session = typeof auth.$Infer.Session;
|
|
26
|
+
export type User = typeof auth.$Infer.User;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { prisma } from '@/lib/db';
|
|
2
|
+
import { prismaAdapter } from '@better-auth/prisma';
|
|
3
|
+
import { betterAuth } from 'better-auth';
|
|
4
|
+
|
|
5
|
+
export const auth = betterAuth({
|
|
6
|
+
database: prismaAdapter(prisma, {
|
|
7
|
+
provider: 'postgresql',
|
|
8
|
+
}),
|
|
9
|
+
emailAndPassword: {
|
|
10
|
+
enabled: true,
|
|
11
|
+
},
|
|
12
|
+
socialProviders: {
|
|
13
|
+
// Uncomment to add OAuth providers
|
|
14
|
+
// google: {
|
|
15
|
+
// clientId: process.env.GOOGLE_CLIENT_ID!,
|
|
16
|
+
// clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
|
|
17
|
+
// },
|
|
18
|
+
// github: {
|
|
19
|
+
// clientId: process.env.GITHUB_CLIENT_ID!,
|
|
20
|
+
// clientSecret: process.env.GITHUB_CLIENT_SECRET!,
|
|
21
|
+
// },
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export type Session = typeof auth.$Infer.Session;
|
|
26
|
+
export type User = typeof auth.$Infer.User;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
generator client {
|
|
2
|
+
provider = "prisma-client-js"
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
datasource db {
|
|
6
|
+
provider = "mongodb"
|
|
7
|
+
url = env("DATABASE_URL")
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Better Auth models for MongoDB
|
|
11
|
+
model User {
|
|
12
|
+
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
13
|
+
name String
|
|
14
|
+
email String
|
|
15
|
+
emailVerified Boolean @default(false)
|
|
16
|
+
image String?
|
|
17
|
+
createdAt DateTime @default(now())
|
|
18
|
+
updatedAt DateTime @updatedAt
|
|
19
|
+
sessions Session[]
|
|
20
|
+
accounts Account[]
|
|
21
|
+
role String @default("USER")
|
|
22
|
+
|
|
23
|
+
@@unique([email])
|
|
24
|
+
@@map("user")
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
model Session {
|
|
28
|
+
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
29
|
+
expiresAt DateTime
|
|
30
|
+
token String @unique
|
|
31
|
+
createdAt DateTime @default(now())
|
|
32
|
+
updatedAt DateTime @updatedAt
|
|
33
|
+
ipAddress String?
|
|
34
|
+
userAgent String?
|
|
35
|
+
userId String @db.ObjectId
|
|
36
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
37
|
+
|
|
38
|
+
@@index([userId])
|
|
39
|
+
@@map("session")
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
model Account {
|
|
43
|
+
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
44
|
+
accountId String
|
|
45
|
+
providerId String
|
|
46
|
+
userId String @db.ObjectId
|
|
47
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
48
|
+
accessToken String?
|
|
49
|
+
refreshToken String?
|
|
50
|
+
idToken String?
|
|
51
|
+
accessTokenExpiresAt DateTime?
|
|
52
|
+
refreshTokenExpiresAt DateTime?
|
|
53
|
+
scope String?
|
|
54
|
+
password String?
|
|
55
|
+
createdAt DateTime @default(now())
|
|
56
|
+
updatedAt DateTime @updatedAt
|
|
57
|
+
|
|
58
|
+
@@index([userId])
|
|
59
|
+
@@map("account")
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
model Verification {
|
|
63
|
+
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
64
|
+
identifier String
|
|
65
|
+
value String
|
|
66
|
+
expiresAt DateTime
|
|
67
|
+
createdAt DateTime @default(now())
|
|
68
|
+
updatedAt DateTime @updatedAt
|
|
69
|
+
|
|
70
|
+
@@index([identifier])
|
|
71
|
+
@@map("verification")
|
|
72
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
generator client {
|
|
2
|
+
provider = "prisma-client-js"
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
datasource db {
|
|
6
|
+
provider = "postgresql"
|
|
7
|
+
url = env("DATABASE_URL")
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Better Auth models for PostgreSQL
|
|
11
|
+
model User {
|
|
12
|
+
id String @id @default(cuid())
|
|
13
|
+
name String
|
|
14
|
+
email String
|
|
15
|
+
emailVerified Boolean @default(false)
|
|
16
|
+
image String?
|
|
17
|
+
createdAt DateTime @default(now())
|
|
18
|
+
updatedAt DateTime @updatedAt
|
|
19
|
+
sessions Session[]
|
|
20
|
+
accounts Account[]
|
|
21
|
+
role String @default("USER")
|
|
22
|
+
|
|
23
|
+
@@unique([email])
|
|
24
|
+
@@map("user")
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
model Session {
|
|
28
|
+
id String @id @default(cuid())
|
|
29
|
+
expiresAt DateTime
|
|
30
|
+
token String @unique
|
|
31
|
+
createdAt DateTime @default(now())
|
|
32
|
+
updatedAt DateTime @updatedAt
|
|
33
|
+
ipAddress String?
|
|
34
|
+
userAgent String?
|
|
35
|
+
userId String
|
|
36
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
37
|
+
|
|
38
|
+
@@index([userId])
|
|
39
|
+
@@map("session")
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
model Account {
|
|
43
|
+
id String @id @default(cuid())
|
|
44
|
+
accountId String
|
|
45
|
+
providerId String
|
|
46
|
+
userId String
|
|
47
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
48
|
+
accessToken String?
|
|
49
|
+
refreshToken String?
|
|
50
|
+
idToken String?
|
|
51
|
+
accessTokenExpiresAt DateTime?
|
|
52
|
+
refreshTokenExpiresAt DateTime?
|
|
53
|
+
scope String?
|
|
54
|
+
password String?
|
|
55
|
+
createdAt DateTime @default(now())
|
|
56
|
+
updatedAt DateTime @updatedAt
|
|
57
|
+
|
|
58
|
+
@@index([userId])
|
|
59
|
+
@@map("account")
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
model Verification {
|
|
63
|
+
id String @id @default(cuid())
|
|
64
|
+
identifier String
|
|
65
|
+
value String
|
|
66
|
+
expiresAt DateTime
|
|
67
|
+
createdAt DateTime @default(now())
|
|
68
|
+
updatedAt DateTime @updatedAt
|
|
69
|
+
|
|
70
|
+
@@index([identifier])
|
|
71
|
+
@@map("verification")
|
|
72
|
+
}
|