stackkit 0.2.2 → 0.2.6

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 (34) hide show
  1. package/bin/stackkit.js +10 -3
  2. package/dist/cli/add.js +188 -61
  3. package/dist/cli/create.js +75 -35
  4. package/dist/cli/doctor.js +36 -161
  5. package/dist/cli/list.js +10 -40
  6. package/dist/index.js +6 -6
  7. package/dist/lib/conversion/js-conversion.js +27 -11
  8. package/dist/lib/discovery/installed-detection.d.ts +7 -0
  9. package/dist/lib/discovery/installed-detection.js +134 -0
  10. package/dist/lib/discovery/module-discovery.d.ts +1 -1
  11. package/dist/lib/discovery/module-discovery.js +26 -17
  12. package/dist/lib/discovery/shared.js +9 -7
  13. package/dist/lib/generation/code-generator.d.ts +2 -0
  14. package/dist/lib/generation/code-generator.js +98 -4
  15. package/dist/lib/generation/generator-utils.d.ts +1 -1
  16. package/dist/lib/generation/generator-utils.js +5 -3
  17. package/dist/lib/project/detect.js +59 -29
  18. package/dist/types/index.d.ts +21 -17
  19. package/modules/auth/better-auth/files/lib/auth.ts +2 -2
  20. package/package.json +13 -10
  21. package/templates/express/gitignore +23 -0
  22. package/templates/nextjs/gitignore +42 -0
  23. package/templates/nextjs/next-env.d.ts +6 -0
  24. package/templates/react/dist/assets/index-D4AHT4dU.js +193 -0
  25. package/templates/react/dist/assets/index-rpwj5ZOX.css +1 -0
  26. package/templates/react/dist/index.html +14 -0
  27. package/templates/react/dist/vite.svg +1 -0
  28. package/templates/react/gitignore +44 -0
  29. package/templates/react/src/utils/utils.ts +1 -1
  30. /package/templates/express/{.env.example → env.example} +0 -0
  31. /package/templates/nextjs/{.env.example → env.example} +0 -0
  32. /package/templates/react/{.env.example → env.example} +0 -0
  33. /package/templates/react/{.prettierignore → prettierignore} +0 -0
  34. /package/templates/react/{.prettierrc → prettierrc} +0 -0
@@ -52,7 +52,7 @@ async function discoverModules(modulesDir) {
52
52
  });
53
53
  }
54
54
  catch {
55
- // Silently skip invalid templates
55
+ // ignore invalid template
56
56
  }
57
57
  }
58
58
  }
@@ -83,7 +83,7 @@ async function discoverModules(modulesDir) {
83
83
  discovered.databases.push(metadata);
84
84
  }
85
85
  catch {
86
- // Silently skip invalid modules
86
+ // ignore invalid module
87
87
  }
88
88
  }
89
89
  }
@@ -105,7 +105,7 @@ async function discoverModules(modulesDir) {
105
105
  discovered.auth.push(metadata);
106
106
  }
107
107
  catch {
108
- // Silently skip invalid modules
108
+ // ignore invalid module
109
109
  }
110
110
  }
111
111
  }
@@ -128,11 +128,8 @@ function getValidDatabaseOptions(databases) {
128
128
  options.push("prisma");
129
129
  }
130
130
  }
131
- else if (db.name === "mongoose") {
132
- options.push("mongoose");
133
- }
134
131
  else {
135
- // For other databases, add the name directly
132
+ // For other databases, add the module name directly (generic handling)
136
133
  options.push(db.name);
137
134
  }
138
135
  }
