stackkit 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/add.js +47 -18
- package/dist/lib/generation/code-generator.js +18 -0
- package/package.json +1 -1
package/dist/cli/add.js
CHANGED
|
@@ -78,6 +78,20 @@ async function getAddConfig(module, options, projectInfo) {
|
|
|
78
78
|
if (!moduleMetadata) {
|
|
79
79
|
throw new Error(`Auth provider "${provider}" not found`);
|
|
80
80
|
}
|
|
81
|
+
// Validate compatibility with existing project
|
|
82
|
+
if (projectInfo) {
|
|
83
|
+
// Auth.js requires Next.js + Prisma
|
|
84
|
+
if (provider === "authjs" &&
|
|
85
|
+
(projectInfo.framework !== "nextjs" || !projectInfo.hasPrisma)) {
|
|
86
|
+
throw new Error("Auth.js is only supported with Next.js and Prisma database in this project");
|
|
87
|
+
}
|
|
88
|
+
// Better-auth requires a database for server frameworks (non-react)
|
|
89
|
+
if (provider === "better-auth" &&
|
|
90
|
+
!projectInfo.hasDatabase &&
|
|
91
|
+
projectInfo.framework !== "react") {
|
|
92
|
+
throw new Error("Better Auth requires a database for server frameworks in this project");
|
|
93
|
+
}
|
|
94
|
+
}
|
|
81
95
|
return {
|
|
82
96
|
module: "auth",
|
|
83
97
|
provider,
|
|
@@ -90,19 +104,25 @@ async function getAddConfig(module, options, projectInfo) {
|
|
|
90
104
|
throw new Error(`Unknown module type "${module}". Use "database" or "auth", or specify a provider directly.`);
|
|
91
105
|
}
|
|
92
106
|
async function getInteractiveConfig(modulesDir, projectInfo) {
|
|
107
|
+
// Discover modules once and use compatibility info to decide which categories to show
|
|
108
|
+
const discovered = await (0, module_discovery_1.discoverModules)(modulesDir);
|
|
109
|
+
const compatibleAuths = (0, module_discovery_1.getCompatibleAuthOptions)(discovered.auth || [], projectInfo?.framework || "nextjs", projectInfo?.hasPrisma ? "prisma" : "none");
|
|
110
|
+
const categories = [
|
|
111
|
+
{ name: "Database", value: "database" },
|
|
112
|
+
];
|
|
113
|
+
// Only show Auth category if there is at least one compatible auth option
|
|
114
|
+
if (compatibleAuths.length > 1) {
|
|
115
|
+
categories.push({ name: "Auth", value: "auth" });
|
|
116
|
+
}
|
|
93
117
|
const answers = await inquirer_1.default.prompt([
|
|
94
118
|
{
|
|
95
119
|
type: "list",
|
|
96
120
|
name: "category",
|
|
97
121
|
message: "What would you like to add?",
|
|
98
|
-
choices:
|
|
99
|
-
{ name: "Database", value: "database" },
|
|
100
|
-
{ name: "Auth", value: "auth" },
|
|
101
|
-
],
|
|
122
|
+
choices: categories,
|
|
102
123
|
},
|
|
103
124
|
]);
|
|
104
125
|
const category = answers.category;
|
|
105
|
-
const discovered = await (0, module_discovery_1.discoverModules)(modulesDir);
|
|
106
126
|
if (category === "database") {
|
|
107
127
|
const dbChoices = (0, module_discovery_1.getDatabaseChoices)(discovered.databases || [], projectInfo?.framework || "nextjs");
|
|
108
128
|
const dbAnswers = await inquirer_1.default.prompt([
|
|
@@ -135,7 +155,9 @@ async function getInteractiveConfig(modulesDir, projectInfo) {
|
|
|
135
155
|
};
|
|
136
156
|
}
|
|
137
157
|
else if (category === "auth") {
|
|
138
|
-
|
|
158
|
+
// Filter auth choices based on project compatibility (framework + database)
|
|
159
|
+
const dbString = projectInfo?.hasPrisma ? "prisma" : "none";
|
|
160
|
+
const authChoices = (0, module_discovery_1.getCompatibleAuthOptions)(discovered.auth || [], projectInfo?.framework || "nextjs", dbString);
|
|
139
161
|
const authAnswers = await inquirer_1.default.prompt([
|
|
140
162
|
{
|
|
141
163
|
type: "list",
|
|
@@ -145,11 +167,17 @@ async function getInteractiveConfig(modulesDir, projectInfo) {
|
|
|
145
167
|
},
|
|
146
168
|
]);
|
|
147
169
|
const selectedAuth = authAnswers.auth;
|
|
170
|
+
if (selectedAuth === "none") {
|
|
171
|
+
logger_1.logger.info("Cancelled");
|
|
172
|
+
process.exit(0);
|
|
173
|
+
}
|
|
148
174
|
const metadata = await loadModuleMetadata(modulesDir, selectedAuth, selectedAuth);
|
|
149
175
|
if (!metadata) {
|
|
150
176
|
throw new Error(`Auth provider "${selectedAuth}" not found`);
|
|
151
177
|
}
|
|
152
|
-
if (projectInfo &&
|
|
178
|
+
if (projectInfo &&
|
|
179
|
+
metadata.supportedFrameworks &&
|
|
180
|
+
!metadata.supportedFrameworks.includes(projectInfo.framework)) {
|
|
153
181
|
throw new Error(`Auth provider "${selectedAuth}" does not support ${projectInfo.framework}`);
|
|
154
182
|
}
|
|
155
183
|
return {
|
|
@@ -244,6 +272,18 @@ async function addModuleToProject(projectRoot, projectInfo, config, options) {
|
|
|
244
272
|
selectedModules.auth = config.provider;
|
|
245
273
|
}
|
|
246
274
|
const postInstall = await gen.applyToProject(selectedModules, [], projectRoot);
|
|
275
|
+
// Install dependencies first, then run post-install commands (e.g. prisma generate)
|
|
276
|
+
if (!options?.dryRun && options?.install !== false) {
|
|
277
|
+
const installSpinner = logger_1.logger.startSpinner("Installing dependencies...");
|
|
278
|
+
try {
|
|
279
|
+
await (0, package_manager_1.installDependencies)(projectRoot, projectInfo.packageManager);
|
|
280
|
+
installSpinner.succeed("Dependencies installed");
|
|
281
|
+
}
|
|
282
|
+
catch (err) {
|
|
283
|
+
installSpinner.fail("Failed to install dependencies");
|
|
284
|
+
throw err;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
247
287
|
if (postInstall && postInstall.length > 0 && !options?.dryRun) {
|
|
248
288
|
const postInstallSpinner = logger_1.logger.startSpinner("Running post-install commands...");
|
|
249
289
|
try {
|
|
@@ -257,17 +297,6 @@ async function addModuleToProject(projectRoot, projectInfo, config, options) {
|
|
|
257
297
|
throw error;
|
|
258
298
|
}
|
|
259
299
|
}
|
|
260
|
-
if (!options?.dryRun && options?.install !== false) {
|
|
261
|
-
const installSpinner = logger_1.logger.startSpinner("Installing dependencies...");
|
|
262
|
-
try {
|
|
263
|
-
await (0, package_manager_1.installDependencies)(projectRoot, projectInfo.packageManager);
|
|
264
|
-
installSpinner.succeed("Dependencies installed");
|
|
265
|
-
}
|
|
266
|
-
catch (err) {
|
|
267
|
-
installSpinner.fail("Failed to install dependencies");
|
|
268
|
-
throw err;
|
|
269
|
-
}
|
|
270
|
-
}
|
|
271
300
|
return;
|
|
272
301
|
}
|
|
273
302
|
const mergedDeps = {};
|
|
@@ -390,6 +390,24 @@ class AdvancedCodeGenerator {
|
|
|
390
390
|
catch {
|
|
391
391
|
// ignore failures here — not critical
|
|
392
392
|
}
|
|
393
|
+
// Ensure gitignore is present in target even if template authors
|
|
394
|
+
// renamed it to avoid npm/package issues (e.g. 'gitignore' or '_gitignore')
|
|
395
|
+
try {
|
|
396
|
+
const gitCandidates = [".gitignore", "gitignore", "_gitignore"];
|
|
397
|
+
for (const g of gitCandidates) {
|
|
398
|
+
const src = path.join(templatePath, g);
|
|
399
|
+
if (await fs.pathExists(src)) {
|
|
400
|
+
const dest = path.join(outputPath, ".gitignore");
|
|
401
|
+
if (!(await fs.pathExists(dest))) {
|
|
402
|
+
await fs.copy(src, dest);
|
|
403
|
+
}
|
|
404
|
+
break;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
catch {
|
|
409
|
+
// ignore
|
|
410
|
+
}
|
|
393
411
|
}
|
|
394
412
|
}
|
|
395
413
|
processOperationTemplates(operation, context) {
|