create-stackkit-app 0.4.0 → 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 +25 -11
- package/dist/lib/create-project.js +88 -8
- 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 +3 -3
- 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/express/src/middlewares/error.middleware.ts +18 -0
- package/templates/express/src/server.ts +8 -0
- package/templates/{bases/express-base → express}/template.json +1 -1
- package/templates/express/tsconfig.json +14 -0
- package/templates/{bases/nextjs-base → nextjs}/app/page.tsx +5 -5
- package/templates/{bases/nextjs-base → nextjs}/template.json +1 -1
- package/templates/react-vite/.env.example +2 -0
- package/templates/react-vite/README.md +85 -0
- package/templates/react-vite/eslint.config.js +23 -0
- package/templates/{bases/react-vite-base → react-vite}/index.html +2 -1
- package/templates/react-vite/package.json +45 -0
- package/templates/react-vite/public/vite.svg +1 -0
- 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/assets/react.svg +1 -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/react-vite/template.json +20 -0
- package/templates/{bases/react-vite-base/tsconfig.json → react-vite/tsconfig.app.json} +10 -3
- package/templates/react-vite/tsconfig.json +7 -0
- package/templates/react-vite/tsconfig.node.json +26 -0
- package/templates/react-vite/vite.config.ts +13 -0
- package/modules/auth/authjs-express/files/lib/auth.ts +0 -40
- package/modules/auth/authjs-express/files/routes/auth.ts +0 -12
- package/modules/auth/authjs-express/module.json +0 -39
- package/modules/auth/authjs-nextjs/files/api/auth/[...nextauth]/route.ts +0 -3
- package/modules/auth/authjs-nextjs/files/lib/auth.ts +0 -43
- package/modules/auth/authjs-nextjs/module.json +0 -38
- package/modules/auth/nextauth/files/app-router/api/auth/[...nextauth]/route.ts +0 -6
- package/modules/auth/nextauth/files/lib/auth.ts +0 -82
- package/modules/auth/nextauth/files/pages-router/api/auth/[...nextauth].ts +0 -4
- package/modules/auth/nextauth/module.json +0 -50
- 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/index.ts +0 -27
- package/templates/bases/express-base/tsconfig.json +0 -17
- package/templates/bases/nextjs-base/package-lock.json +0 -6538
- package/templates/bases/react-vite-base/package.json +0 -27
- package/templates/bases/react-vite-base/src/App.css +0 -14
- package/templates/bases/react-vite-base/src/App.tsx +0 -23
- 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/src/vite-env.d.ts +0 -1
- package/templates/bases/react-vite-base/template.json +0 -5
- package/templates/bases/react-vite-base/vite.config.ts +0 -7
- /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}/tsconfig.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
|
|
|
@@ -8,18 +8,32 @@ Create production-ready projects with one command.
|
|
|
8
8
|
npx create-stackkit-app my-app
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
Interactive wizard
|
|
12
|
-
- **Framework**: Next.js, Express, React
|
|
13
|
-
- **Database**: Prisma
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
11
|
+
Interactive wizard helps you choose:
|
|
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
16
|
|
|
17
|
-
##
|
|
17
|
+
## Quick Start
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
# Create project
|
|
21
|
+
npx create-stackkit-app my-app
|
|
22
|
+
|
|
23
|
+
# Navigate and run
|
|
24
|
+
cd my-app
|
|
25
|
+
npm run dev
|
|
23
26
|
```
|
|
24
27
|
|
|
25
|
-
|
|
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
|
|
36
|
+
|
|
37
|
+
## Documentation
|
|
38
|
+
|
|
39
|
+
Full documentation available at [stackkit.dev](https://stackkit.dev) or [GitHub](https://github.com/tariqul420/stackkit)
|
|
@@ -84,8 +84,6 @@ async function getProjectConfig(projectName) {
|
|
|
84
84
|
// Next.js apps
|
|
85
85
|
if (answers.framework === 'nextjs') {
|
|
86
86
|
return [
|
|
87
|
-
{ name: 'Auth.js v5', value: 'authjs-nextjs' },
|
|
88
|
-
{ name: 'NextAuth.js', value: 'nextauth' },
|
|
89
87
|
{ name: 'Better Auth', value: 'better-auth-nextjs' },
|
|
90
88
|
{ name: 'Clerk', value: 'clerk-nextjs' },
|
|
91
89
|
{ name: 'None', value: 'none' },
|
|
@@ -94,7 +92,6 @@ async function getProjectConfig(projectName) {
|
|
|
94
92
|
// Express apps
|
|
95
93
|
if (answers.framework === 'express') {
|
|
96
94
|
return [
|
|
97
|
-
{ name: 'Auth.js', value: 'authjs-express' },
|
|
98
95
|
{ name: 'Better Auth', value: 'better-auth-express' },
|
|
99
96
|
{ name: 'Clerk', value: 'clerk-express' },
|
|
100
97
|
{ name: 'None', value: 'none' },
|
|
@@ -170,11 +167,11 @@ async function composeTemplate(config, targetDir) {
|
|
|
170
167
|
await copyBaseFramework(templatesDir, targetDir, config.framework);
|
|
171
168
|
// 2. Merge database configuration
|
|
172
169
|
if (config.database !== 'none') {
|
|
173
|
-
await mergeDatabaseConfig(templatesDir, targetDir, config.database);
|
|
170
|
+
await mergeDatabaseConfig(templatesDir, targetDir, config.database, config.framework);
|
|
174
171
|
}
|
|
175
172
|
// 3. Merge auth configuration
|
|
176
173
|
if (config.auth !== 'none') {
|
|
177
|
-
await mergeAuthConfig(templatesDir, targetDir, config.framework, config.auth);
|
|
174
|
+
await mergeAuthConfig(templatesDir, targetDir, config.framework, config.auth, config.database);
|
|
178
175
|
}
|
|
179
176
|
// 4. Update package.json with project name
|
|
180
177
|
const packageJsonPath = path_1.default.join(targetDir, 'package.json');
|
|
@@ -189,7 +186,7 @@ async function composeTemplate(config, targetDir) {
|
|
|
189
186
|
}
|
|
190
187
|
}
|
|
191
188
|
async function copyBaseFramework(templatesDir, targetDir, framework) {
|
|
192
|
-
const baseDir = path_1.default.join(templatesDir,
|
|
189
|
+
const baseDir = path_1.default.join(templatesDir, framework);
|
|
193
190
|
if (!(await fs_extra_1.default.pathExists(baseDir))) {
|
|
194
191
|
throw new Error(`Base template not found for framework: ${framework}\n` + `Expected at: ${baseDir}`);
|
|
195
192
|
}
|
|
@@ -200,7 +197,7 @@ async function copyBaseFramework(templatesDir, targetDir, framework) {
|
|
|
200
197
|
},
|
|
201
198
|
});
|
|
202
199
|
}
|
|
203
|
-
async function mergeDatabaseConfig(templatesDir, targetDir, database) {
|
|
200
|
+
async function mergeDatabaseConfig(templatesDir, targetDir, database, framework) {
|
|
204
201
|
// Use modules directory (sibling to templates)
|
|
205
202
|
const modulesDir = path_1.default.join(templatesDir, '..', 'modules');
|
|
206
203
|
const dbModulePath = path_1.default.join(modulesDir, 'database', database);
|
|
@@ -242,8 +239,16 @@ async function mergeDatabaseConfig(templatesDir, targetDir, database) {
|
|
|
242
239
|
envVars[envVar.key] = envVar.value;
|
|
243
240
|
}
|
|
244
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
|
+
}
|
|
245
250
|
}
|
|
246
|
-
async function mergeAuthConfig(templatesDir, targetDir, framework, auth) {
|
|
251
|
+
async function mergeAuthConfig(templatesDir, targetDir, framework, auth, database = 'none') {
|
|
247
252
|
// Use modules directory (sibling to templates)
|
|
248
253
|
const modulesDir = path_1.default.join(templatesDir, '..', 'modules');
|
|
249
254
|
// Auth modules are now named with framework suffix
|
|
@@ -303,6 +308,47 @@ async function mergeAuthConfig(templatesDir, targetDir, framework, auth) {
|
|
|
303
308
|
}
|
|
304
309
|
}
|
|
305
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
|
+
}
|
|
306
352
|
// Merge package.json with module dependencies
|
|
307
353
|
await mergePackageJson(targetDir, {
|
|
308
354
|
dependencies: moduleData.dependencies,
|
|
@@ -429,6 +475,40 @@ async function initGit(cwd) {
|
|
|
429
475
|
throw new Error('Git initialization failed');
|
|
430
476
|
}
|
|
431
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
|
+
}
|
|
432
512
|
function showNextSteps(config) {
|
|
433
513
|
console.log(chalk_1.default.green.bold(`\n✓ Created ${config.projectName}\n`));
|
|
434
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
|
+
}
|