create-stackkit-app 0.4.4 → 0.4.5

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.
Files changed (55) hide show
  1. package/README.md +1 -1
  2. package/dist/index.js +62 -4
  3. package/dist/lib/create-project.d.ts +20 -1
  4. package/dist/lib/create-project.js +133 -48
  5. package/dist/lib/utils/config-utils.js +56 -1
  6. package/dist/lib/utils/logger.d.ts +16 -0
  7. package/dist/lib/utils/logger.js +59 -0
  8. package/dist/lib/utils/module-utils.js +346 -196
  9. package/dist/lib/utils/package-utils.js +2 -2
  10. package/modules/auth/authjs/files/api/auth/[...nextauth]/route.ts +6 -0
  11. package/modules/auth/authjs/files/lib/auth-client.ts +11 -0
  12. package/modules/auth/authjs/files/lib/auth.ts +41 -0
  13. package/modules/auth/authjs/files/schemas/prisma-schema.prisma +45 -0
  14. package/modules/auth/authjs/module.json +95 -0
  15. package/modules/auth/better-auth/files/lib/auth-client.ts +7 -0
  16. package/modules/auth/better-auth/files/lib/auth.ts +62 -0
  17. package/modules/auth/better-auth/files/lib/email-service.ts +34 -0
  18. package/modules/auth/better-auth/files/lib/email-templates.ts +89 -0
  19. package/modules/auth/better-auth/files/schemas/prisma-schema.prisma +1 -1
  20. package/modules/auth/better-auth/module.json +164 -27
  21. package/modules/database/mongoose/files/lib/db.ts +68 -0
  22. package/modules/database/{mongoose-mongodb → mongoose}/files/models/User.ts +0 -5
  23. package/modules/database/{mongoose-mongodb → mongoose}/module.json +9 -24
  24. package/modules/database/prisma/files/lib/prisma.ts +1 -3
  25. package/modules/database/prisma/files/prisma/schema.prisma +1 -1
  26. package/modules/database/prisma/files/prisma.config.ts +2 -2
  27. package/modules/database/prisma/module.json +5 -23
  28. package/package.json +1 -1
  29. package/templates/express/.env.example +0 -1
  30. package/templates/express/package.json +4 -4
  31. package/templates/express/src/app.ts +2 -2
  32. package/templates/express/src/features/health/health.controller.ts +18 -0
  33. package/templates/express/src/features/health/health.route.ts +9 -0
  34. package/templates/express/src/features/health/health.service.ts +6 -0
  35. package/templates/nextjs/lib/env.ts +8 -0
  36. package/templates/nextjs/package.json +7 -7
  37. package/templates/react-vite/.env.example +1 -2
  38. package/templates/react-vite/.prettierignore +4 -0
  39. package/templates/react-vite/.prettierrc +9 -0
  40. package/templates/react-vite/README.md +22 -0
  41. package/templates/react-vite/package.json +16 -16
  42. package/templates/react-vite/src/router.tsx +0 -12
  43. package/templates/react-vite/vite.config.ts +0 -6
  44. package/modules/auth/clerk/files/express/auth.ts +0 -7
  45. package/modules/auth/clerk/files/nextjs/auth-provider.tsx +0 -5
  46. package/modules/auth/clerk/files/nextjs/middleware.ts +0 -9
  47. package/modules/auth/clerk/files/react/auth-provider.tsx +0 -15
  48. package/modules/auth/clerk/module.json +0 -115
  49. package/modules/database/mongoose-mongodb/files/lib/db.ts +0 -78
  50. package/templates/express/src/features/auth/auth.controller.ts +0 -48
  51. package/templates/express/src/features/auth/auth.route.ts +0 -10
  52. package/templates/express/src/features/auth/auth.service.ts +0 -21
  53. package/templates/react-vite/src/api/services/user.service.ts +0 -18
  54. package/templates/react-vite/src/pages/UserProfile.tsx +0 -40
  55. package/templates/react-vite/src/types/user.d.ts +0 -6
@@ -42,27 +42,77 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
42
42
  const path_1 = __importStar(require("path"));
43
43
  const config_utils_1 = require("./config-utils");
44
44
  const file_utils_1 = require("./file-utils");
