stackkit 0.2.9 → 0.3.0

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 (31) hide show
  1. package/bin/stackkit.js +8 -5
  2. package/dist/cli/add.js +4 -9
  3. package/dist/cli/create.js +4 -9
  4. package/dist/cli/doctor.js +11 -32
  5. package/dist/lib/constants.js +3 -4
  6. package/dist/lib/conversion/js-conversion.js +20 -16
  7. package/dist/lib/discovery/installed-detection.js +28 -38
  8. package/dist/lib/discovery/module-discovery.d.ts +0 -15
  9. package/dist/lib/discovery/module-discovery.js +15 -50
  10. package/dist/lib/framework/framework-utils.d.ts +4 -5
  11. package/dist/lib/framework/framework-utils.js +38 -49
  12. package/dist/lib/generation/code-generator.d.ts +11 -12
  13. package/dist/lib/generation/code-generator.js +54 -134
  14. package/dist/lib/generation/generator-utils.js +3 -15
  15. package/dist/lib/project/detect.js +11 -19
  16. package/modules/auth/better-auth/files/express/middlewares/authorize.ts +66 -8
  17. package/modules/auth/better-auth/files/express/modules/auth/auth.controller.ts +7 -0
  18. package/modules/auth/better-auth/files/express/modules/auth/auth.route.ts +5 -0
  19. package/modules/auth/better-auth/files/express/modules/auth/auth.service.ts +145 -11
  20. package/modules/auth/better-auth/files/express/modules/auth/{auth.interface.ts → auth.type.ts} +16 -6
  21. package/modules/auth/better-auth/files/shared/config/env.ts +8 -4
  22. package/modules/auth/better-auth/files/shared/lib/auth.ts +24 -25
  23. package/modules/auth/better-auth/files/shared/mongoose/auth/constants.ts +11 -0
  24. package/modules/auth/better-auth/files/shared/mongoose/auth/helper.ts +51 -0
  25. package/modules/auth/better-auth/files/shared/utils/email.ts +0 -1
  26. package/modules/auth/better-auth/generator.json +24 -20
  27. package/modules/database/mongoose/files/lib/mongoose.ts +28 -3
  28. package/modules/database/mongoose/generator.json +1 -1
  29. package/package.json +2 -2
  30. package/templates/express/env.example +1 -0
  31. package/templates/express/src/config/env.ts +4 -2
@@ -12,20 +12,24 @@ const fs_extra_1 = __importDefault(require("fs-extra"));
12
12
  const path_1 = __importDefault(require("path"));
13
13
  const package_root_1 = require("../utils/package-root");
14
14
  const shared_1 = require("./shared");
