stackkit 0.2.0 → 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/README.md +4 -7
- package/dist/cli/add.js +84 -120
- package/dist/cli/create.js +28 -15
- package/dist/cli/doctor.js +203 -21
- package/dist/cli/list.js +37 -1
- package/dist/index.js +104 -6
- package/dist/lib/discovery/module-discovery.d.ts +0 -7
- package/dist/lib/discovery/module-discovery.js +26 -23
- package/dist/lib/discovery/shared.d.ts +6 -0
- package/dist/lib/discovery/shared.js +50 -0
- package/dist/lib/framework/framework-utils.js +43 -3
- package/dist/lib/generation/code-generator.js +18 -0
- package/dist/lib/pm/package-manager.js +58 -31
- package/modules/auth/authjs/generator.json +1 -1
- package/modules/auth/better-auth/files/lib/auth.ts +5 -1
- package/package.json +1 -1
- package/templates/express/README.md +4 -9
- package/templates/express/template.json +9 -1
- package/templates/nextjs/.env.example +1 -0
- package/templates/nextjs/README.md +2 -5
- package/templates/nextjs/template.json +2 -0
- package/templates/react/README.md +2 -5
- package/templates/react/src/lib/queryClient.ts +2 -2
- package/templates/react/src/utils/utils.ts +3 -0
- package/templates/react/template.json +2 -0
- package/templates/react/src/config/constants.ts +0 -5
- package/templates/react/src/hooks/index.ts +0 -64
- package/templates/react/src/utils/helpers.ts +0 -51
package/dist/cli/doctor.js
CHANGED
|
@@ -8,6 +8,7 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
8
8
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
10
|
const logger_1 = require("../lib/ui/logger");
|
|
11
|
+
const package_root_1 = require("../lib/utils/package-root");
|
|
11
12
|
// Constants for consistent messaging
|
|
12
13
|
const MESSAGES = {
|
|
13
14
|
NO_PACKAGE_JSON: "No package.json found in current directory or any parent directory.",
|
|
@@ -211,24 +212,125 @@ function checkNodeVersion() {
|
|
|
211
212
|
function detectAuthModules(packageJson) {
|
|
212
213
|
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
213
214
|
const modules = [];
|
|
214
|
-
|
|
215
|
-
|
|
215
|
+
try {
|
|
216
|
+
const modulesDir = path_1.default.join((0, package_root_1.getPackageRoot)(), "modules", "auth");
|
|
217
|
+
if (fs_extra_1.default.existsSync(modulesDir)) {
|
|
218
|
+
const authDirs = fs_extra_1.default.readdirSync(modulesDir);
|
|
219
|
+
for (const authDir of authDirs) {
|
|
220
|
+
try {
|
|
221
|
+
const genPath = path_1.default.join(modulesDir, authDir, "generator.json");
|
|
222
|
+
const modJson = path_1.default.join(modulesDir, authDir, "module.json");
|
|
223
|
+
let pkgNames = [];
|
|
224
|
+
if (fs_extra_1.default.existsSync(genPath)) {
|
|
225
|
+
const gen = JSON.parse(fs_extra_1.default.readFileSync(genPath, "utf-8"));
|
|
226
|
+
if (Array.isArray(gen.operations)) {
|
|
227
|
+
for (const op of gen.operations) {
|
|
228
|
+
if (op.dependencies && typeof op.dependencies === "object") {
|
|
229
|
+
pkgNames.push(...Object.keys(op.dependencies));
|
|
230
|
+
}
|
|
231
|
+
if (op.devDependencies && typeof op.devDependencies === "object") {
|
|
232
|
+
pkgNames.push(...Object.keys(op.devDependencies));
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
// Fallback: check module.json provider/name
|
|
238
|
+
let moduleName = authDir;
|
|
239
|
+
if (fs_extra_1.default.existsSync(modJson)) {
|
|
240
|
+
try {
|
|
241
|
+
const m = JSON.parse(fs_extra_1.default.readFileSync(modJson, "utf-8"));
|
|
242
|
+
if (m && m.name)
|
|
243
|
+
moduleName = m.name;
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
/* ignore */
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
for (const pkg of pkgNames) {
|
|
250
|
+
if (deps[pkg]) {
|
|
251
|
+
modules.push(moduleName);
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
catch {
|
|
257
|
+
// ignore per-module errors
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
216
261
|
}
|
|
217
|
-
|
|
218
|
-
|
|
262
|
+
catch {
|
|
263
|
+
// ignore discovery errors
|
|
219
264
|
}
|
|
220
|
-
|
|
265
|
+
// Fallback to original simple checks if nothing found
|
|
266
|
+
if (modules.length === 0) {
|
|
267
|
+
if (deps["better-auth"])
|
|
268
|
+
modules.push("better-auth");
|
|
269
|
+
if (deps["next-auth"])
|
|
270
|
+
modules.push("authjs");
|
|
271
|
+
}
|
|
272
|
+
return Array.from(new Set(modules));
|
|
221
273
|
}
|
|
222
274
|
function detectDatabaseModules(packageJson) {
|
|
223
275
|
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
224
276
|
const modules = [];
|
|
225
|
-
|
|
226
|
-
|
|
277
|
+
try {
|
|
278
|
+
const modulesDir = path_1.default.join((0, package_root_1.getPackageRoot)(), "modules", "database");
|
|
279
|
+
if (fs_extra_1.default.existsSync(modulesDir)) {
|
|
280
|
+
const dbDirs = fs_extra_1.default.readdirSync(modulesDir);
|
|
281
|
+
for (const dbDir of dbDirs) {
|
|
282
|
+
try {
|
|
283
|
+
const genPath = path_1.default.join(modulesDir, dbDir, "generator.json");
|
|
284
|
+
const modJson = path_1.default.join(modulesDir, dbDir, "module.json");
|
|
285
|
+
let pkgNames = [];
|
|
286
|
+
if (fs_extra_1.default.existsSync(genPath)) {
|
|
287
|
+
const gen = JSON.parse(fs_extra_1.default.readFileSync(genPath, "utf-8"));
|
|
288
|
+
if (Array.isArray(gen.operations)) {
|
|
289
|
+
for (const op of gen.operations) {
|
|
290
|
+
if (op.dependencies && typeof op.dependencies === "object") {
|
|
291
|
+
pkgNames.push(...Object.keys(op.dependencies));
|
|
292
|
+
}
|
|
293
|
+
if (op.devDependencies && typeof op.devDependencies === "object") {
|
|
294
|
+
pkgNames.push(...Object.keys(op.devDependencies));
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
let moduleName = dbDir;
|
|
300
|
+
if (fs_extra_1.default.existsSync(modJson)) {
|
|
301
|
+
try {
|
|
302
|
+
const m = JSON.parse(fs_extra_1.default.readFileSync(modJson, "utf-8"));
|
|
303
|
+
if (m && m.name)
|
|
304
|
+
moduleName = m.name;
|
|
305
|
+
}
|
|
306
|
+
catch {
|
|
307
|
+
/* ignore */
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
for (const pkg of pkgNames) {
|
|
311
|
+
if (deps[pkg]) {
|
|
312
|
+
modules.push(moduleName);
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
catch {
|
|
318
|
+
// ignore per-module errors
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
catch {
|
|
324
|
+
// ignore discovery errors
|
|
227
325
|
}
|
|
228
|
-
if
|
|
229
|
-
|
|
326
|
+
// Fallback to original checks if nothing found
|
|
327
|
+
if (modules.length === 0) {
|
|
328
|
+
if (deps["@prisma/client"] || deps["prisma"])
|
|
329
|
+
modules.push("prisma");
|
|
330
|
+
if (deps["mongoose"])
|
|
331
|
+
modules.push("mongoose");
|
|
230
332
|
}
|
|
231
|
-
return modules;
|
|
333
|
+
return Array.from(new Set(modules));
|
|
232
334
|
}
|
|
233
335
|
async function checkKeyFiles(projectRoot, projectType, authModules, databaseModules) {
|
|
234
336
|
const checks = [];
|
|
@@ -260,8 +362,42 @@ async function checkKeyFiles(projectRoot, projectType, authModules, databaseModu
|
|
|
260
362
|
async function checkAuthRoutesExist(projectRoot, projectType) {
|
|
261
363
|
if (projectType !== "nextjs")
|
|
262
364
|
return true; // Skip for non-Next.js
|
|
263
|
-
|
|
264
|
-
|
|
365
|
+
// Build candidate auth route paths from generator.json files in modules/auth
|
|
366
|
+
const candidates = new Set();
|
|
367
|
+
try {
|
|
368
|
+
const authModulesDir = path_1.default.join((0, package_root_1.getPackageRoot)(), "modules", "auth");
|
|
369
|
+
if (await fs_extra_1.default.pathExists(authModulesDir)) {
|
|
370
|
+
const authDirs = await fs_extra_1.default.readdir(authModulesDir);
|
|
371
|
+
for (const dir of authDirs) {
|
|
372
|
+
const genPath = path_1.default.join(authModulesDir, dir, "generator.json");
|
|
373
|
+
if (!(await fs_extra_1.default.pathExists(genPath)))
|
|
374
|
+
continue;
|
|
375
|
+
try {
|
|
376
|
+
const gen = await fs_extra_1.default.readJson(genPath);
|
|
377
|
+
if (Array.isArray(gen.operations)) {
|
|
378
|
+
for (const op of gen.operations) {
|
|
379
|
+
if (typeof op.destination === "string")
|
|
380
|
+
candidates.add(op.destination);
|
|
381
|
+
if (Array.isArray(op.operations)) {
|
|
382
|
+
for (const sub of op.operations) {
|
|
383
|
+
if (typeof sub.destination === "string")
|
|
384
|
+
candidates.add(sub.destination);
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
catch {
|
|
391
|
+
// ignore malformed generator
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
catch {
|
|
397
|
+
// ignore discovery errors
|
|
398
|
+
}
|
|
399
|
+
// Fallback to known common paths if generators don't provide any
|
|
400
|
+
const fallback = [
|
|
265
401
|
"app/api/auth/[...nextauth]/route.ts",
|
|
266
402
|
"app/api/auth/[...nextauth]/route.js",
|
|
267
403
|
"src/app/api/auth/[...nextauth]/route.ts",
|
|
@@ -270,13 +406,14 @@ async function checkAuthRoutesExist(projectRoot, projectType) {
|
|
|
270
406
|
"pages/api/auth/[...nextauth].js",
|
|
271
407
|
"src/pages/api/auth/[...nextauth].ts",
|
|
272
408
|
"src/pages/api/auth/[...nextauth].js",
|
|
273
|
-
// Better Auth routes
|
|
274
409
|
"app/api/auth/[...all]/route.ts",
|
|
275
410
|
"app/api/auth/[...all]/route.js",
|
|
276
411
|
"src/app/api/auth/[...all]/route.ts",
|
|
277
412
|
"src/app/api/auth/[...all]/route.js",
|
|
278
413
|
];
|
|
279
|
-
for (const
|
|
414
|
+
for (const p of fallback)
|
|
415
|
+
candidates.add(p);
|
|
416
|
+
for (const routePath of candidates) {
|
|
280
417
|
if (await fs_extra_1.default.pathExists(path_1.default.join(projectRoot, routePath))) {
|
|
281
418
|
return true;
|
|
282
419
|
}
|
|
@@ -288,14 +425,59 @@ async function checkEnvFiles(projectRoot, authModules, databaseModules) {
|
|
|
288
425
|
const requiredKeys = [];
|
|
289
426
|
const missing = [];
|
|
290
427
|
const present = [];
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
428
|
+
// Dynamically collect required env keys from generator.json for detected modules
|
|
429
|
+
try {
|
|
430
|
+
const modulesDir = path_1.default.join((0, package_root_1.getPackageRoot)(), "modules");
|
|
431
|
+
async function collectEnvKeys(category, name) {
|
|
432
|
+
const genPath = path_1.default.join(modulesDir, category, name, "generator.json");
|
|
433
|
+
if (!(await fs_extra_1.default.pathExists(genPath)))
|
|
434
|
+
return;
|
|
435
|
+
try {
|
|
436
|
+
const gen = await fs_extra_1.default.readJson(genPath);
|
|
437
|
+
if (Array.isArray(gen.operations)) {
|
|
438
|
+
for (const op of gen.operations) {
|
|
439
|
+
if (op.type === "add-env" && op.envVars && typeof op.envVars === "object") {
|
|
440
|
+
for (const k of Object.keys(op.envVars)) {
|
|
441
|
+
if (!requiredKeys.includes(k))
|
|
442
|
+
requiredKeys.push(k);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
// Also check nested operations (e.g., patch-file -> operations)
|
|
446
|
+
if (Array.isArray(op.operations)) {
|
|
447
|
+
for (const sub of op.operations) {
|
|
448
|
+
if (sub.type === "add-env" && sub.envVars && typeof sub.envVars === "object") {
|
|
449
|
+
for (const k of Object.keys(sub.envVars)) {
|
|
450
|
+
if (!requiredKeys.includes(k))
|
|
451
|
+
requiredKeys.push(k);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
catch {
|
|
460
|
+
// ignore malformed generator
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
for (const db of databaseModules) {
|
|
464
|
+
await collectEnvKeys("database", db);
|
|
465
|
+
}
|
|
466
|
+
for (const auth of authModules) {
|
|
467
|
+
await collectEnvKeys("auth", auth);
|
|
468
|
+
}
|
|
296
469
|
}
|
|
297
|
-
|
|
298
|
-
|
|
470
|
+
catch {
|
|
471
|
+
// fallback to previous minimal checks if discovery fails
|
|
472
|
+
if (databaseModules.includes("prisma")) {
|
|
473
|
+
requiredKeys.push("DATABASE_URL");
|
|
474
|
+
}
|
|
475
|
+
if (authModules.includes("authjs")) {
|
|
476
|
+
requiredKeys.push("NEXTAUTH_SECRET", "NEXTAUTH_URL");
|
|
477
|
+
}
|
|
478
|
+
if (authModules.includes("better-auth")) {
|
|
479
|
+
requiredKeys.push("BETTER_AUTH_SECRET", "BETTER_AUTH_URL");
|
|
480
|
+
}
|
|
299
481
|
}
|
|
300
482
|
const envPaths = [".env", ".env.local"];
|
|
301
483
|
let envContent = "";
|
package/dist/cli/list.js
CHANGED
|
@@ -7,6 +7,8 @@ exports.listCommand = listCommand;
|
|
|
7
7
|
const chalk_1 = __importDefault(require("chalk"));
|
|
8
8
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const module_discovery_1 = require("../lib/discovery/module-discovery");
|
|
11
|
+
const shared_1 = require("../lib/discovery/shared");
|
|
10
12
|
const logger_1 = require("../lib/ui/logger");
|
|
11
13
|
const package_root_1 = require("../lib/utils/package-root");
|
|
12
14
|
async function listCommand(options) {
|
|
@@ -34,6 +36,14 @@ async function listCommand(options) {
|
|
|
34
36
|
if (showModules) {
|
|
35
37
|
const modulesDir = path_1.default.join((0, package_root_1.getPackageRoot)(), "modules");
|
|
36
38
|
const modules = await getAvailableModules(modulesDir);
|
|
39
|
+
// Discover modules to derive provider lists dynamically
|
|
40
|
+
let discovered;
|
|
41
|
+
try {
|
|
42
|
+
discovered = await (0, module_discovery_1.discoverModules)(path_1.default.join((0, package_root_1.getPackageRoot)(), "modules"));
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
discovered = { frameworks: [], databases: [], auth: [] };
|
|
46
|
+
}
|
|
37
47
|
if (modules.length > 0) {
|
|
38
48
|
hasModules = true;
|
|
39
49
|
logger_1.logger.log(chalk_1.default.bold.magenta("MODULES"));
|
|
@@ -68,7 +78,33 @@ async function listCommand(options) {
|
|
|
68
78
|
: isLastMod
|
|
69
79
|
? "│ └──"
|
|
70
80
|
: "│ ├──";
|
|
71
|
-
|
|
81
|
+
// Compute provider names from discovered database choices
|
|
82
|
+
const choices = (0, module_discovery_1.getDatabaseChoices)(discovered.databases || [], "nextjs");
|
|
83
|
+
const prismaProviders = choices
|
|
84
|
+
.filter((c) => c.value.startsWith("prisma-"))
|
|
85
|
+
.map((c) => {
|
|
86
|
+
const m = c.name.match(/\(([^)]+)\)/);
|
|
87
|
+
return m ? m[1] : c.name;
|
|
88
|
+
});
|
|
89
|
+
const providersText = prismaProviders.length > 0
|
|
90
|
+
? prismaProviders.join(", ")
|
|
91
|
+
: (() => {
|
|
92
|
+
const detected = (0, shared_1.getPrismaProvidersFromGenerator)((0, package_root_1.getPackageRoot)()).map((p) => {
|
|
93
|
+
if (p === "postgresql")
|
|
94
|
+
return "PostgreSQL";
|
|
95
|
+
if (p === "mongodb")
|
|
96
|
+
return "MongoDB";
|
|
97
|
+
if (p === "mysql")
|
|
98
|
+
return "MySQL";
|
|
99
|
+
if (p === "sqlite")
|
|
100
|
+
return "SQLite";
|
|
101
|
+
return p;
|
|
102
|
+
});
|
|
103
|
+
return detected.length > 0
|
|
104
|
+
? detected.join(", ")
|
|
105
|
+
: "PostgreSQL, MongoDB, MySQL, SQLite";
|
|
106
|
+
})();
|
|
107
|
+
logger_1.logger.log(` ${chalk_1.default.gray(providerPrefix)} ${chalk_1.default.dim(`Providers: ${providersText}`)}`);
|
|
72
108
|
}
|
|
73
109
|
});
|
|
74
110
|
});
|
package/dist/index.js
CHANGED
|
@@ -1,15 +1,113 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
4
|
+
if (k2 === undefined) k2 = k;
|
|
5
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
6
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
7
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
8
|
+
}
|
|
9
|
+
Object.defineProperty(o, k2, desc);
|
|
10
|
+
}) : (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
o[k2] = m[k];
|
|
13
|
+
}));
|
|
14
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
15
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
16
|
+
}) : function(o, v) {
|
|
17
|
+
o["default"] = v;
|
|
18
|
+
});
|
|
19
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
20
|
+
var ownKeys = function(o) {
|
|
21
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
22
|
+
var ar = [];
|
|
23
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
24
|
+
return ar;
|
|
25
|
+
};
|
|
26
|
+
return ownKeys(o);
|
|
27
|
+
};
|
|
28
|
+
return function (mod) {
|
|
29
|
+
if (mod && mod.__esModule) return mod;
|
|
30
|
+
var result = {};
|
|
31
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
32
|
+
__setModuleDefault(result, mod);
|
|
33
|
+
return result;
|
|
34
|
+
};
|
|
35
|
+
})();
|
|
3
36
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
37
|
const commander_1 = require("commander");
|
|
5
|
-
const
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const fs_1 = require("fs");
|
|
40
|
+
const path_1 = require("path");
|
|
6
41
|
const add_1 = require("./cli/add");
|
|
42
|
+
const create_1 = require("./cli/create");
|
|
7
43
|
const doctor_1 = require("./cli/doctor");
|
|
8
44
|
const list_1 = require("./cli/list");
|
|
45
|
+
const shared_1 = require("./lib/discovery/shared");
|
|
9
46
|
const logger_1 = require("./lib/ui/logger");
|
|
10
|
-
const
|
|
11
|
-
const path_1 = require("path");
|
|
47
|
+
const package_root_1 = require("./lib/utils/package-root");
|
|
12
48
|
const packageJson = JSON.parse((0, fs_1.readFileSync)((0, path_1.join)(__dirname, "../package.json"), "utf-8"));
|
|
49
|
+
function buildOptionHints() {
|
|
50
|
+
try {
|
|
51
|
+
const pkgRoot = (0, package_root_1.getPackageRoot)();
|
|
52
|
+
const modulesDir = (0, path_1.join)(pkgRoot, "modules");
|
|
53
|
+
const dbs = [];
|
|
54
|
+
const auths = [];
|
|
55
|
+
if (fs.existsSync((0, path_1.join)(modulesDir, "database"))) {
|
|
56
|
+
for (const d of fs.readdirSync((0, path_1.join)(modulesDir, "database"))) {
|
|
57
|
+
const moduleJson = (0, path_1.join)(modulesDir, "database", d, "module.json");
|
|
58
|
+
if (fs.existsSync(moduleJson)) {
|
|
59
|
+
try {
|
|
60
|
+
const m = JSON.parse((0, fs_1.readFileSync)(moduleJson, "utf-8"));
|
|
61
|
+
if (m && m.name === "prisma") {
|
|
62
|
+
try {
|
|
63
|
+
const providers = (0, shared_1.getPrismaProvidersFromGenerator)((0, package_root_1.getPackageRoot)());
|
|
64
|
+
if (providers.length > 0) {
|
|
65
|
+
for (const p of providers)
|
|
66
|
+
dbs.push(`prisma-${p}`);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
dbs.push("prisma");
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
dbs.push("prisma");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else if (m && m.name) {
|
|
77
|
+
dbs.push(m.name);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
/* ignore */
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
if (fs.existsSync((0, path_1.join)(modulesDir, "auth"))) {
|
|
87
|
+
for (const a of fs.readdirSync((0, path_1.join)(modulesDir, "auth"))) {
|
|
88
|
+
const moduleJson = (0, path_1.join)(modulesDir, "auth", a, "module.json");
|
|
89
|
+
if (fs.existsSync(moduleJson)) {
|
|
90
|
+
try {
|
|
91
|
+
const m = JSON.parse((0, fs_1.readFileSync)(moduleJson, "utf-8"));
|
|
92
|
+
if (m && m.name)
|
|
93
|
+
auths.push(m.name);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
/* ignore */
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return {
|
|
102
|
+
databaseHint: dbs.length > 0 ? dbs.join(", ") : "prisma, mongoose, none",
|
|
103
|
+
authHint: auths.length > 0 ? auths.join(", ") : "better-auth, authjs, none",
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return { databaseHint: "prisma, mongoose, none", authHint: "better-auth, authjs, none" };
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const hints = buildOptionHints();
|
|
13
111
|
const program = new commander_1.Command();
|
|
14
112
|
program
|
|
15
113
|
.name("stackkit")
|
|
@@ -37,9 +135,9 @@ program
|
|
|
37
135
|
.description("Create a new StackKit project")
|
|
38
136
|
.usage("[project-name] [options]")
|
|
39
137
|
.option("-f, --framework <framework>", "Framework: nextjs, express, react")
|
|
40
|
-
.option("-d, --database <database>",
|
|
41
|
-
.option("--prisma-provider <provider>", "Prisma provider
|
|
42
|
-
.option("-a, --auth <auth>",
|
|
138
|
+
.option("-d, --database <database>", `Database: ${hints.databaseHint}`)
|
|
139
|
+
.option("--prisma-provider <provider>", "Prisma provider")
|
|
140
|
+
.option("-a, --auth <auth>", `Auth: ${hints.authHint}`)
|
|
43
141
|
.option("-l, --language <language>", "Language: typescript, javascript")
|
|
44
142
|
.option("-p, --package-manager <pm>", "Package manager: pnpm, npm, yarn, bun")
|
|
45
143
|
.option("--skip-install", "Skip dependency installation")
|
|
@@ -38,13 +38,6 @@ export declare function getValidDatabaseOptions(databases: ModuleMetadata[]): st
|
|
|
38
38
|
* Get valid auth options for CLI
|
|
39
39
|
*/
|
|
40
40
|
export declare function getValidAuthOptions(authModules: ModuleMetadata[]): string[];
|
|
41
|
-
/**
|
|
42
|
-
* Parse database option into database name and provider
|
|
43
|
-
*/
|
|
44
|
-
export declare function parseDatabaseOption(dbOption: string): {
|
|
45
|
-
database: string;
|
|
46
|
-
provider?: string;
|
|
47
|
-
};
|
|
48
41
|
/**
|
|
49
42
|
* Get compatible auth options for given framework and database
|
|
50
43
|
*/
|
|
@@ -6,12 +6,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.discoverModules = discoverModules;
|
|
7
7
|
exports.getValidDatabaseOptions = getValidDatabaseOptions;
|
|
8
8
|
exports.getValidAuthOptions = getValidAuthOptions;
|
|
9
|
-
exports.parseDatabaseOption = parseDatabaseOption;
|
|
10
9
|
exports.getCompatibleAuthOptions = getCompatibleAuthOptions;
|
|
11
10
|
exports.getDatabaseChoices = getDatabaseChoices;
|
|
12
11
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
13
12
|
const path_1 = __importDefault(require("path"));
|
|
14
13
|
const package_root_1 = require("../utils/package-root");
|
|
14
|
+
const shared_1 = require("./shared");
|
|
15
15
|
/**
|
|
16
16
|
* Discover all available modules from the modules directory
|
|
17
17
|
*/
|
|
@@ -119,11 +119,17 @@ function getValidDatabaseOptions(databases) {
|
|
|
119
119
|
const options = ["none"];
|
|
120
120
|
for (const db of databases) {
|
|
121
121
|
if (db.name === "prisma") {
|
|
122
|
-
|
|
123
|
-
|
|
122
|
+
const providers = (0, shared_1.getPrismaProvidersFromGenerator)();
|
|
123
|
+
if (providers.length > 0) {
|
|
124
|
+
for (const p of providers)
|
|
125
|
+
options.push(`prisma-${p}`);
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
options.push("prisma");
|
|
129
|
+
}
|
|
124
130
|
}
|
|
125
131
|
else if (db.name === "mongoose") {
|
|
126
|
-
options.push("mongoose"
|
|
132
|
+
options.push("mongoose");
|
|
127
133
|
}
|
|
128
134
|
else {
|
|
129
135
|
// For other databases, add the name directly
|
|
@@ -142,22 +148,7 @@ function getValidAuthOptions(authModules) {
|
|
|
142
148
|
}
|
|
143
149
|
return options;
|
|
144
150
|
}
|
|
145
|
-
|
|
146
|
-
* Parse database option into database name and provider
|
|
147
|
-
*/
|
|
148
|
-
function parseDatabaseOption(dbOption) {
|
|
149
|
-
if (dbOption === "none") {
|
|
150
|
-
return { database: "none" };
|
|
151
|
-
}
|
|
152
|
-
if (dbOption.startsWith("prisma-")) {
|
|
153
|
-
const provider = dbOption.split("-")[1];
|
|
154
|
-
return { database: "prisma", provider };
|
|
155
|
-
}
|
|
156
|
-
if (dbOption === "mongoose" || dbOption === "mongoose") {
|
|
157
|
-
return { database: "mongoose" };
|
|
158
|
-
}
|
|
159
|
-
return { database: dbOption };
|
|
160
|
-
}
|
|
151
|
+
// parseDatabaseOption moved to shared helpers
|
|
161
152
|
/**
|
|
162
153
|
* Get compatible auth options for given framework and database
|
|
163
154
|
*/
|
|
@@ -168,11 +159,13 @@ function getCompatibleAuthOptions(authModules, framework, database) {
|
|
|
168
159
|
if (auth.supportedFrameworks && !auth.supportedFrameworks.includes(framework)) {
|
|
169
160
|
continue;
|
|
170
161
|
}
|
|
162
|
+
// Normalize database option (handle prisma-<provider> values)
|
|
163
|
+
const parsedDb = (0, shared_1.parseDatabaseOption)(database || "").database;
|
|
171
164
|
// Special compatibility rules
|
|
172
|
-
if (auth.name === "authjs" && (
|
|
165
|
+
if (auth.name === "authjs" && (parsedDb !== "prisma" || framework !== "nextjs")) {
|
|
173
166
|
continue;
|
|
174
167
|
}
|
|
175
|
-
if (auth.name === "better-auth" &&
|
|
168
|
+
if (auth.name === "better-auth" && parsedDb === "none" && framework !== "react") {
|
|
176
169
|
continue;
|
|
177
170
|
}
|
|
178
171
|
compatible.push({
|
|
@@ -195,7 +188,17 @@ function getDatabaseChoices(databases, framework) {
|
|
|
195
188
|
continue;
|
|
196
189
|
}
|
|
197
190
|
if (db.name === "prisma") {
|
|
198
|
-
|
|
191
|
+
const providers = (0, shared_1.getPrismaProvidersFromGenerator)();
|
|
192
|
+
if (providers.length > 0) {
|
|
193
|
+
for (const p of providers)
|
|
194
|
+
choices.push({
|
|
195
|
+
name: `Prisma (${p.charAt(0).toUpperCase() + p.slice(1)})`,
|
|
196
|
+
value: `prisma-${p}`,
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
choices.push({ name: "Prisma", value: "prisma" });
|
|
201
|
+
}
|
|
199
202
|
}
|
|
200
203
|
else if (db.name === "mongoose") {
|
|
201
204
|
choices.push({ name: "Mongoose", value: "mongoose" });
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.parseDatabaseOption = parseDatabaseOption;
|
|
7
|
+
exports.getPrismaProvidersFromGenerator = getPrismaProvidersFromGenerator;
|
|
8
|
+
exports.isPrismaOption = isPrismaOption;
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const package_root_1 = require("../utils/package-root");
|
|
11
|
+
function parseDatabaseOption(dbOption) {
|
|
12
|
+
if (!dbOption)
|
|
13
|
+
return { database: "none" };
|
|
14
|
+
if (dbOption === "none")
|
|
15
|
+
return { database: "none" };
|
|
16
|
+
if (dbOption.startsWith("prisma-")) {
|
|
17
|
+
const provider = dbOption.split("-")[1];
|
|
18
|
+
return { database: "prisma", provider };
|
|
19
|
+
}
|
|
20
|
+
if (dbOption === "prisma")
|
|
21
|
+
return { database: "prisma" };
|
|
22
|
+
if (dbOption === "mongoose")
|
|
23
|
+
return { database: "mongoose" };
|
|
24
|
+
return { database: dbOption };
|
|
25
|
+
}
|
|
26
|
+
function getPrismaProvidersFromGenerator(modulesDir) {
|
|
27
|
+
const pkgRoot = modulesDir || (0, package_root_1.getPackageRoot)();
|
|
28
|
+
const genPath = path_1.default.join(pkgRoot, "modules", "database", "prisma", "generator.json");
|
|
29
|
+
try {
|
|
30
|
+
const gen = require(genPath);
|
|
31
|
+
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));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return Array.from(providers);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function isPrismaOption(value) {
|
|
45
|
+
if (!value)
|
|
46
|
+
return false;
|
|
47
|
+
if (value === "prisma")
|
|
48
|
+
return true;
|
|
49
|
+
return value.startsWith("prisma-");
|
|
50
|
+
}
|