45
- async function mergeDatabaseConfig(templatesDir, targetDir, database, framework, dbProvider) {
46
- const modulesDir = (0, path_1.join)(templatesDir, "..", "modules");
47
- const dbModulePath = (0, path_1.join)(modulesDir, "database", database);
48
- if (!(await fs_extra_1.default.pathExists(dbModulePath))) {
49
- // eslint-disable-next-line no-console
50
- console.warn(`Database module not found: ${database}`);
51
- return [];
45
+ const logger_1 = require("./logger");
46
+ /**
47
+ * Process environment variables with variable replacement
48
+ */
49
+ function processEnvVars(envVarList, variables) {
50
+ const envVars = {};
51
+ for (const envVar of envVarList) {
52
+ let value = envVar.value;
53
+ for (const [key, val] of Object.entries(variables)) {
54
+ value = value.replace(new RegExp(`{{${key}}}`, "g"), val);
55
+ }
56
+ envVars[envVar.key] = value;
52
57
  }
53
- // Read module.json
54
- const moduleJsonPath = (0, path_1.join)(dbModulePath, "module.json");
55
- if (!(await fs_extra_1.default.pathExists(moduleJsonPath))) {
56
- return [];
58
+ return envVars;
59
+ }
60
+ /**
61
+ * Get framework-specific paths for file placement
62
+ */
63
+ function getFrameworkPaths(framework) {
64
+ switch (framework) {
65
+ case "nextjs":
66
+ return { lib: "lib", router: "app", models: "lib/models" };
67
+ case "express":
68
+ return { lib: "lib", router: "src", models: "lib/models" };
69
+ case "react-vite":
70
+ return { lib: "src/lib", router: "src", models: "src/models" };
71
+ default:
72
+ return { lib: "src/lib", router: "src", models: "src/models" };
57
73
  }
58
- const moduleData = await fs_extra_1.default.readJson(moduleJsonPath);
74
+ }
75
+ /**
76
+ * Generate variables based on database, framework, and provider
77
+ */
78
+ function generateVariables(database, framework, dbProvider, auth) {
59
79
  const variables = {};
80
+ // Database-specific variables
81
+ variables.dbFile = database === "prisma" ? "prisma.ts" : "db.ts";
82
+ variables.dbDescription =
83
+ database === "prisma"
84
+ ? "Create Prisma client singleton"
85
+ : "Create MongoDB connection with Mongoose";
86
+ // Auth-specific variables
87
+ if (auth) {
88
+ variables.authFile = "auth.ts";
89
+ variables.authDescription = `Create ${auth} authentication configuration`;
90
+ // Dynamic dbImport for auth modules
91
+ const libPath = framework === "nextjs" ? "@/lib" : ".";
92
+ const adapterImport = 'import { prismaAdapter } from "better-auth/adapters/prisma";';
93
+ if (database === "prisma") {
94
+ variables.dbImport = `import { prisma } from "${libPath}/prisma";
95
+ ${adapterImport}`;
96
+ }
97
+ else {
98
+ variables.dbImport =
99
+ database === "prisma"
100
+ ? `import { prisma } from "${libPath}/prisma";`
101
+ : `import { client } from "${libPath}/db";`;
102
+ }
103
+ }
104
+ else {
105
+ // Framework-specific database import for database modules
106
+ const libPath = framework === "nextjs" ? "@/lib" : ".";
107
+ variables.dbImport = database === "prisma" ? `${libPath}/prisma` : `${libPath}/db`;
108
+ }
109
+ // Provider-specific variables
60
110
  if (dbProvider) {
61
111
  variables.provider = dbProvider;
62
- if (dbProvider === "postgresql") {
63
- variables.connectionString = "postgresql://user:password@localhost:5432/mydb?schema=public";
64
- variables.prismaClientInit = `
65
- import { PrismaPg } from "@prisma/adapter-pg";
112
+ switch (dbProvider) {
113
+ case "postgresql":
114
+ variables.connectionString = "postgresql://user:password@localhost:5432/mydb?schema=public";
115
+ variables.prismaClientInit = `import { PrismaPg } from "@prisma/adapter-pg";
66
116
 
67
117
  const globalForPrisma = global as unknown as {
68
118
  prisma: PrismaClient | undefined;
@@ -78,17 +128,16 @@ const prisma = globalForPrisma.prisma ?? new PrismaClient({
78
128
 
79
129
  if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
80
130
  `;
81
- }
82
- else if (dbProvider === "mongodb") {
83
- variables.connectionString = "mongodb+srv://username:password@cluster.mongodb.net/mydb";
84
- variables.prismaClientInit = `
131
+ break;
132
+ case "mongodb":
133
+ variables.connectionString = "mongodb+srv://username:password@cluster.mongodb.net/mydb";
134
+ variables.prismaClientInit = `
85
135
  const prisma = new PrismaClient()
86
136
  `;
87
- }
88
- else if (dbProvider === "mysql") {
89
- variables.connectionString = "mysql://user:password@localhost:3306/mydb";
90
- variables.prismaClientInit = `
91
- import { PrismaMariaDb } from '@prisma/adapter-mariadb';
137
+ break;
138
+ case "mysql":
139
+ variables.connectionString = "mysql://user:password@localhost:3306/mydb";
140
+ variables.prismaClientInit = `import { PrismaMariaDb } from '@prisma/adapter-mariadb';
92
141
 
93
142
  const adapter = new PrismaMariaDb({
94
143
  host: process.env.DATABASE_HOST,
@@ -99,213 +148,314 @@ const adapter = new PrismaMariaDb({
99
148
  });
100
149
  const prisma = new PrismaClient({ adapter });
101
150
  `;
102
- }
103
- else if (dbProvider === "sqlite") {
104
- variables.connectionString = "file:./dev.db";
105
- variables.prismaClientInit = `
106
- import { PrismaBetterSqlite3 } from "@prisma/adapter-better-sqlite3";
151
+ break;
152
+ case "sqlite":
153
+ variables.connectionString = "file:./dev.db";
154
+ variables.prismaClientInit = `import { PrismaBetterSqlite3 } from "@prisma/adapter-better-sqlite3";
107
155
 
108
156
  const adapter = new PrismaBetterSqlite3({ url: process.env.DATABASE_URL });
109
157
  const prisma = new PrismaClient({ adapter });
110
158
  `;
159
+ break;
111
160
  }
112
161
  }
113
- const filesDir = (0, path_1.join)(dbModulePath, "files");
114
- if (await fs_extra_1.default.pathExists(filesDir)) {
115
- const libDir = framework === "nextjs" ? "lib" : "src";
116
- for (const patch of moduleData.patches || []) {
117
- if (patch.type === "create-file") {
118
- const sourceFile = (0, path_1.join)(filesDir, patch.source);
119
- let destFile = (0, path_1.join)(targetDir, patch.destination);
120
- destFile = destFile
121
- .replace("{{lib}}", libDir)
122
- .replace("{{src}}", "src")
123
- .replace("{{models}}", framework === "nextjs" ? "models" : "src/models");
124
- if (await fs_extra_1.default.pathExists(sourceFile)) {
125
- await fs_extra_1.default.ensureDir((0, path_1.join)(destFile, ".."));
126
- // Check if text file
127
- const ext = path_1.default.extname(sourceFile);
128
- if ([".ts", ".js", ".prisma", ".json"].includes(ext)) {
129
- let content = await fs_extra_1.default.readFile(sourceFile, "utf-8");
130
- for (const [key, value] of Object.entries(variables)) {
131
- content = content.replace(new RegExp(`{{${key}}}`, "g"), value);
132
- }
133
- await fs_extra_1.default.writeFile(destFile, content);
162
+ return variables;
163
+ }
164
+ /**
165
+ * Process a single patch with variable replacement
166
+ */
167
+ async function processPatch(patch, filesDir, targetDir, variables, frameworkPaths) {
168
+ if (patch.type === "create-file") {
169
+ if (!patch.source || !patch.destination)
170
+ return;
171
+ try {
172
+ // Replace variables in source and destination
173
+ const sourcePath = patch.source.replace(/\{\{(\w+)\}\}/g, (match, key) => variables[key] || match);
174
+ const sourceFile = (0, path_1.join)(filesDir, sourcePath);
175
+ let destFile = (0, path_1.join)(targetDir, patch.destination.replace(/\{\{(\w+)\}\}/g, (match, key) => variables[key] || match));
176
+ // Apply framework-specific path replacements
177
+ destFile = destFile
178
+ .replace("{{lib}}", frameworkPaths.lib)
179
+ .replace("{{router}}", frameworkPaths.router)
180
+ .replace("{{models}}", frameworkPaths.models);
181
+ if (!(await fs_extra_1.default.pathExists(sourceFile))) {
182
+ logger_1.logger.warn(`Source file not found: ${sourceFile}`);
183
+ return;
184
+ }
185
+ await fs_extra_1.default.ensureDir(path_1.default.dirname(destFile));
186
+ const ext = path_1.default.extname(sourceFile);
187
+ if ([".ts", ".js", ".tsx", ".prisma", ".json"].includes(ext)) {
188
+ let content = await fs_extra_1.default.readFile(sourceFile, "utf-8");
189
+ for (const [key, value] of Object.entries(variables)) {
190
+ content = content.replace(new RegExp(`{{${key}}}`, "g"), value);
191
+ }
192
+ await fs_extra_1.default.writeFile(destFile, content);
193
+ }
194
+ else {
195
+ await fs_extra_1.default.copy(sourceFile, destFile, { overwrite: false });
196
+ }
197
+ }
198
+ catch (error) {
199
+ logger_1.logger.error(`Failed to process patch ${patch.description}: ${error.message}`);
200
+ throw error;
201
+ }
202
+ }
203
+ else if (patch.type === "patch-file") {
204
+ if (!patch.file)
205
+ return;
206
+ try {
207
+ const filePath = (0, path_1.join)(targetDir, patch.file);
208
+ if (!(await fs_extra_1.default.pathExists(filePath))) {
209
+ logger_1.logger.warn(`File to patch not found: ${filePath}`);
210
+ return;
211
+ }
212
+ let content = await fs_extra_1.default.readFile(filePath, "utf-8");
213
+ for (const operation of patch.operations || []) {
214
+ if (operation.type === "add-import" && operation.imports) {
215
+ // Add imports at the top of the file, after existing imports
216
+ const imports = operation.imports.join("\n");
217
+ // Find the last import statement
218
+ const importRegex = /^import\s+.*$/gm;
219
+ const matches = [...content.matchAll(importRegex)];
220
+ if (matches.length > 0) {
221
+ const lastImport = matches[matches.length - 1];
222
+ const insertIndex = (lastImport.index ?? 0) + lastImport[0].length;
223
+ content = content.slice(0, insertIndex) + "\n" + imports + content.slice(insertIndex);
134
224
  }
135
225
  else {
136
- await fs_extra_1.default.copy(sourceFile, destFile, { overwrite: false });
226
+ // No imports found, add at the beginning
227
+ content = imports + "\n\n" + content;
228
+ }
229
+ }
230
+ else if (operation.type === "add-code") {
231
+ if (operation.after && operation.code) {
232
+ const insertIndex = content.indexOf(operation.after);
233
+ if (insertIndex !== -1) {
234
+ const afterIndex = insertIndex + operation.after.length;
235
+ content = content.slice(0, afterIndex) + operation.code + content.slice(afterIndex);
236
+ }
137
237
  }
138
238
  }
139
239
  }
240
+ await fs_extra_1.default.writeFile(filePath, content);
140
241
  }
141
- }
142
- const dependencies = {
143
- ...moduleData.dependencies.common,
144
- ...(dbProvider ? moduleData.dependencies.providers[dbProvider] : {}),
145
- };
146
- const devDependencies = {
147
- ...moduleData.devDependencies.common,
148
- ...(dbProvider ? moduleData.devDependencies.providers[dbProvider] : {}),
149
- };
150
- await (0, file_utils_1.mergePackageJson)(targetDir, {
151
- dependencies,
152
- devDependencies,
153
- });
154
- const envVars = {};
155
- const commonEnvVars = Array.isArray(moduleData.envVars) ? moduleData.envVars : moduleData.envVars?.common || [];
156
- const providerEnvVars = dbProvider && moduleData.envVars?.providers?.[dbProvider] ? moduleData.envVars.providers[dbProvider] : [];
157
- const allEnvVars = [...commonEnvVars, ...providerEnvVars];
158
- for (const envVar of allEnvVars) {
159
- let value = envVar.value;
160
- for (const [key, val] of Object.entries(variables)) {
161
- value = value.replace(new RegExp(`{{${key}}}`, "g"), val);
162
- }
163
- envVars[envVar.key] = value;
164
- }
165
- await (0, file_utils_1.mergeEnvFile)(targetDir, envVars);
166
- if (moduleData.frameworkPatches) {
167
- const frameworkKey = framework === "react-vite" ? "react" : framework;
168
- const patches = moduleData.frameworkPatches[frameworkKey];
169
- if (patches) {
170
- await (0, config_utils_1.applyFrameworkPatches)(targetDir, patches);
242
+ catch (error) {
243
+ logger_1.logger.error(`Failed to process patch-file ${patch.description}: ${error.message}`);
244
+ throw error;
171
245
  }
172
246
  }
173
- return moduleData.postInstall || [];
174
247
  }
175
- async function mergeAuthConfig(templatesDir, targetDir, framework, auth, database = "none", dbProvider) {
176
- const modulesDir = (0, path_1.join)(templatesDir, "..", "modules");
177
- const authKey = auth;
178
- const authModulePath = (0, path_1.join)(modulesDir, "auth", authKey);
179
- if (!(await fs_extra_1.default.pathExists(authModulePath))) {
180
- // eslint-disable-next-line no-console
181
- console.warn(`Auth module not found: ${authKey}`);
182
- return;
183
- }
184
- // Read module.json
185
- const moduleJsonPath = (0, path_1.join)(authModulePath, "module.json");
248
+ /**
249
+ * Validate and extract module data
250
+ */
251
+ async function loadModuleData(modulePath) {
252
+ const moduleJsonPath = (0, path_1.join)(modulePath, "module.json");
186
253
  if (!(await fs_extra_1.default.pathExists(moduleJsonPath))) {
187
- return;
254
+ throw new Error(`Module configuration not found: ${moduleJsonPath}`);
188
255
  }
189
256
  const moduleData = await fs_extra_1.default.readJson(moduleJsonPath);
190
- if (moduleData.supportedFrameworks && !moduleData.supportedFrameworks.includes(framework)) {
191
- // eslint-disable-next-line no-console
192
- console.warn(`Auth ${authKey} does not support framework ${framework}`);
193
- return;
257
+ if (!moduleData) {
258
+ throw new Error(`Invalid module configuration: ${moduleJsonPath}`);
194
259
  }
195
- let frameworkConfig = null;
196
- if (moduleData.frameworkConfigs) {
197
- frameworkConfig = moduleData.frameworkConfigs[framework];
198
- if (!frameworkConfig) {
199
- // eslint-disable-next-line no-console
200
- console.warn(`No config for framework ${framework} in ${authKey}`);
201
- return;
260
+ return moduleData;
261
+ }
262
+ async function mergeDatabaseConfig(templatesDir, targetDir, database, framework, dbProvider) {
263
+ try {
264
+ const modulesDir = (0, path_1.join)(templatesDir, "..", "modules");
265
+ const dbModulePath = (0, path_1.join)(modulesDir, "database", database);
266
+ if (!(await fs_extra_1.default.pathExists(dbModulePath))) {
267
+ logger_1.logger.warn(`Database module not found: ${database}`);
268
+ return [];
202
269
  }
270
+ const moduleData = await loadModuleData(dbModulePath);
271
+ const variables = generateVariables(database, framework, dbProvider);
272
+ const frameworkPaths = getFrameworkPaths(framework);
273
+ const filesDir = (0, path_1.join)(dbModulePath, "files");
274
+ if (await fs_extra_1.default.pathExists(filesDir)) {
275
+ for (const patch of moduleData.patches || []) {
276
+ await processPatch(patch, filesDir, targetDir, variables, frameworkPaths);
277
+ }
278
+ }
279
+ // Merge dependencies
280
+ let dependencies = {};
281
+ let devDependencies = {};
282
+ if (moduleData.dependencies) {
283
+ if (moduleData.dependencies.common || moduleData.dependencies.providers) {
284
+ // Structured dependencies (common + providers)
285
+ dependencies = {
286
+ ...moduleData.dependencies.common,
287
+ ...(dbProvider ? moduleData.dependencies.providers?.[dbProvider] : {}),
288
+ };
289
+ }
290
+ else {
291
+ // Flat dependencies structure
292
+ dependencies = { ...moduleData.dependencies };
293
+ }
294
+ }
295
+ if (moduleData.devDependencies) {
296
+ if (moduleData.devDependencies.common || moduleData.devDependencies.providers) {
297
+ // Structured devDependencies
298
+ devDependencies = {
299
+ ...moduleData.devDependencies.common,
300
+ ...(dbProvider ? moduleData.devDependencies.providers?.[dbProvider] : {}),
301
+ };
302
+ }
303
+ else {
304
+ // Flat devDependencies structure
305
+ devDependencies = { ...moduleData.devDependencies };
306
+ }
307
+ }
308
+ await (0, file_utils_1.mergePackageJson)(targetDir, { dependencies, devDependencies });
309
+ // Process environment variables
310
+ const envVars = {};
311
+ const commonEnvVars = Array.isArray(moduleData.envVars)
312
+ ? moduleData.envVars
313
+ : moduleData.envVars?.common || [];
314
+ const providerEnvVars = dbProvider && moduleData.envVars?.providers?.[dbProvider]
315
+ ? moduleData.envVars.providers[dbProvider]
316
+ : [];
317
+ const allEnvVars = [...commonEnvVars, ...providerEnvVars];
318
+ Object.assign(envVars, processEnvVars(allEnvVars, variables));
319
+ await (0, file_utils_1.mergeEnvFile)(targetDir, envVars);
320
+ // Apply framework-specific patches
321
+ if (moduleData.frameworkPatches) {
322
+ const frameworkKey = framework === "react-vite" ? "react" : framework;
323
+ const patches = moduleData.frameworkPatches[frameworkKey];
324
+ if (patches) {
325
+ await (0, config_utils_1.applyFrameworkPatches)(targetDir, patches);
326
+ }
327
+ }
328
+ return moduleData.postInstall || [];
203
329
  }
204
- const variables = {};
205
- if (framework === "nextjs") {
206
- variables.dbImport = "@/lib/db";
207
- }
208
- else if (framework === "express") {
209
- variables.dbImport = "../db";
210
- }
211
- else {
212
- variables.dbImport = "../db";
330
+ catch (error) {
331
+ logger_1.logger.error(`Failed to merge database config for ${database}: ${error.message}`);
332
+ throw error;
213
333
  }
214
- const filesDir = (0, path_1.join)(authModulePath, "files");
215
- if (await fs_extra_1.default.pathExists(filesDir)) {
216
- const getReplacements = () => {
217
- if (framework === "nextjs") {
218
- return { lib: "lib", router: "app" };
334
+ }
335
+ async function mergeAuthConfig(templatesDir, targetDir, framework, auth, database = "none", dbProvider) {
336
+ try {
337
+ const modulesDir = (0, path_1.join)(templatesDir, "..", "modules");
338
+ const authModulePath = (0, path_1.join)(modulesDir, "auth", auth);
339
+ if (!(await fs_extra_1.default.pathExists(authModulePath))) {
340
+ logger_1.logger.warn(`Auth module not found: ${auth}`);
341
+ return;
342
+ }
343
+ const moduleData = await loadModuleData(authModulePath);
344
+ if (moduleData.supportedFrameworks && !moduleData.supportedFrameworks.includes(framework)) {
345
+ logger_1.logger.warn(`Auth ${auth} does not support framework ${framework}`);
346
+ return;
347
+ }
348
+ let frameworkConfig = null;
349
+ if (moduleData.frameworkConfigs) {
350
+ frameworkConfig = moduleData.frameworkConfigs[framework];
351
+ if (!frameworkConfig) {
352
+ logger_1.logger.warn(`No config for framework ${framework} in ${auth}`);
353
+ return;
219
354
  }
220
- else if (framework === "express") {
221
- return { lib: "src", router: "src" };
355
+ const shared = moduleData.frameworkConfigs.shared;
356
+ if (shared) {
357
+ frameworkConfig = {
358
+ ...shared,
359
+ ...frameworkConfig,
360
+ };
222
361
  }
223
- else {
224
- return { lib: "src", router: "src" };
362
+ }
363
+ const variables = generateVariables(database, framework, dbProvider, auth);
364
+ const frameworkPaths = getFrameworkPaths(framework);
365
+ // Handle database adapters first to set variables
366
+ if (database !== "none" && moduleData.databaseAdapters) {
367
+ let adapterKey = database;
368
+ if (database === "prisma" && dbProvider) {
369
+ adapterKey = `prisma-${dbProvider}`;
225
370
  }
226
- };
227
- const replacements = getReplacements();
228
- const patches = frameworkConfig?.patches || moduleData.patches || [];
229
- for (const patch of patches) {
230
- if (patch.type === "create-file") {
231
- const sourceFile = (0, path_1.join)(filesDir, patch.source);
232
- let destFile = (0, path_1.join)(targetDir, patch.destination);
233
- destFile = destFile
234
- .replace("{{lib}}", replacements.lib)
235
- .replace("{{router}}", replacements.router);
236
- if (await fs_extra_1.default.pathExists(sourceFile)) {
237
- await fs_extra_1.default.ensureDir(path_1.default.dirname(destFile));
238
- // Check if text file
239
- const ext = path_1.default.extname(sourceFile);
240
- if ([".ts", ".js", ".json"].includes(ext)) {
241
- let content = await fs_extra_1.default.readFile(sourceFile, "utf-8");
371
+ const adapterConfig = moduleData.databaseAdapters[adapterKey];
372
+ if (adapterConfig) {
373
+ // Generate adapter code based on database type
374
+ if (database === "prisma" && dbProvider) {
375
+ variables.databaseAdapter = `database: prismaAdapter(prisma, {\n provider: "${dbProvider}",\n }),`;
376
+ }
377
+ if (adapterConfig.schema && adapterConfig.schemaDestination) {
378
+ const schemaSource = (0, path_1.join)(authModulePath, adapterConfig.schema);
379
+ const schemaDest = (0, path_1.join)(targetDir, adapterConfig.schemaDestination);
380
+ if (await fs_extra_1.default.pathExists(schemaSource)) {
381
+ await fs_extra_1.default.ensureDir(path_1.default.dirname(schemaDest));
382
+ let content = await fs_extra_1.default.readFile(schemaSource, "utf-8");
383
+ // Set schema variables for Prisma
384
+ if (dbProvider === "postgresql") {
385
+ variables.provider = "postgresql";
386
+ variables.idDefault = "@default(cuid())";
387
+ variables.userIdType = "";
388
+ }
389
+ else if (dbProvider === "mongodb") {
390
+ variables.provider = "mongodb";
391
+ variables.idDefault = '@default(auto()) @map("_id") @db.ObjectId';
392
+ variables.userIdType = "@db.ObjectId";
393
+ }
394
+ else if (dbProvider === "mysql") {
395
+ variables.provider = "mysql";
396
+ variables.idDefault = "@default(cuid())";
397
+ variables.userIdType = "";
398
+ }
399
+ else if (dbProvider === "sqlite") {
400
+ variables.provider = "sqlite";
401
+ variables.idDefault = "@default(cuid())";
402
+ variables.userIdType = "";
403
+ }
242
404
  for (const [key, value] of Object.entries(variables)) {
243
405
  content = content.replace(new RegExp(`{{${key}}}`, "g"), value);
244
406
  }
245
- await fs_extra_1.default.writeFile(destFile, content);
246
- }
247
- else {
248
- await fs_extra_1.default.copy(sourceFile, destFile, { overwrite: false });
407
+ await fs_extra_1.default.writeFile(schemaDest, content, { flag: "a" }); // append
249
408
  }
250
409
  }
410
+ if (adapterConfig.dependencies) {
411
+ const commonDeps = moduleData.databaseAdapters.common?.dependencies || {};
412
+ const commonDevDeps = moduleData.databaseAdapters.common?.devDependencies || {};
413
+ const specificDeps = adapterConfig.dependencies;
414
+ const specificDevDeps = adapterConfig.devDependencies || {};
415
+ await (0, file_utils_1.mergePackageJson)(targetDir, {
416
+ dependencies: { ...commonDeps, ...specificDeps },
417
+ devDependencies: { ...commonDevDeps, ...specificDevDeps },
418
+ });
419
+ }
251
420
  }
252
421
  }
253
- }
254
- // Add framework-specific patches
255
- if (framework === "nextjs") {
256
- const apiSource = (0, path_1.join)(filesDir, "api/auth/[...all]/route.ts");
257
- const apiDest = (0, path_1.join)(targetDir, "app/api/auth/[...all]/route.ts");
258
- if (await fs_extra_1.default.pathExists(apiSource)) {
259
- await fs_extra_1.default.ensureDir(path_1.default.dirname(apiDest));
260
- await fs_extra_1.default.copy(apiSource, apiDest, { overwrite: false });
261
- }
262
- }
263
- if (database !== "none" && moduleData.databaseAdapters) {
264
- let adapterKey = database;
265
- if (database === "prisma" && dbProvider) {
266
- adapterKey = `prisma-${dbProvider}`;
422
+ const filesDir = (0, path_1.join)(authModulePath, "files");
423
+ if (await fs_extra_1.default.pathExists(filesDir)) {
424
+ const patches = frameworkConfig?.patches || moduleData.patches || [];
425
+ for (const patch of patches) {
426
+ await processPatch(patch, filesDir, targetDir, variables, frameworkPaths);
427
+ }
267
428
  }
268
- const adapterConfig = moduleData.databaseAdapters[adapterKey];
269
- if (adapterConfig) {
270
- variables.databaseAdapter = adapterConfig.adapterCode;
271
- if (adapterConfig.schema && adapterConfig.schemaDestination) {
272
- const schemaSource = (0, path_1.join)(authModulePath, adapterConfig.schema);
273
- const schemaDest = (0, path_1.join)(targetDir, adapterConfig.schemaDestination);
274
- if (await fs_extra_1.default.pathExists(schemaSource)) {
275
- await fs_extra_1.default.ensureDir(path_1.default.dirname(schemaDest));
276
- let content = await fs_extra_1.default.readFile(schemaSource, "utf-8");
277
- // Set schema variables
278
- if (dbProvider === "postgresql") {
279
- variables.provider = "postgresql";
280
- variables.idDefault = "@default(cuid())";
281
- variables.userIdType = "";
282
- }
283
- else if (dbProvider === "mongodb") {
284
- variables.provider = "mongodb";
285
- variables.idDefault = '@default(auto()) @map("_id") @db.ObjectId';
286
- variables.userIdType = "@db.ObjectId";
287
- }
288
- for (const [key, value] of Object.entries(variables)) {
289
- content = content.replace(new RegExp(`{{${key}}}`, "g"), value);
290
- }
291
- await fs_extra_1.default.writeFile(schemaDest, content, { flag: "a" }); // append
292
- }
429
+ // Add framework-specific patches
430
+ if (framework === "nextjs") {
431
+ const apiSource = (0, path_1.join)(filesDir, "api/auth/[...all]/route.ts");
432
+ const apiDest = (0, path_1.join)(targetDir, "app/api/auth/[...all]/route.ts");
433
+ if (await fs_extra_1.default.pathExists(apiSource)) {
434
+ await fs_extra_1.default.ensureDir(path_1.default.dirname(apiDest));
435
+ await fs_extra_1.default.copy(apiSource, apiDest, { overwrite: false });
293
436
  }
294
- if (adapterConfig.dependencies) {
295
- await (0, file_utils_1.mergePackageJson)(targetDir, {
296
- dependencies: adapterConfig.dependencies,
297
- });
437
+ }
438
+ // Merge package.json
439
+ await (0, file_utils_1.mergePackageJson)(targetDir, {
440
+ dependencies: frameworkConfig?.dependencies || moduleData.dependencies,
441
+ devDependencies: frameworkConfig?.devDependencies || moduleData.devDependencies,
442
+ });
443
+ // Process environment variables
444
+ const envVars = {};
445
+ const envVarList = frameworkConfig?.envVars || moduleData.envVars || [];
446
+ Object.assign(envVars, processEnvVars(envVarList, variables));
447
+ await (0, file_utils_1.mergeEnvFile)(targetDir, envVars);
448
+ // Apply framework-specific patches
449
+ if (moduleData.frameworkPatches) {
450
+ const frameworkKey = framework === "react-vite" ? "react" : framework;
451
+ const patches = moduleData.frameworkPatches[frameworkKey];
452
+ if (patches) {
453
+ await (0, config_utils_1.applyFrameworkPatches)(targetDir, patches);
298
454
  }
299
455
  }
300
456
  }
301
- await (0, file_utils_1.mergePackageJson)(targetDir, {
302
- dependencies: frameworkConfig?.dependencies || moduleData.dependencies,
303
- devDependencies: frameworkConfig?.devDependencies || moduleData.devDependencies,
304
- });
305
- const envVars = {};
306
- const envVarList = frameworkConfig?.envVars || moduleData.envVars || [];
307
- for (const envVar of envVarList) {
308
- envVars[envVar.key] = envVar.value;
457
+ catch (error) {
458
+ logger_1.logger.error(`Failed to merge auth config for ${auth}: ${error.message}`);
459
+ throw error;
309
460
  }
310
- await (0, file_utils_1.mergeEnvFile)(targetDir, envVars);
311
461
  }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.installDependencies = installDependencies;
4
4
  const child_process_1 = require("child_process");
5
+ const logger_1 = require("./logger");
5
6
  async function installDependencies(cwd, packageManager) {
6
7
  const commands = {
7
8
  npm: "npm install",
@@ -23,8 +24,7 @@ async function installDependencies(cwd, packageManager) {
23
24
  const fallbacks = ["pnpm", "npm", "yarn", "bun"];
24
25
  const found = fallbacks.find((p) => isAvailable(p));
25
26
  if (found) {
26
- // eslint-disable-next-line no-console
27
- console.warn(`Selected package manager '${chosen}' was not found. Falling back to '${found}'.`);
27
+ logger_1.logger.warn(`Selected package manager '${chosen}' was not found. Falling back to '${found}'.`);
28
28
  chosen = found;
29
29
  }
30
30
  else {
@@ -0,0 +1,6 @@
1
+ import NextAuth from "next-auth";
2
+ import { authOptions } from "@/lib/auth";
3
+
4
+ const handler = NextAuth(authOptions);
5
+
6
+ export { handler as GET, handler as POST };
@@ -0,0 +1,11 @@
1
+ import { getServerSession } from "next-auth/next";
2
+ import { authOptions } from "@/lib/auth";
3
+
4
+ export async function getSession() {
5
+ return await getServerSession(authOptions);
6
+ }
7
+
8
+ export async function getCurrentUser() {
9
+ const session = await getSession();
10
+ return session?.user;
11
+ }