15
- /**
16
- * Discover all available modules from the modules directory
17
- */
15
+ async function readJsonSafe(filePath) {
16
+ try {
17
+ return (await fs_extra_1.default.readJson(filePath));
18
+ }
19
+ catch {
20
+ return null;
21
+ }
22
+ }
18
23
  async function discoverModules(modulesDir) {
19
24
  const discovered = {
20
25
  frameworks: [],
21
26
  databases: [],
22
27
  auth: [],
23
28
  };
24
- // If modulesDir isn't provided or doesn't exist, try common locations
25
29
  const candidates = [];
26
30
  if (modulesDir)
27
31
  candidates.push(modulesDir);
28
- candidates.push(path_1.default.join((0, package_root_1.getPackageRoot)(), "modules")); // package root
32
+ candidates.push(path_1.default.join((0, package_root_1.getPackageRoot)(), "modules"));
29
33
  let resolvedModulesDir;
30
34
  for (const c of candidates) {
31
35
  if (await fs_extra_1.default.pathExists(c)) {
@@ -36,32 +40,26 @@ async function discoverModules(modulesDir) {
36
40
  if (!resolvedModulesDir)
37
41
  return discovered;
38
42
  modulesDir = resolvedModulesDir;
39
- // Discover frameworks from templates directory
40
43
  const templatesDir = path_1.default.join(modulesDir, "..", "templates");
41
44
  if (await fs_extra_1.default.pathExists(templatesDir)) {
42
45
  const frameworkDirs = await fs_extra_1.default.readdir(templatesDir);
43
46
  for (const frameworkName of frameworkDirs) {
44
47
  const templateJsonPath = path_1.default.join(templatesDir, frameworkName, "template.json");
45
48
  if (await fs_extra_1.default.pathExists(templateJsonPath)) {
46
- try {
47
- const templateConfig = (await fs_extra_1.default.readJson(templateJsonPath));
49
+ const templateConfig = await readJsonSafe(templateJsonPath);
50
+ if (templateConfig) {
48
51
  discovered.frameworks.push({
49
52
  ...templateConfig,
50
53
  name: frameworkName,
51
54
  category: "framework",
52
55
  });
53
56
  }
54
- catch {
55
- // ignore invalid template
56
- }
57
57
  }
58
58
  }
59
59
  }
60
- // Discover database modules
61
60
  const databaseDir = path_1.default.join(modulesDir, "database");
62
61
  if (await fs_extra_1.default.pathExists(databaseDir)) {
63
62
  const dbModules = await fs_extra_1.default.readdir(databaseDir);
64
- // Sort to ensure consistent order: prisma first, then others
65
63
  dbModules.sort((a, b) => {
66
64
  if (a === "prisma")
67
65
  return -1;
@@ -73,22 +71,17 @@ async function discoverModules(modulesDir) {
73
71
  const modulePath = path_1.default.join(databaseDir, moduleName);
74
72
  const moduleJsonPath = path_1.default.join(modulePath, "module.json");
75
73
  if (await fs_extra_1.default.pathExists(moduleJsonPath)) {
76
- try {
77
- const metadata = (await fs_extra_1.default.readJson(moduleJsonPath));
78
- // Ensure name/displayName fallbacks
74
+ const metadata = await readJsonSafe(moduleJsonPath);
75
+ if (metadata) {
79
76
  if (!metadata.name)
80
77
  metadata.name = moduleName;
81
78
  if (!metadata.displayName)
82
79
  metadata.displayName = moduleName;
83
80
  discovered.databases.push(metadata);
84
81
  }
85
- catch {
86
- // ignore invalid module
87
- }
88
82
  }
89
83
  }
90
84
  }
91
- // Discover auth modules
92
85
  const authDir = path_1.default.join(modulesDir, "auth");
93
86
  if (await fs_extra_1.default.pathExists(authDir)) {
94
87
  const authModules = await fs_extra_1.default.readdir(authDir);
@@ -96,25 +89,19 @@ async function discoverModules(modulesDir) {
96
89
  const modulePath = path_1.default.join(authDir, moduleName);
97
90
  const moduleJsonPath = path_1.default.join(modulePath, "module.json");
98
91
  if (await fs_extra_1.default.pathExists(moduleJsonPath)) {
99
- try {
100
- const metadata = (await fs_extra_1.default.readJson(moduleJsonPath));
92
+ const metadata = await readJsonSafe(moduleJsonPath);
93
+ if (metadata) {
101
94
  if (!metadata.name)
102
95
  metadata.name = moduleName;
103
96
  if (!metadata.displayName)
104
97
  metadata.displayName = moduleName;
105
98
  discovered.auth.push(metadata);
106
99
  }
107
- catch {
108
- // ignore invalid module
109
- }
110
100
  }
111
101
  }
112
102
  }
113
103
  return discovered;
114
104
  }
115
- /**
116
- * Get valid database options for CLI
117
- */
118
105
  function getValidDatabaseOptions(databases) {
119
106
  const options = ["none"];
120
107
  for (const db of databases) {
@@ -129,15 +116,11 @@ function getValidDatabaseOptions(databases) {
129
116
  }
130
117
  }
131
118
  else {
132
- // For other databases, add the module name directly (generic handling)
133
119
  options.push(db.name);
134
120
  }
135
121
  }
136
122
  return options;
137
123
  }
138
- /**
139
- * Get valid auth options for CLI
140
- */
141
124
  function getValidAuthOptions(authModules) {
142
125
  const options = ["none"];
143
126
  for (const auth of authModules) {
@@ -145,28 +128,17 @@ function getValidAuthOptions(authModules) {
145
128
  }
146
129
  return options;
147
130
  }
148
- // parseDatabaseOption moved to shared helpers
149
- /**
150
- * Get compatible auth options for given framework and database
151
- */
152
131
  function getCompatibleAuthOptions(authModules, framework, database, frameworksMeta) {
153
132
  const compatible = [];
154
133
  for (const auth of authModules) {
155
- // Check if auth supports the framework
156
134
  if (auth.supportedFrameworks && !auth.supportedFrameworks.includes(framework)) {
157
135
  continue;
158
136
  }
159
- // Normalize database option (handle prisma-<provider> values)
160
137
  const parsedDb = (0, shared_1.parseDatabaseOption)(database || "").database;
161
- // If module provides explicit compatibility matrix, use it
162
138
  let dbCompatible = true;
163
139
  if (auth.compatibility && auth.compatibility.databases) {
164
140
  dbCompatible = auth.compatibility.databases.includes(parsedDb);
165
141
  }
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
142
  let explicitlyAllowedByFramework = false;
171
143
  if (frameworksMeta && Array.isArray(frameworksMeta)) {
172
144
  const fw = frameworksMeta.find((f) => f.name === framework);
@@ -184,17 +156,12 @@ function getCompatibleAuthOptions(authModules, framework, database, frameworksMe
184
156
  value: auth.name,
185
157
  });
186
158
  }
187
- // Add "None" at the end
188
159
  compatible.push({ name: "None", value: "none" });
189
160
  return compatible;
190
161
  }
191
- /**
192
- * Get database choices for inquirer prompts
193
- */
194
162
  function getDatabaseChoices(databases, framework) {
195
163
  const choices = [];
196
164
  for (const db of databases) {
197
- // Check framework compatibility
198
165
  if (db.supportedFrameworks && !db.supportedFrameworks.includes(framework)) {
199
166
  continue;
200
167
  }
@@ -212,11 +179,9 @@ function getDatabaseChoices(databases, framework) {
212
179
  }
213
180
  }
214
181
  else {
215
- // Generic handling for other database modules
216
182
  choices.push({ name: db.displayName || db.name, value: db.name });
217
183
  }
218
184
  }
219
- // Add "None" at the end
220
185
  choices.push({ name: "None", value: "none" });
221
186
  return choices;
222
187
  }
@@ -15,8 +15,7 @@ export interface ModuleConfig {
15
15
  databases?: string[];
16
16
  };
17
17
  }
18
- export declare class FrameworkUtils {
19
- private static frameworkConfigs;
20
- static loadFrameworkConfig(frameworkName: string, templatesDir: string): Promise<FrameworkConfig>;
21
- static isCompatible(framework: string, database?: string, auth?: string): boolean;
22
- }
18
+ export declare const FrameworkUtils: {
19
+ loadFrameworkConfig(frameworkName: string, templatesDir: string): Promise<FrameworkConfig>;
20
+ isCompatible(framework: string, database?: string, auth?: string): boolean;
21
+ };
@@ -36,16 +36,38 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.FrameworkUtils = void 0;
37
37
  const fs = __importStar(require("fs-extra"));
38
38
  const path = __importStar(require("path"));
39
- // eslint-disable-next-line @typescript-eslint/no-extraneous-class
40
- class FrameworkUtils {
41
- static async loadFrameworkConfig(frameworkName, templatesDir) {
39
+ const frameworkConfigs = new Map();
40
+ async function collectModuleNames(baseDir) {
41
+ if (!(await fs.pathExists(baseDir))) {
42
+ return [];
43
+ }
44
+ const names = [];
45
+ const entries = await fs.readdir(baseDir);
46
+ for (const entry of entries) {
47
+ const moduleJson = path.join(baseDir, entry, "module.json");
48
+ if (!(await fs.pathExists(moduleJson))) {
49
+ continue;
50
+ }
51
+ try {
52
+ const moduleConfig = (await fs.readJson(moduleJson));
53
+ if (moduleConfig.name) {
54
+ names.push(moduleConfig.name);
55
+ }
56
+ }
57
+ catch {
58
+ continue;
59
+ }
60
+ }
61
+ return names;
62
+ }
63
+ exports.FrameworkUtils = {
64
+ async loadFrameworkConfig(frameworkName, templatesDir) {
42
65
  const configPath = path.join(templatesDir, frameworkName, "template.json");
43
66
  if (await fs.pathExists(configPath)) {
44
67
  const config = await fs.readJson(configPath);
45
- this.frameworkConfigs.set(frameworkName, config);
68
+ frameworkConfigs.set(frameworkName, config);
46
69
  return config;
47
70
  }
48
- // Derive compatibility dynamically from available modules if possible
49
71
  const defaultConfig = {
50
72
  name: frameworkName,
51
73
  displayName: frameworkName.charAt(0).toUpperCase() + frameworkName.slice(1),
@@ -56,51 +78,20 @@ class FrameworkUtils {
56
78
  };
57
79
  try {
58
80
  const modulesDir = path.join(templatesDir, "..", "modules");
59
- const dbDir = path.join(modulesDir, "database");
60
- const authDir = path.join(modulesDir, "auth");
61
- if (await fs.pathExists(dbDir)) {
62
- const dbs = await fs.readdir(dbDir);
63
- for (const d of dbs) {
64
- const moduleJson = path.join(dbDir, d, "module.json");
65
- if (await fs.pathExists(moduleJson)) {
66
- try {
67
- const m = await fs.readJson(moduleJson);
68
- if (m && m.name)
69
- defaultConfig.compatibility.databases.push(m.name);
70
- }
71
- catch {
72
- // ignore malformed
73
- }
74
- }
75
- }
76
- }
77
- if (await fs.pathExists(authDir)) {
78
- const auths = await fs.readdir(authDir);
79
- for (const a of auths) {
80
- const moduleJson = path.join(authDir, a, "module.json");
81
- if (await fs.pathExists(moduleJson)) {
82
- try {
83
- const m = await fs.readJson(moduleJson);
84
- if (m && m.name)
85
- defaultConfig.compatibility.auth.push(m.name);
86
- }
87
- catch {
88
- // ignore malformed
89
- }
90
- }
91
- }
92
- }
81
+ defaultConfig.compatibility.databases = await collectModuleNames(path.join(modulesDir, "database"));
82
+ defaultConfig.compatibility.auth = await collectModuleNames(path.join(modulesDir, "auth"));
93
83
  }
94
84
  catch {
95
- // ignore discovery errors and leave empty lists
85
+ defaultConfig.compatibility.databases = [];
86
+ defaultConfig.compatibility.auth = [];
96
87
  }
97
- this.frameworkConfigs.set(frameworkName, defaultConfig);
88
+ frameworkConfigs.set(frameworkName, defaultConfig);
98
89
  return defaultConfig;
99
- }
100
- static isCompatible(framework, database, auth) {
101
- const config = this.frameworkConfigs.get(framework);
90
+ },
91
+ isCompatible(framework, database, auth) {
92
+ const config = frameworkConfigs.get(framework);
102
93
  if (!config)
103
- return true; // Assume compatible if no config
94
+ return true;
104
95
  if (database && !config.compatibility.databases.includes(database)) {
105
96
  return false;
106
97
  }
@@ -108,7 +99,5 @@ class FrameworkUtils {
108
99
  return false;
109
100
  }
110
101
  return true;
111
- }
112
- }
113
- exports.FrameworkUtils = FrameworkUtils;
114
- FrameworkUtils.frameworkConfigs = new Map();
102
+ },
103
+ };
@@ -14,6 +14,12 @@ export interface TemplateCondition {
14
14
  auth?: string | string[];
15
15
  features?: string[];
16
16
  }
17
+ type SelectedModules = {
18
+ framework: string;
19
+ database?: string;
20
+ auth?: string;
21
+ prismaProvider?: string;
22
+ };
17
23
  export interface Operation {
18
24
  type: "create-file" | "patch-file" | "add-dependency" | "add-script" | "add-env" | "run-command";
19
25
  description?: string;
@@ -57,18 +63,15 @@ export declare class AdvancedCodeGenerator {
57
63
  private postInstallCommands;
58
64
  private createdFiles;
59
65
  constructor(frameworkConfig: FrameworkConfig);
66
+ private initializeContext;
67
+ private isGeneratorSelected;
60
68
  loadGenerators(modulesPath: string): Promise<void>;
61
69
  private evaluateCondition;
62
70
  private processTemplate;
63
71
  private renderHeadingFromExpr;
64
72
  private processVariableDefinitions;
65
73
  private processTemplateRecursive;
66
- generate(selectedModules: {
67
- framework: string;
68
- database?: string;
69
- auth?: string;
70
- prismaProvider?: string;
71
- }, features: string[], outputPath: string): Promise<string[]>;
74
+ generate(selectedModules: SelectedModules, features: string[], outputPath: string): Promise<string[]>;
72
75
  getCreatedFiles(): string[];
73
76
  private executeOperation;
74
77
  private copyTemplate;
@@ -82,12 +85,7 @@ export declare class AdvancedCodeGenerator {
82
85
  private executeAddEnv;
83
86
  private executeRunCommand;
84
87
  private generatePackageJson;
85
- applyToProject(selectedModules: {
86
- framework: string;
87
- database?: string;
88
- auth?: string;
89
- prismaProvider?: string;
90
- }, features: string[], projectPath: string): Promise<string[]>;
88
+ applyToProject(selectedModules: SelectedModules, features: string[], projectPath: string): Promise<string[]>;
91
89
  getAvailableGenerators(): {
92
90
  frameworks: string[];
93
91
  databases: string[];
@@ -95,3 +93,4 @@ export declare class AdvancedCodeGenerator {
95
93
  };
96
94
  registerGenerator(type: "framework" | "database" | "auth", name: string, config: GeneratorConfig): void;
97
95
  }
96
+ export {};