@@ -152,7 +149,7 @@ function getValidAuthOptions(authModules) {
152
149
  /**
153
150
  * Get compatible auth options for given framework and database
154
151
  */
155
- function getCompatibleAuthOptions(authModules, framework, database) {
152
+ function getCompatibleAuthOptions(authModules, framework, database, frameworksMeta) {
156
153
  const compatible = [];
157
154
  for (const auth of authModules) {
158
155
  // Check if auth supports the framework
@@ -161,13 +158,27 @@ function getCompatibleAuthOptions(authModules, framework, database) {
161
158
  }
162
159
  // Normalize database option (handle prisma-<provider> values)
163
160
  const parsedDb = (0, shared_1.parseDatabaseOption)(database || "").database;
164
- // Special compatibility rules
165
- if (auth.name === "authjs" && (parsedDb !== "prisma" || framework !== "nextjs")) {
166
- continue;
161
+ // If module provides explicit compatibility matrix, use it
162
+ let dbCompatible = true;
163
+ if (auth.compatibility && auth.compatibility.databases) {
164
+ dbCompatible = auth.compatibility.databases.includes(parsedDb);
167
165
  }
168
- if (auth.name === "better-auth" && parsedDb === "none" && framework !== "react") {
169
- continue;
166
+ // If the framework template explicitly lists this auth as compatible,
167
+ // allow it even if the auth module's database compatibility would normally
168
+ // exclude the current database selection (covers cases like React where
169
+ // the framework can support auth without a DB).
170
+ let explicitlyAllowedByFramework = false;
171
+ if (frameworksMeta && Array.isArray(frameworksMeta)) {
172
+ const fw = frameworksMeta.find((f) => f.name === framework);
173
+ if (fw && fw.compatibility) {
174
+ const authList = fw.compatibility.auth;
175
+ if (Array.isArray(authList) && authList.includes(auth.name)) {
176
+ explicitlyAllowedByFramework = true;
177
+ }
178
+ }
170
179
  }
180
+ if (!dbCompatible && !explicitlyAllowedByFramework)
181
+ continue;
171
182
  compatible.push({
172
183
  name: auth.displayName,
173
184
  value: auth.name,
@@ -200,11 +211,9 @@ function getDatabaseChoices(databases, framework) {
200
211
  choices.push({ name: "Prisma", value: "prisma" });
201
212
  }
202
213
  }
203
- else if (db.name === "mongoose") {
204
- choices.push({ name: "Mongoose", value: "mongoose" });
205
- }
206
214
  else {
207
- choices.push({ name: db.displayName, value: db.name });
215
+ // Generic handling for other database modules
216
+ choices.push({ name: db.displayName || db.name, value: db.name });
208
217
  }
209
218
  }
210
219
  // Add "None" at the end
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.parseDatabaseOption = parseDatabaseOption;
7
7
  exports.getPrismaProvidersFromGenerator = getPrismaProvidersFromGenerator;
8
8
  exports.isPrismaOption = isPrismaOption;
9
+ const fs_extra_1 = __importDefault(require("fs-extra"));
9
10
  const path_1 = __importDefault(require("path"));
10
11
  const package_root_1 = require("../utils/package-root");
11
12
  function parseDatabaseOption(dbOption) {
@@ -19,20 +20,21 @@ function parseDatabaseOption(dbOption) {
19
20
  }
20
21
  if (dbOption === "prisma")
21
22
  return { database: "prisma" };
22
- if (dbOption === "mongoose")
23
- return { database: "mongoose" };
24
23
  return { database: dbOption };
25
24
  }
26
25
  function getPrismaProvidersFromGenerator(modulesDir) {
27
26
  const pkgRoot = modulesDir || (0, package_root_1.getPackageRoot)();
28
27
  const genPath = path_1.default.join(pkgRoot, "modules", "database", "prisma", "generator.json");
29
28
  try {
30
- const gen = require(genPath);
29
+ const gen = fs_extra_1.default.readJsonSync(genPath, { throws: false });
31
30
  const providers = new Set();
32
- if (Array.isArray(gen.operations)) {
33
- for (const op of gen.operations) {
34
- if (op.condition && op.condition.prismaProvider)
35
- providers.add(String(op.condition.prismaProvider));
31
+ const ops = gen && typeof gen === "object" ? gen["operations"] : undefined;
32
+ if (Array.isArray(ops)) {
33
+ for (const op of ops) {
34
+ const cond = op && typeof op === "object" ? op["condition"] : undefined;
35
+ if (cond && typeof cond["prismaProvider"] === "string") {
36
+ providers.add(String(cond["prismaProvider"]));
37
+ }
36
38
  }
37
39
  }
38
40
  return Array.from(providers);
@@ -53,6 +53,7 @@ export declare class AdvancedCodeGenerator {
53
53
  private generators;
54
54
  private frameworkConfig;
55
55
  private postInstallCommands;
56
+ private createdFiles;
56
57
  constructor(frameworkConfig: FrameworkConfig);
57
58
  loadGenerators(modulesPath: string): Promise<void>;
58
59
  private evaluateCondition;
@@ -65,6 +66,7 @@ export declare class AdvancedCodeGenerator {
65
66
  auth?: string;
66
67
  prismaProvider?: string;
67
68
  }, features: string[], outputPath: string): Promise<string[]>;
69
+ getCreatedFiles(): string[];
68
70
  private executeOperation;
69
71
  private copyTemplate;
70
72
  private processOperationTemplates;
@@ -36,12 +36,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.AdvancedCodeGenerator = void 0;
37
37
  const fs = __importStar(require("fs-extra"));
38
38
  const path = __importStar(require("path"));
39
+ const shared_1 = require("../discovery/shared");
39
40
  const package_root_1 = require("../utils/package-root");
40
41
  const generator_utils_1 = require("./generator-utils");
41
42
  class AdvancedCodeGenerator {
42
43
  constructor(frameworkConfig) {
43
44
  this.generators = new Map();
44
45
  this.postInstallCommands = [];
46
+ this.createdFiles = [];
45
47
  this.frameworkConfig = frameworkConfig;
46
48
  }
47
49
  async loadGenerators(modulesPath) {
@@ -60,7 +62,7 @@ class AdvancedCodeGenerator {
60
62
  this.generators.set(`${type}:${moduleName}`, config);
61
63
  }
62
64
  catch {
63
- // Silently skip invalid generator files
65
+ // ignore invalid generator files
64
66
  }
65
67
  }
66
68
  }
@@ -290,7 +292,10 @@ class AdvancedCodeGenerator {
290
292
  };
291
293
  // Set default prismaProvider if database is prisma but no provider specified
292
294
  if (selectedModules.database === "prisma" && !context.prismaProvider) {
293
- context.prismaProvider = "postgresql";
295
+ const providers = (0, shared_1.getPrismaProvidersFromGenerator)((0, package_root_1.getPackageRoot)());
296
+ if (providers && providers.length > 0) {
297
+ context.prismaProvider = providers[0];
298
+ }
294
299
  }
295
300
  // Collect all applicable operations
296
301
  const applicableOperations = [];
@@ -340,6 +345,9 @@ class AdvancedCodeGenerator {
340
345
  await this.generatePackageJson(selectedModules, features, outputPath);
341
346
  return this.postInstallCommands;
342
347
  }
348
+ getCreatedFiles() {
349
+ return this.createdFiles.slice();
350
+ }
343
351
  async executeOperation(operation, context, outputPath) {
344
352
  // Process templates in operation content
345
353
  const processedOperation = this.processOperationTemplates(operation, context);
@@ -388,7 +396,7 @@ class AdvancedCodeGenerator {
388
396
  }
389
397
  }
390
398
  catch {
391
- // ignore failures here — not critical
399
+ // ignore (not critical)
392
400
  }
393
401
  // Ensure gitignore is present in target even if template authors
394
402
  // renamed it to avoid npm/package issues (e.g. 'gitignore' or '_gitignore')
@@ -408,6 +416,81 @@ class AdvancedCodeGenerator {
408
416
  catch {
409
417
  // ignore
410
418
  }
419
+ // Ensure any top-level dotfiles declared in template.json are created
420
+ try {
421
+ const templateJsonPath = path.join(templatePath, "template.json");
422
+ if (await fs.pathExists(templateJsonPath)) {
423
+ const tpl = await fs.readJson(templateJsonPath);
424
+ if (tpl && Array.isArray(tpl.files)) {
425
+ for (const f of tpl.files) {
426
+ if (typeof f === "string" && f.startsWith(".")) {
427
+ const targetDest = path.join(outputPath, f);
428
+ if (await fs.pathExists(targetDest))
429
+ continue; // already present
430
+ // Special-case: allow creating .gitignore from non-dot fallbacks
431
+ if (f === ".gitignore") {
432
+ const nameWithoutDot = f.slice(1);
433
+ const candidates = [f, nameWithoutDot, `_${nameWithoutDot}`];
434
+ for (const cand of candidates) {
435
+ const src = path.join(templatePath, cand);
436
+ if (await fs.pathExists(src)) {
437
+ await fs.copy(src, targetDest);
438
+ break;
439
+ }
440
+ }
441
+ continue;
442
+ }
443
+ // For other dotfiles (e.g. .env.example), only create if the template
444
+ // actually contains a dotfile source. Don't synthesize from non-dot fallbacks
445
+ // to avoid creating files unintentionally.
446
+ const srcDot = path.join(templatePath, f);
447
+ if (await fs.pathExists(srcDot)) {
448
+ await fs.copy(srcDot, targetDest);
449
+ }
450
+ }
451
+ }
452
+ }
453
+ }
454
+ }
455
+ catch {
456
+ // ignore
457
+ }
458
+ try {
459
+ const templateJsonPath2 = path.join(templatePath, "template.json");
460
+ if (await fs.pathExists(templateJsonPath2)) {
461
+ const tpl = await fs.readJson(templateJsonPath2);
462
+ if (tpl && Array.isArray(tpl.files)) {
463
+ for (const f of tpl.files) {
464
+ if (typeof f === "string" && f.startsWith(".")) {
465
+ const dotDest = path.join(outputPath, f);
466
+ const nameWithoutDot = f.slice(1);
467
+ const nonDot = path.join(outputPath, nameWithoutDot);
468
+ const underscore = path.join(outputPath, `_${nameWithoutDot}`);
469
+ // If dot already exists, remove non-dot fallbacks
470
+ if (await fs.pathExists(dotDest)) {
471
+ if (await fs.pathExists(nonDot)) {
472
+ await fs.remove(nonDot);
473
+ }
474
+ if (await fs.pathExists(underscore)) {
475
+ await fs.remove(underscore);
476
+ }
477
+ continue;
478
+ }
479
+ // If dot doesn't exist but a non-dot fallback was copied, rename it
480
+ if (await fs.pathExists(nonDot)) {
481
+ await fs.move(nonDot, dotDest, { overwrite: true });
482
+ }
483
+ else if (await fs.pathExists(underscore)) {
484
+ await fs.move(underscore, dotDest, { overwrite: true });
485
+ }
486
+ }
487
+ }
488
+ }
489
+ }
490
+ }
491
+ catch {
492
+ // ignore
493
+ }
411
494
  }
412
495
  }
413
496
  processOperationTemplates(operation, context) {
@@ -481,6 +564,14 @@ class AdvancedCodeGenerator {
481
564
  }
482
565
  // Write destination file
483
566
  await fs.writeFile(destinationPath, content, "utf-8");
567
+ try {
568
+ const rel = path.relative(outputPath, destinationPath);
569
+ if (rel && !this.createdFiles.includes(rel))
570
+ this.createdFiles.push(rel);
571
+ }
572
+ catch {
573
+ // ignore logging failures
574
+ }
484
575
  }
485
576
  async executePatchFile(operation, context, outputPath) {
486
577
  if (!operation.destination)
@@ -755,7 +846,10 @@ class AdvancedCodeGenerator {
755
846
  features,
756
847
  };
757
848
  if (selectedModules.database === "prisma" && !context.prismaProvider) {
758
- context.prismaProvider = "postgresql";
849
+ const providers = (0, shared_1.getPrismaProvidersFromGenerator)((0, package_root_1.getPackageRoot)());
850
+ if (providers && providers.length > 0) {
851
+ context.prismaProvider = providers[0];
852
+ }
759
853
  }
760
854
  const applicableOperations = [];
761
855
  for (const [key, generator] of this.generators) {
@@ -1,5 +1,5 @@
1
- import type { GeneratorConfig } from "./code-generator";
2
1
  import type { ModuleMetadata } from "../../types";
2
+ import type { GeneratorConfig } from "./code-generator";
3
3
  export declare function mergeModuleIntoGeneratorConfig(config: GeneratorConfig, modulePath: string): Promise<GeneratorConfig>;
4
4
  export declare function mergeGeneratorIntoModuleMetadata(metadata: ModuleMetadata, modulePath: string): Promise<ModuleMetadata>;
5
5
  export declare function locateOperationSource(generatorType: string, generatorName: string, sourceRel: string): string | null;
@@ -78,11 +78,13 @@ async function mergeGeneratorIntoModuleMetadata(metadata, modulePath) {
78
78
  if (generator.operations && Array.isArray(generator.operations)) {
79
79
  for (const operation of generator.operations) {
80
80
  if (operation.type === "add-env" && operation.envVars) {
81
- metadata.envVars = metadata.envVars || [];
81
+ if (!Array.isArray(metadata.envVars))
82
+ metadata.envVars = [];
83
+ const arr = metadata.envVars;
82
84
  for (const [key, value] of Object.entries(operation.envVars)) {
83
- metadata.envVars.push({
85
+ arr.push({
84
86
  key,
85
- value: value,
87
+ value: String(value),
86
88
  description: `Environment variable for ${key}`,
87
89
  required: true,
88
90
  });
@@ -8,35 +8,68 @@ exports.getRouterBasePath = getRouterBasePath;
8
8
  exports.getLibPath = getLibPath;
9
9
  const fs_extra_1 = __importDefault(require("fs-extra"));
10
10
  const path_1 = __importDefault(require("path"));
11
+ const installed_detection_1 = require("../discovery/installed-detection");
12
+ const package_root_1 = require("../utils/package-root");
11
13
  async function detectProjectInfo(targetDir) {
12
14
  const packageJsonPath = path_1.default.join(targetDir, "package.json");
13
15
  if (!(await fs_extra_1.default.pathExists(packageJsonPath))) {
14
16
  throw new Error("No package.json found. This does not appear to be a Node.js project.");
15
17
  }
16
18
  const packageJson = await fs_extra_1.default.readJSON(packageJsonPath);
17
- // Detect framework
18
- const isNextJs = packageJson.dependencies?.next || packageJson.devDependencies?.next;
19
- const isExpress = packageJson.dependencies?.express || packageJson.devDependencies?.express;
20
- const isReact = packageJson.dependencies?.react || packageJson.devDependencies?.react;
21
- const isVite = packageJson.dependencies?.vite || packageJson.devDependencies?.vite;
22
- let framework;
23
- if (isNextJs) {
24
- framework = "nextjs";
25
- }
26
- else if (isExpress) {
27
- framework = "express";
28
- }
29
- else if (isReact && isVite) {
30
- framework = "react";
19
+ // Detect framework by matching available templates' characteristic files
20
+ // Framework is dynamic and driven by templates; keep as string for discovery
21
+ let framework = "unknown";
22
+ try {
23
+ const templatesDir = path_1.default.join((0, package_root_1.getPackageRoot)(), "templates");
24
+ if (await fs_extra_1.default.pathExists(templatesDir)) {
25
+ const dirs = await fs_extra_1.default.readdir(templatesDir);
26
+ let bestMatch = null;
27
+ for (const d of dirs) {
28
+ const tplPath = path_1.default.join(templatesDir, d, "template.json");
29
+ if (!(await fs_extra_1.default.pathExists(tplPath)))
30
+ continue;
31
+ try {
32
+ const tpl = await fs_extra_1.default.readJSON(tplPath);
33
+ const files = Array.isArray(tpl.files) ? tpl.files : [];
34
+ let score = 0;
35
+ for (const f of files) {
36
+ const candidate = path_1.default.join(targetDir, f.replace(/\\/g, "/"));
37
+ if (await fs_extra_1.default.pathExists(candidate))
38
+ score++;
39
+ }
40
+ if (!bestMatch || score > bestMatch.score)
41
+ bestMatch = { name: d, score };
42
+ }
43
+ catch {
44
+ // ignore
45
+ }
46
+ }
47
+ if (bestMatch && bestMatch.score > 0) {
48
+ // Use the template folder name as the framework identifier
49
+ framework = bestMatch.name;
50
+ }
51
+ }
31
52
  }
32
- else if (isReact) {
33
- framework = "react";
53
+ catch {
54
+ // fall back to dependency heuristics below
34
55
  }
35
- else {
36
- framework = "unknown";
56
+ // Fallback: simple dependency-based detection
57
+ if (framework === "unknown") {
58
+ const isNextJs = packageJson.dependencies?.next || packageJson.devDependencies?.next;
59
+ const isExpress = packageJson.dependencies?.express || packageJson.devDependencies?.express;
60
+ const isReact = packageJson.dependencies?.react || packageJson.devDependencies?.react;
61
+ const isVite = packageJson.dependencies?.vite || packageJson.devDependencies?.vite;
62
+ if (isNextJs)
63
+ framework = "nextjs";
64
+ else if (isExpress)
65
+ framework = "express";
66
+ else if (isReact && isVite)
67
+ framework = "react";
68
+ else if (isReact)
69
+ framework = "react";
37
70
  }
38
71
  if (framework === "unknown") {
39
- throw new Error("Only Next.js, Express, and React projects are currently supported.");
72
+ throw new Error("Unsupported project type or unable to detect framework from templates.");
40
73
  }
41
74
  // Detect router type (only for Next.js)
42
75
  let router = "unknown";
@@ -79,16 +112,13 @@ async function detectProjectInfo(targetDir) {
79
112
  else if (bunLockExists) {
80
113
  packageManager = "bun";
81
114
  }
82
- // Check for existing integrations
83
- const hasAuth = !!(packageJson.dependencies?.["next-auth"] ||
84
- packageJson.dependencies?.["better-auth"] ||
85
- packageJson.dependencies?.["@auth/core"] ||
86
- packageJson.dependencies?.["@kinde-oss/kinde-auth-nextjs"]);
87
- const hasPrisma = !!(packageJson.dependencies?.["@prisma/client"] || packageJson.devDependencies?.["prisma"]);
88
- const hasDatabase = hasPrisma ||
89
- !!(packageJson.dependencies?.["mongoose"] ||
90
- packageJson.dependencies?.["typeorm"] ||
91
- packageJson.dependencies?.["drizzle-orm"]);
115
+ // Detect installed modules by comparing project dependencies against
116
+ // declared dependencies in `modules/*/generator.json` and `module.json`.
117
+ const detectedAuth = await (0, installed_detection_1.detectAuthModules)(packageJson);
118
+ const detectedDbs = await (0, installed_detection_1.detectDatabaseModules)(packageJson);
119
+ const hasAuth = detectedAuth.length > 0;
120
+ const hasPrisma = detectedDbs.includes("prisma");
121
+ const hasDatabase = hasPrisma || detectedDbs.length > 0;
92
122
  return {
93
123
  framework,
94
124
  router,
@@ -7,32 +7,36 @@ export interface TemplateMetadata {
7
7
  features: string[];
8
8
  }
9
9
  export interface ModuleMetadata {
10
- name: string;
11
- displayName: string;
12
- description: string;
13
- category: "auth" | "database" | "ui" | "other";
14
- supportedFrameworks: string[];
15
- dependencies: {
10
+ name?: string;
11
+ displayName?: string;
12
+ description?: string;
13
+ category?: string;
14
+ provider?: string;
15
+ supportedFrameworks?: string[];
16
+ frameworkConfigs?: Record<string, unknown>;
17
+ dependencies?: Record<string, unknown> | {
16
18
  common?: Record<string, string>;
17
19
  providers?: Record<string, Record<string, string>>;
18
- } | Record<string, string>;
19
- devDependencies?: {
20
+ };
21
+ devDependencies?: Record<string, unknown> | {
20
22
  common?: Record<string, string>;
21
23
  providers?: Record<string, Record<string, string>>;
22
- } | Record<string, string>;
23
- envVars: EnvVar[];
24
- patches: ModulePatch[];
24
+ };
25
+ envVars?: EnvVar[] | Record<string, string>;
26
+ patches?: ModulePatch[];
25
27
  frameworkPatches?: Record<string, {
26
28
  [file: string]: {
27
29
  merge?: Record<string, unknown>;
28
30
  };
29
31
  }>;
30
32
  postInstall?: string[];
31
- frameworkConfigs?: Record<string, {
32
- dependencies?: Record<string, string>;
33
- devDependencies?: Record<string, string>;
34
- patches?: ModulePatch[];
35
- }>;
33
+ compatibility?: {
34
+ databases?: string[];
35
+ auth?: string[];
36
+ languages?: string[];
37
+ };
38
+ files?: string[];
39
+ scripts?: Record<string, string>;
36
40
  }
37
41
  export interface EnvVar {
38
42
  key: string;
@@ -64,7 +68,7 @@ export interface ModifyJsonPatch extends ModulePatch {
64
68
  }[];
65
69
  }
66
70
  export interface ProjectInfo {
67
- framework: "nextjs" | "express" | "react" | "unknown";
71
+ framework: string;
68
72
  router: "app" | "pages" | "unknown";
69
73
  language: "ts" | "js";
70
74
  packageManager: "npm" | "yarn" | "pnpm" | "bun";
@@ -1,4 +1,4 @@
1
- import { betterAuth, env } from "better-auth";
1
+ import { betterAuth } from "better-auth";
2
2
  import { sendEmail } from "./email/email-service";
3
3
  import { getVerificationEmailTemplate, getPasswordResetEmailTemplate } from "./email/email-templates";
4
4
  {{#switch database}}
@@ -32,7 +32,7 @@ return betterAuth({
32
32
  {{/switch}}
33
33
  baseURL: process.env.BETTER_AUTH_URL,
34
34
  secret: process.env.BETTER_AUTH_SECRET,
35
- trustedOrigins: [process.env.APP_URL],
35
+ trustedOrigins: [process.env.APP_URL!],
36
36
  user: {
37
37
  additionalFields: {
38
38
  role: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stackkit",
3
- "version": "0.2.2",
3
+ "version": "0.2.6",
4
4
  "description": "Production-ready CLI to create and extend JavaScript or TypeScript apps with modular stacks.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -25,8 +25,8 @@
25
25
  "scripts": {
26
26
  "dev": "tsc --watch",
27
27
  "build": "npm run clean && tsc && npm run copy-assets",
28
- "copy-assets": "cp -r ../../templates . && cp -r ../../modules .",
29
- "clean": "rm -rf dist templates modules",
28
+ "copy-assets": "node ./scripts/copy-assets.js",
29
+ "clean": "node ./scripts/clean.js",
30
30
  "typecheck": "tsc --noEmit",
31
31
  "lint": "eslint src --ext .ts",
32
32
  "lint:fix": "eslint src --ext .ts --fix",
@@ -52,6 +52,9 @@
52
52
  ],
53
53
  "author": "Tariqul Islam",
54
54
  "license": "MIT",
55
+ "engines": {
56
+ "node": ">=18"
57
+ },
55
58
  "dependencies": {
56
59
  "chalk": "^4.1.2",
57
60
  "commander": "^12.0.0",
@@ -64,17 +67,17 @@
64
67
  "@babel/core": "^7.28.5",
65
68
  "@babel/preset-env": "^7.28.5",
66
69
  "@babel/preset-typescript": "^7.28.5",
67
- "@babel/preset-react": "^7.28.5"
70
+ "@babel/preset-react": "^7.28.5",
71
+ "recast": "^0.20.5",
72
+ "@babel/parser": "^7.28.5",
73
+ "@babel/plugin-transform-typescript": "^7.28.5",
74
+ "@babel/plugin-transform-react-jsx": "^7.27.1"
68
75
  },
69
76
  "devDependencies": {
70
77
  "@types/fs-extra": "^11.0.4",
71
78
  "@types/inquirer": "^9.0.7",
72
79
  "@types/node": "^25.0.8",
73
80
  "@types/validate-npm-package-name": "^4.0.2",
74
- "typescript": "^5.3.3",
75
- "recast": "^0.20.5",
76
- "@babel/plugin-transform-typescript": "^7.28.5",
77
- "@babel/parser": "^7.28.5",
78
- "@babel/plugin-transform-react-jsx": "^7.27.1"
81
+ "typescript": "^5.3.3"
79
82
  }
80
- }
83
+ }
@@ -0,0 +1,23 @@
1
+ # Dependencies
2
+ node_modules/
3
+
4
+ # Build output
5
+ dist/
6
+
7
+ # Environment
8
+ .env*
9
+ !.env.example
10
+
11
+ # Logs
12
+ logs/
13
+ *.log
14
+ npm-debug.log*
15
+ yarn-debug.log*
16
+ yarn-error.log*
17
+
18
+ # OS
19
+ .DS_Store
20
+ *.pem
21
+
22
+ # TypeScript
23
+ *.tsbuildinfo
@@ -0,0 +1,42 @@
1
+ # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2
+
3
+ # dependencies
4
+ /node_modules
5
+ /.pnp
6
+ .pnp.*
7
+ .yarn/*
8
+ !.yarn/patches
9
+ !.yarn/plugins
10
+ !.yarn/releases
11
+ !.yarn/versions
12
+
13
+ # testing
14
+ /coverage
15
+
16
+ # next.js
17
+ /.next/
18
+ /out/
19
+
20
+ # production
21
+ /build
22
+
23
+ # misc
24
+ .DS_Store
25
+ *.pem
26
+
27
+ # debug
28
+ npm-debug.log*
29
+ yarn-debug.log*
30
+ yarn-error.log*
31
+ .pnpm-debug.log*
32
+
33
+ # env files
34
+ .env*
35
+ !.env.example
36
+
37
+ # vercel
38
+ .vercel
39
+
40
+ # typescript
41
+ *.tsbuildinfo
42
+ next-env.d.ts
@@ -0,0 +1,6 @@
1
+ /// <reference types="next" />
2
+ /// <reference types="next/image-types/global" />
3
+ import "./.next/types/routes.d.ts";
4
+
5
+ // NOTE: This file should not be edited
6
+ // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.