stackkit-cli 0.4.3 → 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 (102) hide show
  1. package/README.md +26 -2
  2. package/bin/stackkit.js +10 -1
  3. package/dist/commands/add.js +128 -10
  4. package/dist/commands/doctor.d.ts +11 -0
  5. package/dist/commands/doctor.js +483 -0
  6. package/dist/commands/list.d.ts +1 -1
  7. package/dist/commands/list.js +59 -38
  8. package/dist/index.js +11 -13
  9. package/dist/types/index.d.ts +29 -2
  10. package/dist/utils/config-utils.d.ts +2 -0
  11. package/dist/utils/config-utils.js +88 -0
  12. package/dist/utils/detect.js +12 -2
  13. package/dist/utils/env-editor.d.ts +0 -1
  14. package/dist/utils/env-editor.js +50 -25
  15. package/dist/utils/files.d.ts +8 -0
  16. package/dist/utils/files.js +51 -0
  17. package/dist/utils/js-conversion.d.ts +1 -0
  18. package/dist/utils/js-conversion.js +244 -0
  19. package/dist/utils/module-utils.d.ts +2 -0
  20. package/dist/utils/module-utils.js +461 -0
  21. package/dist/utils/package-manager.js +15 -31
  22. package/modules/auth/authjs/files/api/auth/[...nextauth]/route.ts +6 -0
  23. package/modules/auth/authjs/files/lib/auth-client.ts +11 -0
  24. package/modules/auth/authjs/files/lib/auth.ts +41 -0
  25. package/modules/auth/authjs/files/schemas/prisma-schema.prisma +45 -0
  26. package/modules/auth/authjs/module.json +95 -0
  27. package/modules/auth/better-auth/files/lib/auth-client.ts +7 -0
  28. package/modules/auth/better-auth/files/lib/auth.ts +75 -0
  29. package/modules/auth/better-auth/files/lib/email-service.ts +34 -0
  30. package/modules/auth/better-auth/files/lib/email-templates.ts +89 -0
  31. package/modules/auth/better-auth/files/schemas/prisma-schema.prisma +63 -0
  32. package/modules/auth/better-auth/module.json +191 -0
  33. package/modules/database/mongoose/files/lib/db.ts +68 -0
  34. package/modules/database/mongoose/files/models/User.ts +34 -0
  35. package/modules/database/mongoose/module.json +55 -0
  36. package/modules/database/prisma/files/lib/prisma.ts +4 -0
  37. package/modules/database/prisma/files/prisma/schema.prisma +8 -0
  38. package/modules/database/prisma/files/prisma.config.ts +12 -0
  39. package/modules/database/prisma/module.json +122 -0
  40. package/package.json +1 -1
  41. package/templates/express/.env.example +1 -10
  42. package/templates/express/package.json +15 -21
  43. package/templates/express/src/app.ts +9 -29
  44. package/templates/express/src/config/env.ts +3 -14
  45. package/templates/express/src/features/health/health.controller.ts +18 -0
  46. package/templates/express/src/features/health/health.route.ts +9 -0
  47. package/templates/express/src/features/health/health.service.ts +6 -0
  48. package/templates/express/src/middlewares/error.middleware.ts +2 -2
  49. package/templates/express/src/server.ts +1 -1
  50. package/templates/express/template.json +1 -5
  51. package/templates/express/tsconfig.json +0 -1
  52. package/templates/nextjs/lib/env.ts +8 -0
  53. package/templates/nextjs/package.json +7 -7
  54. package/templates/react-vite/.env.example +1 -2
  55. package/templates/react-vite/.prettierignore +4 -0
  56. package/templates/react-vite/.prettierrc +9 -0
  57. package/templates/react-vite/README.md +22 -0
  58. package/templates/react-vite/package.json +16 -16
  59. package/templates/react-vite/src/router.tsx +0 -12
  60. package/templates/react-vite/vite.config.ts +0 -6
  61. package/dist/commands/init.d.ts +0 -10
  62. package/dist/commands/init.js +0 -157
  63. package/dist/utils/code-inject.d.ts +0 -14
  64. package/dist/utils/code-inject.js +0 -70
  65. package/dist/utils/json-editor.d.ts +0 -8
  66. package/dist/utils/json-editor.js +0 -45
  67. package/modules/auth/better-auth-express/adapters/mongoose-mongodb.ts +0 -13
  68. package/modules/auth/better-auth-express/adapters/prisma-mongodb.ts +0 -15
  69. package/modules/auth/better-auth-express/adapters/prisma-postgresql.ts +0 -15
  70. package/modules/auth/better-auth-express/files/lib/auth.ts +0 -16
  71. package/modules/auth/better-auth-express/files/routes/auth.ts +0 -12
  72. package/modules/auth/better-auth-express/files/schemas/prisma-mongodb-schema.prisma +0 -72
  73. package/modules/auth/better-auth-express/files/schemas/prisma-postgresql-schema.prisma +0 -72
  74. package/modules/auth/better-auth-express/module.json +0 -61
  75. package/modules/auth/better-auth-nextjs/adapters/mongoose-mongodb.ts +0 -24
  76. package/modules/auth/better-auth-nextjs/adapters/prisma-mongodb.ts +0 -26
  77. package/modules/auth/better-auth-nextjs/adapters/prisma-postgresql.ts +0 -26
  78. package/modules/auth/better-auth-nextjs/files/lib/auth.ts +0 -26
  79. package/modules/auth/better-auth-nextjs/files/schemas/prisma-mongodb-schema.prisma +0 -72
  80. package/modules/auth/better-auth-nextjs/files/schemas/prisma-postgresql-schema.prisma +0 -72
  81. package/modules/auth/better-auth-nextjs/module.json +0 -62
  82. package/modules/auth/better-auth-react/files/lib/auth-client.ts +0 -9
  83. package/modules/auth/better-auth-react/module.json +0 -28
  84. package/modules/auth/clerk-express/files/lib/auth.ts +0 -7
  85. package/modules/auth/clerk-express/module.json +0 -34
  86. package/modules/auth/clerk-nextjs/files/lib/auth-provider.tsx +0 -5
  87. package/modules/auth/clerk-nextjs/files/middleware.ts +0 -9
  88. package/modules/auth/clerk-nextjs/module.json +0 -64
  89. package/modules/auth/clerk-react/files/lib/auth-provider.tsx +0 -15
  90. package/modules/auth/clerk-react/module.json +0 -28
  91. package/modules/database/mongoose-mongodb/files/lib/db.ts +0 -40
  92. package/modules/database/mongoose-mongodb/module.json +0 -55
  93. package/modules/database/prisma-mongodb/files/lib/db.ts +0 -9
  94. package/modules/database/prisma-mongodb/files/prisma/schema.prisma +0 -17
  95. package/modules/database/prisma-mongodb/module.json +0 -60
  96. package/modules/database/prisma-postgresql/files/lib/db.ts +0 -9
  97. package/modules/database/prisma-postgresql/files/prisma/schema.prisma +0 -17
  98. package/modules/database/prisma-postgresql/module.json +0 -60
  99. package/templates/react-vite/src/api/services/user.service.ts +0 -18
  100. package/templates/react-vite/src/pages/UserProfile.tsx +0 -40
  101. package/templates/react-vite/src/types/user.d.ts +0 -6
  102. /package/modules/auth/{better-auth-nextjs → better-auth}/files/api/auth/[...all]/route.ts +0 -0
