create-stackkit-app 0.4.2 → 0.4.4
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 +1 -0
- package/bin/create-stackkit.js +10 -1
- package/dist/index.js +2 -1
- package/dist/lib/create-project.js +138 -412
- package/dist/lib/utils/config-utils.d.ts +2 -0
- package/dist/lib/utils/config-utils.js +33 -0
- package/dist/lib/utils/file-utils.d.ts +8 -0
- package/dist/lib/utils/file-utils.js +75 -0
- package/dist/lib/utils/git-utils.d.ts +1 -0
- package/dist/lib/utils/git-utils.js +9 -0
- package/dist/lib/utils/js-conversion.d.ts +1 -0
- package/dist/lib/utils/js-conversion.js +244 -0
- package/dist/lib/utils/module-utils.d.ts +2 -0
- package/dist/lib/utils/module-utils.js +311 -0
- package/dist/lib/utils/package-utils.d.ts +1 -0
- package/dist/lib/utils/package-utils.js +39 -0
- package/modules/auth/better-auth/files/api/auth/[...all]/route.ts +4 -0
- package/modules/auth/better-auth/files/lib/auth.ts +13 -0
- package/modules/auth/better-auth/files/schemas/prisma-schema.prisma +63 -0
- package/modules/auth/better-auth/module.json +54 -0
- package/modules/auth/{clerk-express/files/lib → clerk/files/express}/auth.ts +1 -1
- package/modules/auth/{clerk-nextjs/files/lib → clerk/files/nextjs}/auth-provider.tsx +1 -1
- package/modules/auth/clerk/files/nextjs/middleware.ts +9 -0
- package/modules/auth/{clerk-react/files/lib → clerk/files/react}/auth-provider.tsx +2 -2
- package/modules/auth/clerk/module.json +115 -0
- package/modules/database/mongoose-mongodb/files/lib/db.ts +45 -7
- package/modules/database/mongoose-mongodb/files/models/User.ts +39 -0
- package/modules/database/mongoose-mongodb/module.json +27 -12
- package/modules/database/prisma/files/lib/prisma.ts +6 -0
- package/modules/database/prisma/files/prisma/schema.prisma +8 -0
- package/modules/database/prisma/files/prisma.config.ts +12 -0
- package/modules/database/prisma/module.json +140 -0
- package/package.json +12 -3
- package/templates/express/.env.example +2 -10
- package/templates/express/package.json +13 -18
- package/templates/express/src/app.ts +21 -39
- package/templates/express/src/config/env.ts +6 -17
- package/templates/express/src/features/auth/auth.controller.ts +48 -0
- package/templates/express/src/features/auth/auth.route.ts +10 -0
- package/templates/express/src/features/auth/auth.service.ts +21 -0
- package/templates/express/src/middlewares/error.middleware.ts +5 -5
- package/templates/express/src/server.ts +3 -3
- package/templates/express/template.json +34 -1
- package/templates/express/tsconfig.json +17 -1
- package/templates/nextjs/app/layout.tsx +1 -5
- package/templates/nextjs/app/page.tsx +26 -34
- package/templates/nextjs/package.json +2 -1
- package/templates/nextjs/template.json +13 -1
- package/templates/react-vite/eslint.config.js +9 -9
- package/templates/react-vite/package.json +1 -2
- package/templates/react-vite/src/api/client.ts +16 -16
- package/templates/react-vite/src/api/services/user.service.ts +2 -10
- package/templates/react-vite/src/components/ErrorBoundary.tsx +4 -4
- package/templates/react-vite/src/components/Layout.tsx +1 -1
- package/templates/react-vite/src/components/Loading.tsx +1 -1
- package/templates/react-vite/src/components/SEO.tsx +5 -5
- package/templates/react-vite/src/config/constants.ts +3 -3
- package/templates/react-vite/src/hooks/index.ts +5 -5
- package/templates/react-vite/src/lib/queryClient.ts +2 -2
- package/templates/react-vite/src/main.tsx +12 -12
- package/templates/react-vite/src/pages/About.tsx +6 -2
- package/templates/react-vite/src/pages/Home.tsx +8 -4
- package/templates/react-vite/src/pages/NotFound.tsx +2 -2
- package/templates/react-vite/src/pages/UserProfile.tsx +6 -6
- package/templates/react-vite/src/router.tsx +13 -13
- package/templates/react-vite/src/types/{api.ts → api.d.ts} +6 -6
- package/templates/react-vite/src/types/user.d.ts +6 -0
- package/templates/react-vite/src/utils/helpers.ts +11 -11
- package/templates/react-vite/src/utils/storage.ts +4 -4
- package/templates/react-vite/template.json +26 -0
- package/templates/react-vite/tsconfig.json +1 -4
- package/templates/react-vite/vite.config.ts +5 -5
- package/dist/lib/template-composer.d.ts +0 -16
- package/dist/lib/template-composer.js +0 -197
- package/modules/auth/better-auth-express/adapters/mongoose-mongodb.ts +0 -13
- package/modules/auth/better-auth-express/adapters/prisma-mongodb.ts +0 -15
- package/modules/auth/better-auth-express/adapters/prisma-postgresql.ts +0 -15
- package/modules/auth/better-auth-express/files/lib/auth.ts +0 -16
- package/modules/auth/better-auth-express/files/routes/auth.ts +0 -12
- package/modules/auth/better-auth-express/files/schemas/prisma-mongodb-schema.prisma +0 -72
- package/modules/auth/better-auth-express/files/schemas/prisma-postgresql-schema.prisma +0 -72
- package/modules/auth/better-auth-express/module.json +0 -61
- package/modules/auth/better-auth-nextjs/adapters/mongoose-mongodb.ts +0 -24
- package/modules/auth/better-auth-nextjs/adapters/prisma-mongodb.ts +0 -26
- package/modules/auth/better-auth-nextjs/adapters/prisma-postgresql.ts +0 -26
- package/modules/auth/better-auth-nextjs/files/api/auth/[...all]/route.ts +0 -5
- package/modules/auth/better-auth-nextjs/files/lib/auth.ts +0 -26
- package/modules/auth/better-auth-nextjs/files/schemas/prisma-mongodb-schema.prisma +0 -72
- package/modules/auth/better-auth-nextjs/files/schemas/prisma-postgresql-schema.prisma +0 -72
- package/modules/auth/better-auth-nextjs/module.json +0 -62
- package/modules/auth/better-auth-react/files/lib/auth-client.ts +0 -9
- package/modules/auth/better-auth-react/module.json +0 -28
- package/modules/auth/clerk-express/module.json +0 -34
- package/modules/auth/clerk-nextjs/files/middleware.ts +0 -9
- package/modules/auth/clerk-nextjs/module.json +0 -64
- package/modules/auth/clerk-react/module.json +0 -28
- package/modules/database/prisma-mongodb/files/lib/db.ts +0 -9
- package/modules/database/prisma-mongodb/files/prisma/schema.prisma +0 -17
- package/modules/database/prisma-mongodb/module.json +0 -60
- package/modules/database/prisma-postgresql/files/lib/db.ts +0 -9
- package/modules/database/prisma-postgresql/files/prisma/schema.prisma +0 -17
- package/modules/database/prisma-postgresql/module.json +0 -60
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
import { createBrowserRouter } from
|
|
2
|
-
import { userService } from
|
|
3
|
-
import { ErrorBoundary } from
|
|
4
|
-
import Layout from
|
|
5
|
-
import About from
|
|
6
|
-
import Home from
|
|
7
|
-
import NotFound from
|
|
8
|
-
import UserProfile from
|
|
1
|
+
import { createBrowserRouter } from "react-router";
|
|
2
|
+
import { userService } from "./api/services/user.service";
|
|
3
|
+
import { ErrorBoundary } from "./components/ErrorBoundary";
|
|
4
|
+
import Layout from "./components/Layout";
|
|
5
|
+
import About from "./pages/About";
|
|
6
|
+
import Home from "./pages/Home";
|
|
7
|
+
import NotFound from "./pages/NotFound";
|
|
8
|
+
import UserProfile from "./pages/UserProfile";
|
|
9
9
|
|
|
10
10
|
export const router = createBrowserRouter([
|
|
11
11
|
{
|
|
12
|
-
path:
|
|
12
|
+
path: "/",
|
|
13
13
|
Component: Layout,
|
|
14
14
|
errorElement: <ErrorBoundary />,
|
|
15
15
|
children: [
|
|
16
16
|
{ index: true, Component: Home },
|
|
17
|
-
{ path:
|
|
17
|
+
{ path: "about", Component: About },
|
|
18
18
|
{
|
|
19
|
-
path:
|
|
19
|
+
path: "users/:userId",
|
|
20
20
|
loader: async ({ params }) => {
|
|
21
21
|
const id = params.userId;
|
|
22
|
-
if (!id) throw new Response(
|
|
22
|
+
if (!id) throw new Response("Missing user id", { status: 400 });
|
|
23
23
|
const user = await userService.getUser(id);
|
|
24
24
|
return user;
|
|
25
25
|
},
|
|
26
26
|
Component: UserProfile,
|
|
27
27
|
},
|
|
28
|
-
{ path:
|
|
28
|
+
{ path: "*", Component: NotFound },
|
|
29
29
|
],
|
|
30
30
|
},
|
|
31
31
|
]);
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
type ApiResponse<T = unknown> = {
|
|
2
2
|
data: T;
|
|
3
3
|
message?: string;
|
|
4
4
|
status: number;
|
|
5
|
-
}
|
|
5
|
+
};
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
type PaginatedResponse<T> = {
|
|
8
8
|
data: T[];
|
|
9
9
|
total: number;
|
|
10
10
|
page: number;
|
|
11
11
|
pageSize: number;
|
|
12
12
|
totalPages: number;
|
|
13
|
-
}
|
|
13
|
+
};
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
type ApiError = {
|
|
16
16
|
message: string;
|
|
17
17
|
code?: string;
|
|
18
18
|
status?: number;
|
|
19
19
|
errors?: Record<string, string[]>;
|
|
20
|
-
}
|
|
20
|
+
};
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
export function cn(...classes: (string | boolean | undefined | null)[]): string {
|
|
2
|
-
return classes.filter(Boolean).join(
|
|
2
|
+
return classes.filter(Boolean).join(" ");
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
export function formatDate(date: Date | string): string {
|
|
6
|
-
const d = typeof date ===
|
|
7
|
-
return d.toLocaleDateString(
|
|
8
|
-
year:
|
|
9
|
-
month:
|
|
10
|
-
day:
|
|
6
|
+
const d = typeof date === "string" ? new Date(date) : date;
|
|
7
|
+
return d.toLocaleDateString("en-US", {
|
|
8
|
+
year: "numeric",
|
|
9
|
+
month: "long",
|
|
10
|
+
day: "numeric",
|
|
11
11
|
});
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export function truncate(str: string, maxLength: number): string {
|
|
15
15
|
if (str.length <= maxLength) return str;
|
|
16
|
-
return str.slice(0, maxLength) +
|
|
16
|
+
return str.slice(0, maxLength) + "...";
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export function delay(ms: number): Promise<void> {
|
|
@@ -22,7 +22,7 @@ export function delay(ms: number): Promise<void> {
|
|
|
22
22
|
|
|
23
23
|
export function debounce<T extends (...args: never[]) => unknown>(
|
|
24
24
|
func: T,
|
|
25
|
-
wait: number
|
|
25
|
+
wait: number,
|
|
26
26
|
): (...args: Parameters<T>) => void {
|
|
27
27
|
let timeout: ReturnType<typeof setTimeout> | null = null;
|
|
28
28
|
|
|
@@ -45,7 +45,7 @@ export function slugify(str: string): string {
|
|
|
45
45
|
return str
|
|
46
46
|
.toLowerCase()
|
|
47
47
|
.trim()
|
|
48
|
-
.replace(/[^\w\s-]/g,
|
|
49
|
-
.replace(/[\s_-]+/g,
|
|
50
|
-
.replace(/^-+|-+$/g,
|
|
48
|
+
.replace(/[^\w\s-]/g, "")
|
|
49
|
+
.replace(/[\s_-]+/g, "-")
|
|
50
|
+
.replace(/^-+|-+$/g, "");
|
|
51
51
|
}
|
|
@@ -4,7 +4,7 @@ export const storage = {
|
|
|
4
4
|
const item = localStorage.getItem(key);
|
|
5
5
|
return item ? JSON.parse(item) : (defaultValue ?? null);
|
|
6
6
|
} catch (error) {
|
|
7
|
-
console.error(
|
|
7
|
+
console.error("Error reading from localStorage:", error);
|
|
8
8
|
return defaultValue ?? null;
|
|
9
9
|
}
|
|
10
10
|
},
|
|
@@ -13,7 +13,7 @@ export const storage = {
|
|
|
13
13
|
try {
|
|
14
14
|
localStorage.setItem(key, JSON.stringify(value));
|
|
15
15
|
} catch (error) {
|
|
16
|
-
console.error(
|
|
16
|
+
console.error("Error writing to localStorage:", error);
|
|
17
17
|
}
|
|
18
18
|
},
|
|
19
19
|
|
|
@@ -21,7 +21,7 @@ export const storage = {
|
|
|
21
21
|
try {
|
|
22
22
|
localStorage.removeItem(key);
|
|
23
23
|
} catch (error) {
|
|
24
|
-
console.error(
|
|
24
|
+
console.error("Error removing from localStorage:", error);
|
|
25
25
|
}
|
|
26
26
|
},
|
|
27
27
|
|
|
@@ -29,7 +29,7 @@ export const storage = {
|
|
|
29
29
|
try {
|
|
30
30
|
localStorage.clear();
|
|
31
31
|
} catch (error) {
|
|
32
|
-
console.error(
|
|
32
|
+
console.error("Error clearing localStorage:", error);
|
|
33
33
|
}
|
|
34
34
|
},
|
|
35
35
|
};
|
|
@@ -16,5 +16,31 @@
|
|
|
16
16
|
"tsconfig.app.json",
|
|
17
17
|
"tsconfig.node.json",
|
|
18
18
|
"vite.config.ts"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"dev": "vite",
|
|
22
|
+
"build": "tsc -b && vite build",
|
|
23
|
+
"lint": "eslint .",
|
|
24
|
+
"lint:fix": "eslint . --fix",
|
|
25
|
+
"preview": "vite preview"
|
|
26
|
+
},
|
|
27
|
+
"jsScripts": {
|
|
28
|
+
"dev": "vite",
|
|
29
|
+
"build": "vite build",
|
|
30
|
+
"lint": "eslint .",
|
|
31
|
+
"lint:fix": "eslint . --fix",
|
|
32
|
+
"preview": "vite preview"
|
|
33
|
+
},
|
|
34
|
+
"fileReplacements": [
|
|
35
|
+
{
|
|
36
|
+
"file": "index.html",
|
|
37
|
+
"from": "/src/main.tsx",
|
|
38
|
+
"to": "/src/main.jsx"
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"file": "vite.config.ts",
|
|
42
|
+
"from": "main.tsx",
|
|
43
|
+
"to": "main.jsx"
|
|
44
|
+
}
|
|
19
45
|
]
|
|
20
46
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import tailwindcss from
|
|
2
|
-
import react from
|
|
3
|
-
import path from
|
|
4
|
-
import { defineConfig } from
|
|
1
|
+
import tailwindcss from "@tailwindcss/vite";
|
|
2
|
+
import react from "@vitejs/plugin-react";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { defineConfig } from "vite";
|
|
5
5
|
|
|
6
6
|
export default defineConfig({
|
|
7
7
|
plugins: [react(), tailwindcss()],
|
|
8
8
|
resolve: {
|
|
9
9
|
alias: {
|
|
10
|
-
|
|
10
|
+
"@": path.resolve(__dirname, "./src"),
|
|
11
11
|
},
|
|
12
12
|
},
|
|
13
13
|
});
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export declare class TemplateComposer {
|
|
2
|
-
private templatesDir;
|
|
3
|
-
constructor(templatesDir: string);
|
|
4
|
-
/**
|
|
5
|
-
* Compose a project from base + database + auth selections
|
|
6
|
-
*/
|
|
7
|
-
compose(targetDir: string, framework: string, database: string, auth: string): Promise<void>;
|
|
8
|
-
private loadConfig;
|
|
9
|
-
private getBaseFiles;
|
|
10
|
-
private collectFiles;
|
|
11
|
-
private copyFiles;
|
|
12
|
-
private mergeConfigs;
|
|
13
|
-
private writePackageJson;
|
|
14
|
-
private writeEnvFile;
|
|
15
|
-
private getAuthKey;
|
|
16
|
-
}
|
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.TemplateComposer = void 0;
|
|
7
|
-
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
8
|
-
const path_1 = __importDefault(require("path"));
|
|
9
|
-
class TemplateComposer {
|
|
10
|
-
constructor(templatesDir) {
|
|
11
|
-
this.templatesDir = templatesDir;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Compose a project from base + database + auth selections
|
|
15
|
-
*/
|
|
16
|
-
async compose(targetDir, framework, database, auth) {
|
|
17
|
-
const configs = [];
|
|
18
|
-
const filesToCopy = [];
|
|
19
|
-
// 1. Load base framework template
|
|
20
|
-
const baseConfig = await this.loadConfig(path_1.default.join(this.templatesDir, framework));
|
|
21
|
-
configs.push(baseConfig);
|
|
22
|
-
// Copy base files
|
|
23
|
-
const baseFiles = await this.getBaseFiles(framework);
|
|
24
|
-
filesToCopy.push(...baseFiles);
|
|
25
|
-
// 2. Load database configuration if not "none"
|
|
26
|
-
if (database !== 'none') {
|
|
27
|
-
const dbConfig = await this.loadConfig(path_1.default.join(this.templatesDir, 'databases', database));
|
|
28
|
-
// Check compatibility
|
|
29
|
-
if (dbConfig.compatibleWith?.frameworks &&
|
|
30
|
-
!dbConfig.compatibleWith.frameworks.includes(framework)) {
|
|
31
|
-
throw new Error(`${dbConfig.displayName} is not compatible with ${framework}`);
|
|
32
|
-
}
|
|
33
|
-
configs.push(dbConfig);
|
|
34
|
-
// Copy database files
|
|
35
|
-
const dbDir = path_1.default.join(this.templatesDir, 'databases', database);
|
|
36
|
-
const dbFiles = await this.collectFiles(dbDir);
|
|
37
|
-
filesToCopy.push(...dbFiles.map((f) => ({
|
|
38
|
-
source: f,
|
|
39
|
-
dest: path_1.default.join(targetDir, f.replace(dbDir + path_1.default.sep, '')),
|
|
40
|
-
})));
|
|
41
|
-
}
|
|
42
|
-
// 3. Load auth configuration if not "none"
|
|
43
|
-
if (auth !== 'none') {
|
|
44
|
-
const authKey = this.getAuthKey(framework, auth);
|
|
45
|
-
const authDir = path_1.default.join(this.templatesDir, 'auth', authKey);
|
|
46
|
-
if (await fs_extra_1.default.pathExists(authDir)) {
|
|
47
|
-
const authConfig = await this.loadConfig(authDir);
|
|
48
|
-
// Check compatibility
|
|
49
|
-
if (authConfig.compatibleWith?.frameworks &&
|
|
50
|
-
!authConfig.compatibleWith.frameworks.includes(framework)) {
|
|
51
|
-
throw new Error(`${authConfig.displayName} is not compatible with ${framework}`);
|
|
52
|
-
}
|
|
53
|
-
if (authConfig.compatibleWith?.databases &&
|
|
54
|
-
!authConfig.compatibleWith.databases.includes(database)) {
|
|
55
|
-
throw new Error(`${authConfig.displayName} is not compatible with ${database}`);
|
|
56
|
-
}
|
|
57
|
-
configs.push(authConfig);
|
|
58
|
-
// Copy auth files
|
|
59
|
-
const authFiles = await this.collectFiles(authDir);
|
|
60
|
-
filesToCopy.push(...authFiles.map((f) => ({
|
|
61
|
-
source: f,
|
|
62
|
-
dest: path_1.default.join(targetDir, f.replace(authDir + path_1.default.sep, '')),
|
|
63
|
-
})));
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
// 4. Merge all configurations
|
|
67
|
-
const mergedConfig = this.mergeConfigs(configs);
|
|
68
|
-
// 5. Copy all files
|
|
69
|
-
await this.copyFiles(filesToCopy);
|
|
70
|
-
// 6. Create/update package.json
|
|
71
|
-
await this.writePackageJson(targetDir, mergedConfig);
|
|
72
|
-
// 7. Create/update .env
|
|
73
|
-
await this.writeEnvFile(targetDir, mergedConfig);
|
|
74
|
-
}
|
|
75
|
-
async loadConfig(dir) {
|
|
76
|
-
const configPath = path_1.default.join(dir, 'config.json');
|
|
77
|
-
const templatePath = path_1.default.join(dir, 'template.json');
|
|
78
|
-
if (await fs_extra_1.default.pathExists(configPath)) {
|
|
79
|
-
return await fs_extra_1.default.readJson(configPath);
|
|
80
|
-
}
|
|
81
|
-
else if (await fs_extra_1.default.pathExists(templatePath)) {
|
|
82
|
-
return await fs_extra_1.default.readJson(templatePath);
|
|
83
|
-
}
|
|
84
|
-
throw new Error(`No configuration found in ${dir}`);
|
|
85
|
-
}
|
|
86
|
-
async getBaseFiles(framework) {
|
|
87
|
-
// For now, use existing complete template
|
|
88
|
-
// In future, this will use minimal base templates
|
|
89
|
-
const baseDir = path_1.default.join(this.templatesDir, 'next-prisma-postgres-shadcn');
|
|
90
|
-
const files = await this.collectFiles(baseDir);
|
|
91
|
-
return files.map((source) => ({
|
|
92
|
-
source,
|
|
93
|
-
dest: source.replace(baseDir, ''),
|
|
94
|
-
}));
|
|
95
|
-
}
|
|
96
|
-
async collectFiles(dir, exclude = ['config.json', 'template.json', 'node_modules']) {
|
|
97
|
-
const files = [];
|
|
98
|
-
if (!(await fs_extra_1.default.pathExists(dir))) {
|
|
99
|
-
return files;
|
|
100
|
-
}
|
|
101
|
-
const entries = await fs_extra_1.default.readdir(dir, { withFileTypes: true });
|
|
102
|
-
for (const entry of entries) {
|
|
103
|
-
if (exclude.includes(entry.name))
|
|
104
|
-
continue;
|
|
105
|
-
const fullPath = path_1.default.join(dir, entry.name);
|
|
106
|
-
if (entry.isDirectory()) {
|
|
107
|
-
const subFiles = await this.collectFiles(fullPath, exclude);
|
|
108
|
-
files.push(...subFiles);
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
files.push(fullPath);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return files;
|
|
115
|
-
}
|
|
116
|
-
async copyFiles(files) {
|
|
117
|
-
for (const { source, dest } of files) {
|
|
118
|
-
await fs_extra_1.default.ensureDir(path_1.default.dirname(dest));
|
|
119
|
-
await fs_extra_1.default.copy(source, dest, { overwrite: true });
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
mergeConfigs(configs) {
|
|
123
|
-
return configs.reduce((merged, config) => {
|
|
124
|
-
return {
|
|
125
|
-
...merged,
|
|
126
|
-
dependencies: {
|
|
127
|
-
...merged.dependencies,
|
|
128
|
-
...config.dependencies,
|
|
129
|
-
},
|
|
130
|
-
devDependencies: {
|
|
131
|
-
...merged.devDependencies,
|
|
132
|
-
...config.devDependencies,
|
|
133
|
-
},
|
|
134
|
-
scripts: {
|
|
135
|
-
...merged.scripts,
|
|
136
|
-
...config.scripts,
|
|
137
|
-
},
|
|
138
|
-
env: {
|
|
139
|
-
...merged.env,
|
|
140
|
-
...config.env,
|
|
141
|
-
},
|
|
142
|
-
};
|
|
143
|
-
}, {});
|
|
144
|
-
}
|
|
145
|
-
async writePackageJson(targetDir, config) {
|
|
146
|
-
const pkgPath = path_1.default.join(targetDir, 'package.json');
|
|
147
|
-
let pkg = {};
|
|
148
|
-
if (await fs_extra_1.default.pathExists(pkgPath)) {
|
|
149
|
-
pkg = await fs_extra_1.default.readJson(pkgPath);
|
|
150
|
-
}
|
|
151
|
-
// Merge dependencies and scripts
|
|
152
|
-
if (config.dependencies) {
|
|
153
|
-
pkg.dependencies = { ...pkg.dependencies, ...config.dependencies };
|
|
154
|
-
}
|
|
155
|
-
if (config.devDependencies) {
|
|
156
|
-
pkg.devDependencies = { ...pkg.devDependencies, ...config.devDependencies };
|
|
157
|
-
}
|
|
158
|
-
if (config.scripts) {
|
|
159
|
-
pkg.scripts = { ...pkg.scripts, ...config.scripts };
|
|
160
|
-
}
|
|
161
|
-
await fs_extra_1.default.writeJson(pkgPath, pkg, { spaces: 2 });
|
|
162
|
-
}
|
|
163
|
-
async writeEnvFile(targetDir, config) {
|
|
164
|
-
if (!config.env || Object.keys(config.env).length === 0) {
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
const envPath = path_1.default.join(targetDir, '.env');
|
|
168
|
-
const envExamplePath = path_1.default.join(targetDir, '.env.example');
|
|
169
|
-
const envContent = Object.entries(config.env)
|
|
170
|
-
.map(([key, value]) => `${key}="${value}"`)
|
|
171
|
-
.join('\n') + '\n';
|
|
172
|
-
// Append or create .env.example
|
|
173
|
-
if (await fs_extra_1.default.pathExists(envExamplePath)) {
|
|
174
|
-
const existing = await fs_extra_1.default.readFile(envExamplePath, 'utf-8');
|
|
175
|
-
if (!existing.includes(envContent)) {
|
|
176
|
-
await fs_extra_1.default.appendFile(envExamplePath, '\n' + envContent);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
else {
|
|
180
|
-
await fs_extra_1.default.writeFile(envExamplePath, envContent);
|
|
181
|
-
}
|
|
182
|
-
// Don't overwrite existing .env, but create if missing
|
|
183
|
-
if (!(await fs_extra_1.default.pathExists(envPath))) {
|
|
184
|
-
await fs_extra_1.default.writeFile(envPath, envContent);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
getAuthKey(framework, auth) {
|
|
188
|
-
// Map framework + auth to specific implementation
|
|
189
|
-
const mapping = {
|
|
190
|
-
'nextjs-nextauth': 'nextauth',
|
|
191
|
-
'nextjs-better-auth': 'better-auth-nextjs',
|
|
192
|
-
'express-better-auth': 'better-auth-express',
|
|
193
|
-
};
|
|
194
|
-
return mapping[`${framework}-${auth}`] || auth;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
exports.TemplateComposer = TemplateComposer;
|
|
@@ -1,13 +0,0 @@
|
|
|
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;
|
|
@@ -1,15 +0,0 @@
|
|
|
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;
|
|
@@ -1,15 +0,0 @@
|
|
|
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;
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import { betterAuth } from 'better-auth';
|
|
2
|
-
|
|
3
|
-
export const auth = betterAuth({
|
|
4
|
-
secret: process.env.BETTER_AUTH_SECRET!,
|
|
5
|
-
baseURL: process.env.BETTER_AUTH_URL!,
|
|
6
|
-
|
|
7
|
-
emailAndPassword: {
|
|
8
|
-
enabled: true,
|
|
9
|
-
},
|
|
10
|
-
|
|
11
|
-
// Uncomment to add database adapter
|
|
12
|
-
// database: {
|
|
13
|
-
// provider: "pg", // or "mongodb", "mysql"
|
|
14
|
-
// url: process.env.DATABASE_URL!,
|
|
15
|
-
// },
|
|
16
|
-
});
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { Router } from 'express';
|
|
2
|
-
import { auth } from '../lib/auth';
|
|
3
|
-
|
|
4
|
-
const router = Router();
|
|
5
|
-
|
|
6
|
-
// Mount Better Auth handlers
|
|
7
|
-
router.all('/auth/*', async (req, res) => {
|
|
8
|
-
const response = await auth.handler(req);
|
|
9
|
-
return res.status(response.status).json(response.body);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
export default router;
|
|
@@ -1,72 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1,72 +0,0 @@
|
|
|
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
|
-
}
|