package/README.md CHANGED
@@ -5,6 +5,9 @@ Add authentication and database modules to existing projects.
5
5
  ## Usage
6
6
 
7
7
  ```bash
8
+ # Check project health and compatibility
9
+ npx stackkit-cli doctor
10
+
8
11
  # Add authentication
9
12
  npx stackkit-cli add auth
10
13
 
@@ -21,19 +24,40 @@ npx stackkit-cli list
21
24
  - **Shows compatible modules** for your project
22
25
  - **Installs dependencies** automatically
23
26
  - **Configures everything** - files, env vars, and setup
27
+ - **Health checks** with `doctor` command
24
28
 
25
29
  ## Available Modules
26
30
 
27
31
  ### Authentication
28
32
 
29
33
  - Better Auth (Next.js, Express, React)
30
- - Clerk (Next.js, Express, React)
31
34
 
32
35
  ### Database
33
36
 
34
37
  - Prisma with PostgreSQL or MongoDB (Next.js, Express)
35
38
  - Mongoose with MongoDB (Next.js, Express)
36
39
 
40
+ ## Commands
41
+
42
+ ### `doctor`
43
+
44
+ Check your project's health and compatibility with StackKit modules.
45
+
46
+ ```bash
47
+ stackkit doctor # Basic health check
48
+ stackkit doctor --verbose # Detailed output
49
+ stackkit doctor --json # Machine-readable JSON output
50
+ stackkit doctor --strict # Treat warnings as errors
51
+ ```
52
+
53
+ The doctor command:
54
+ - Detects your project type and framework
55
+ - Checks Node.js version compatibility
56
+ - Identifies installed StackKit modules
57
+ - Validates environment variables
58
+ - Checks for configuration conflicts
59
+ - Provides actionable next steps
60
+
37
61
  ## Documentation
38
62
 
39
- Full documentation: [stackkit.dev](https://stackkit.dev) | [GitHub](https://github.com/tariqul420/stackkit)
63
+ Full documentation: [stackkit.dev](https://stackkit.dev) | [GitHub](https://github.com/tariqul420/stackkit/issues)
package/bin/stackkit.js CHANGED
@@ -1,2 +1,11 @@
1
1
  #!/usr/bin/env node
2
- require("../dist/index.js");
2
+
3
+ try {
4
+ // eslint-disable-next-line
5
+ require("ts-node/register");
6
+ // eslint-disable-next-line
7
+ require("../src/index.ts");
8
+ } catch {
9
+ // eslint-disable-next-line
10
+ require("../dist/index.js");
11
+ }
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.addCommand = addCommand;
7
7
  const chalk_1 = __importDefault(require("chalk"));
8
+ const child_process_1 = require("child_process");
8
9
  const fs_extra_1 = __importDefault(require("fs-extra"));
9
10
  const inquirer_1 = __importDefault(require("inquirer"));
10
11
  const path_1 = __importDefault(require("path"));
@@ -27,6 +28,62 @@ async function addCommand(module, options) {
27
28
  logger_1.logger.error(`Module "${module}" not found`);
28
29
  process.exit(1);
29
30
  }
31
+ // For database modules, ensure provider is selected
32
+ let selectedProvider = options.provider;
33
+ if (moduleMetadata.category === "database" && !selectedProvider) {
34
+ if (typeof moduleMetadata.dependencies === "object" &&
35
+ "providers" in moduleMetadata.dependencies) {
36
+ const providers = Object.keys(moduleMetadata.dependencies.providers || {});
37
+ if (providers.length > 0) {
38
+ const { provider } = await inquirer_1.default.prompt([
39
+ {
40
+ type: "list",
41
+ name: "provider",
42
+ message: "Select database provider:",
43
+ choices: providers.map((p) => ({ name: p, value: p })),
44
+ },
45
+ ]);
46
+ selectedProvider = provider;
47
+ }
48
+ }
49
+ }
50
+ // Merge dependencies based on provider
51
+ const mergedDeps = {};
52
+ const mergedDevDeps = {};
53
+ // Add shared dependencies
54
+ if (moduleMetadata.frameworkConfigs?.shared?.dependencies) {
55
+ Object.assign(mergedDeps, moduleMetadata.frameworkConfigs.shared.dependencies);
56
+ }
57
+ if (moduleMetadata.frameworkConfigs?.shared?.devDependencies) {
58
+ Object.assign(mergedDevDeps, moduleMetadata.frameworkConfigs.shared.devDependencies);
59
+ }
60
+ // Add provider specific dependencies
61
+ if (selectedProvider && moduleMetadata.databaseAdapters?.providers?.[selectedProvider]?.dependencies) {
62
+ Object.assign(mergedDeps, moduleMetadata.databaseAdapters.providers[selectedProvider].dependencies);
63
+ }
64
+ if (selectedProvider && moduleMetadata.databaseAdapters?.providers?.[selectedProvider]?.devDependencies) {
65
+ Object.assign(mergedDevDeps, moduleMetadata.databaseAdapters.providers[selectedProvider].devDependencies);
66
+ }
67
+ // Update metadata with merged deps
68
+ moduleMetadata.dependencies = mergedDeps;
69
+ moduleMetadata.devDependencies = mergedDevDeps;
70
+ // Set variables for replacements
71
+ const variables = {};
72
+ if (selectedProvider) {
73
+ variables.provider = selectedProvider;
74
+ if (selectedProvider === "postgresql") {
75
+ variables.connectionString = "postgresql://user:password@localhost:5432/mydb?schema=public";
76
+ }
77
+ else if (selectedProvider === "mongodb") {
78
+ variables.connectionString = "mongodb://localhost:27017/mydb";
79
+ }
80
+ else if (selectedProvider === "mysql") {
81
+ variables.connectionString = "mysql://user:password@localhost:3306/mydb";
82
+ }
83
+ else if (selectedProvider === "sqlite") {
84
+ variables.connectionString = "file:./dev.db";
85
+ }
86
+ }
30
87
  // Check if framework is supported
31
88
  if (!moduleMetadata.supportedFrameworks.includes(projectInfo.framework)) {
32
89
  logger_1.logger.error(`Module "${module}" does not support ${projectInfo.framework}. Supported: ${moduleMetadata.supportedFrameworks.join(", ")}`);
@@ -54,9 +111,27 @@ async function addCommand(module, options) {
54
111
  }
55
112
  // Apply module patches
56
113
  await applyModulePatches(projectRoot, projectInfo, moduleMetadata, modulesDir, module, options);
114
+ // Apply framework patches
115
+ if (moduleMetadata.frameworkPatches && !options.dryRun) {
116
+ await applyFrameworkPatches(projectRoot, moduleMetadata.frameworkPatches, projectInfo.framework);
117
+ }
118
+ // Run post-install commands
119
+ if (moduleMetadata.postInstall && moduleMetadata.postInstall.length > 0 && !options.dryRun) {
120
+ const postInstallSpinner = logger_1.logger.startSpinner("Running post-install commands...");
121
+ try {
122
+ for (const command of moduleMetadata.postInstall) {
123
+ (0, child_process_1.execSync)(command, { cwd: projectRoot, stdio: "pipe" });
124
+ }
125
+ postInstallSpinner.succeed("Post-install commands completed");
126
+ }
127
+ catch (error) {
128
+ postInstallSpinner.fail("Failed to run post-install commands");
129
+ throw error;
130
+ }
131
+ }
57
132
  // Add dependencies
58
- if (Object.keys(moduleMetadata.dependencies).length > 0 && options.install !== false) {
59
- const deps = Object.entries(moduleMetadata.dependencies).map(([name, version]) => `${name}@${version}`);
133
+ if (Object.keys(mergedDeps).length > 0 && options.install !== false) {
134
+ const deps = Object.entries(mergedDeps).map(([name, version]) => `${name}@${version}`);
60
135
  if (!options.dryRun) {
61
136
  await (0, package_manager_1.addDependencies)(projectRoot, projectInfo.packageManager, deps, false);
62
137
  }
@@ -65,10 +140,8 @@ async function addCommand(module, options) {
65
140
  }
66
141
  }
67
142
  // Add dev dependencies
68
- if (moduleMetadata.devDependencies &&
69
- Object.keys(moduleMetadata.devDependencies).length > 0 &&
70
- options.install !== false) {
71
- const devDeps = Object.entries(moduleMetadata.devDependencies).map(([name, version]) => `${name}@${version}`);
143
+ if (Object.keys(mergedDevDeps).length > 0 && options.install !== false) {
144
+ const devDeps = Object.entries(mergedDevDeps).map(([name, version]) => `${name}@${version}`);
72
145
  if (!options.dryRun) {
73
146
  await (0, package_manager_1.addDependencies)(projectRoot, projectInfo.packageManager, devDeps, true);
74
147
  }
@@ -77,9 +150,14 @@ async function addCommand(module, options) {
77
150
  }
78
151
  }
79
152
  // Add environment variables
80
- if (moduleMetadata.envVars.length > 0) {
153
+ if (moduleMetadata.envVars && moduleMetadata.envVars.length > 0) {
154
+ // Replace variables in envVars
155
+ const processedEnvVars = moduleMetadata.envVars.map((envVar) => ({
156
+ ...envVar,
157
+ value: envVar.value?.replace(/\{\{(\w+)\}\}/g, (match, key) => variables[key] || match),
158
+ }));
81
159
  if (!options.dryRun) {
82
- await (0, env_editor_1.addEnvVariables)(projectRoot, moduleMetadata.envVars, { force: options.force });
160
+ await (0, env_editor_1.addEnvVariables)(projectRoot, processedEnvVars, { force: options.force });
83
161
  }
84
162
  else {
85
163
  logger_1.logger.log(` ${chalk_1.default.dim("~")} .env.example`);
@@ -89,7 +167,7 @@ async function addCommand(module, options) {
89
167
  logger_1.logger.success(`Added ${chalk_1.default.bold(moduleMetadata.displayName)}`);
90
168
  logger_1.logger.newLine();
91
169
  // Print next steps
92
- if (moduleMetadata.envVars.some((v) => v.required)) {
170
+ if (moduleMetadata.envVars && moduleMetadata.envVars.some((v) => v.required)) {
93
171
  logger_1.logger.log("Next: Fill in environment variables in .env");
94
172
  }
95
173
  logger_1.logger.newLine();
@@ -136,8 +214,10 @@ async function loadModuleMetadata(modulesDir, moduleName, provider) {
136
214
  }
137
215
  return null;
138
216
  }
139
- // (removed duplicate import)
140
217
  async function applyModulePatches(projectRoot, projectInfo, moduleMetadata, modulesDir, moduleName, options) {
218
+ if (!moduleMetadata.patches || !Array.isArray(moduleMetadata.patches)) {
219
+ return;
220
+ }
141
221
  // Find the module path
142
222
  const moduleBasePath = await findModulePath(modulesDir, moduleName, options.provider);
143
223
  if (!moduleBasePath) {
@@ -208,3 +288,41 @@ async function findModulePath(modulesDir, moduleName, provider) {
208
288
  }
209
289
  return null;
210
290
  }
291
+ async function applyFrameworkPatches(projectRoot, patches, framework) {
292
+ const frameworkKey = framework;
293
+ const frameworkPatches = patches[frameworkKey];
294
+ if (!frameworkPatches)
295
+ return;
296
+ for (const [filename, patchConfig] of Object.entries(frameworkPatches)) {
297
+ const filePath = path_1.default.join(projectRoot, filename);
298
+ if (await fs_extra_1.default.pathExists(filePath)) {
299
+ const fileContent = await fs_extra_1.default.readJson(filePath);
300
+ if (patchConfig.merge) {
301
+ const merged = deepMerge(fileContent, patchConfig.merge);
302
+ await fs_extra_1.default.writeJson(filePath, merged, { spaces: 2 });
303
+ const relativePath = path_1.default.relative(projectRoot, filePath);
304
+ logger_1.logger.log(` ${chalk_1.default.blue("~")} ${relativePath}`);
305
+ }
306
+ }
307
+ }
308
+ }
309
+ function deepMerge(target, source) {
310
+ const output = { ...target };
311
+ for (const key in source) {
312
+ if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) {
313
+ if (target[key]) {
314
+ output[key] = deepMerge(target[key], source[key]);
315
+ }
316
+ else {
317
+ output[key] = source[key];
318
+ }
319
+ }
320
+ else if (Array.isArray(source[key])) {
321
+ output[key] = Array.from(new Set([...(target[key] || []), ...source[key]]));
322
+ }
323
+ else {
324
+ output[key] = source[key];
325
+ }
326
+ }
327
+ return output;
328
+ }
@@ -0,0 +1,11 @@
1
+ interface DoctorOptions {
2
+ json?: boolean;
3
+ verbose?: boolean;
4
+ strict?: boolean;
5
+ }
6
+ /**
7
+ * Main doctor command function that performs health checks on a StackKit project
8
+ * @param options Command line options
9
+ */
10
+ export declare function doctorCommand(options: DoctorOptions): Promise<void>;
11
+ export {};