stackkit 0.2.6 → 0.2.8
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 +87 -12
- package/dist/cli/create.js +1 -2
- package/dist/cli/list.js +73 -83
- package/dist/index.js +25 -44
- package/dist/lib/constants.d.ts +110 -0
- package/dist/lib/constants.js +112 -0
- package/dist/lib/env/env-editor.js +41 -47
- package/dist/lib/fs/files.d.ts +0 -1
- package/dist/lib/fs/files.js +12 -40
- package/dist/lib/generation/code-generator.d.ts +4 -1
- package/dist/lib/generation/code-generator.js +36 -10
- package/dist/lib/pm/package-manager.d.ts +1 -1
- package/dist/lib/pm/package-manager.js +130 -14
- package/dist/lib/ui/logger.d.ts +8 -1
- package/dist/lib/ui/logger.js +60 -3
- package/dist/lib/utils/fs-helpers.d.ts +12 -0
- package/dist/lib/utils/fs-helpers.js +61 -0
- package/dist/lib/utils/json-loader.d.ts +6 -0
- package/dist/lib/utils/json-loader.js +34 -0
- package/dist/lib/utils/module-loader.d.ts +9 -0
- package/dist/lib/utils/module-loader.js +98 -0
- package/dist/lib/utils/package-root.d.ts +1 -0
- package/dist/lib/utils/package-root.js +75 -2
- package/dist/lib/utils/path-resolver.d.ts +9 -0
- package/dist/lib/utils/path-resolver.js +44 -0
- package/modules/auth/authjs/files/nextjs/api/auth/[...nextauth]/route.ts +3 -0
- package/modules/auth/authjs/files/nextjs/proxy.ts +1 -0
- package/modules/auth/authjs/files/shared/lib/auth.ts +119 -0
- package/modules/auth/authjs/files/{prisma → shared/prisma}/schema.prisma +11 -1
- package/modules/auth/authjs/generator.json +18 -8
- package/modules/auth/better-auth/files/express/middlewares/authorize.ts +54 -0
- package/modules/auth/better-auth/files/express/types/express.d.ts +16 -0
- package/modules/auth/better-auth/files/nextjs/lib/auth/auth-guards.ts +31 -0
- package/modules/auth/better-auth/files/nextjs/proxy.ts +34 -0
- package/modules/auth/better-auth/files/{lib → shared/lib}/auth-client.ts +1 -1
- package/modules/auth/better-auth/files/{lib → shared/lib}/auth.ts +46 -20
- package/modules/auth/better-auth/files/{prisma → shared/prisma}/schema.prisma +11 -2
- package/modules/auth/better-auth/generator.json +74 -19
- package/modules/database/mongoose/generator.json +16 -2
- package/modules/database/prisma/files/lib/prisma.ts +1 -1
- package/modules/database/prisma/files/prisma/schema.prisma +1 -2
- package/modules/database/prisma/generator.json +8 -1
- package/package.json +2 -2
- package/templates/express/env.example +2 -1
- package/templates/express/package.json +3 -4
- package/templates/express/src/app.ts +18 -25
- package/templates/express/src/config/cors.ts +12 -0
- package/templates/express/src/config/helmet.ts +5 -0
- package/templates/express/src/config/logger.ts +6 -0
- package/templates/express/src/config/rate-limit.ts +11 -0
- package/templates/express/src/{features → modules}/health/health.route.ts +1 -1
- package/templates/express/src/routes/index.ts +12 -0
- package/templates/express/src/shared/errors/api-error.ts +14 -0
- package/templates/express/src/shared/errors/error-codes.ts +9 -0
- package/templates/express/src/shared/logger/logger.ts +20 -0
- package/templates/express/src/{middlewares → shared/middlewares}/error.middleware.ts +1 -1
- package/templates/express/src/shared/middlewares/not-found.middleware.ts +9 -0
- package/templates/express/src/shared/utils/async-handler.ts +9 -0
- package/templates/express/src/shared/utils/pagination.ts +6 -0
- package/templates/express/src/shared/utils/response.ts +9 -0
- package/templates/express/tsconfig.json +9 -3
- package/templates/react/src/app/layouts/dashboard-layout.tsx +8 -0
- package/templates/react/src/app/layouts/public-layout.tsx +5 -0
- package/templates/react/src/app/providers.tsx +20 -0
- package/templates/react/src/app/router.tsx +21 -0
- package/templates/react/src/{pages/About.tsx → features/about/pages/about.tsx} +1 -1
- package/templates/react/src/{pages/Home.tsx → features/home/pages/home.tsx} +1 -1
- package/templates/react/src/main.tsx +2 -2
- package/templates/react/src/{api/client.ts → shared/api/http.ts} +1 -1
- package/templates/react/src/{pages/NotFound.tsx → shared/pages/not-found.tsx} +1 -1
- package/dist/lib/git-utils.d.ts +0 -1
- package/dist/lib/git-utils.js +0 -29
- package/modules/auth/authjs/files/api/auth/[...nextauth]/route.ts +0 -2
- package/modules/auth/authjs/files/lib/auth.ts +0 -22
- /package/modules/auth/better-auth/files/{api → nextjs/api}/auth/[...all]/route.ts +0 -0
- /package/modules/auth/better-auth/files/{lib → shared/lib/email}/email-service.ts +0 -0
- /package/modules/auth/better-auth/files/{lib → shared/lib/email}/email-templates.ts +0 -0
- /package/templates/express/src/{features → modules}/health/health.controller.ts +0 -0
- /package/templates/express/src/{features → modules}/health/health.service.ts +0 -0
- /package/templates/react/src/{components/ErrorBoundary.tsx → shared/components/error-boundary.tsx} +0 -0
- /package/templates/react/src/{components/Layout.tsx → shared/components/layout.tsx} +0 -0
- /package/templates/react/src/{components/Loading.tsx → shared/components/loading.tsx} +0 -0
- /package/templates/react/src/{components/SEO.tsx → shared/components/seo.tsx} +0 -0
- /package/templates/react/src/{lib/queryClient.ts → shared/lib/query-client.ts} +0 -0
|
@@ -1,4 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
36
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
37
|
};
|
|
@@ -9,24 +42,64 @@ exports.addDependencies = addDependencies;
|
|
|
9
42
|
exports.initGit = initGit;
|
|
10
43
|
const detect_package_manager_1 = require("detect-package-manager");
|
|
11
44
|
const execa_1 = __importDefault(require("execa"));
|
|
45
|
+
const fs = __importStar(require("fs-extra"));
|
|
46
|
+
const path = __importStar(require("path"));
|
|
47
|
+
const constants_1 = require("../constants");
|
|
12
48
|
const logger_1 = require("../ui/logger");
|
|
13
49
|
async function detectPackageManager(cwd) {
|
|
14
50
|
try {
|
|
51
|
+
for (const { file, pm } of constants_1.LOCK_FILES_ARRAY) {
|
|
52
|
+
if (await fs.pathExists(path.join(cwd, file))) {
|
|
53
|
+
logger_1.logger.debug(`Detected ${pm} from ${file}`);
|
|
54
|
+
return pm;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
15
57
|
const pm = await (0, detect_package_manager_1.detect)({ cwd });
|
|
58
|
+
logger_1.logger.debug(`Detected ${pm} using detect-package-manager`);
|
|
16
59
|
return pm;
|
|
17
60
|
}
|
|
18
|
-
catch {
|
|
19
|
-
|
|
61
|
+
catch (error) {
|
|
62
|
+
logger_1.logger.debug(`Package manager detection failed, defaulting to npm: ${error}`);
|
|
63
|
+
return constants_1.PACKAGE_MANAGERS.NPM;
|
|
20
64
|
}
|
|
21
65
|
}
|
|
22
|
-
async function installDependencies(cwd, pm) {
|
|
66
|
+
async function installDependencies(cwd, pm, maxRetries = 2) {
|
|
23
67
|
const args = ["install"];
|
|
24
68
|
const stdio = "pipe";
|
|
25
|
-
|
|
69
|
+
let lastError = null;
|
|
70
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
71
|
+
try {
|
|
72
|
+
if (attempt > 0) {
|
|
73
|
+
logger_1.logger.debug(`Retry attempt ${attempt} for installing dependencies`);
|
|
74
|
+
await new Promise((resolve) => setTimeout(resolve, constants_1.TIMEOUTS.RETRY_DELAY_BASE * attempt));
|
|
75
|
+
}
|
|
76
|
+
await (0, execa_1.default)(pm, args, { cwd, stdio, timeout: constants_1.TIMEOUTS.PACKAGE_INSTALL });
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
lastError = error;
|
|
81
|
+
logger_1.logger.debug(`Installation attempt ${attempt + 1} failed: ${lastError.message}`);
|
|
82
|
+
const err = error;
|
|
83
|
+
const errorMsg = err.message || "";
|
|
84
|
+
if (errorMsg.includes("ECONNRESET") ||
|
|
85
|
+
errorMsg.includes("ETIMEDOUT") ||
|
|
86
|
+
errorMsg.includes("ENOTFOUND")) {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
throw new Error(`Failed to install dependencies after ${maxRetries + 1} attempts: ${lastError?.message || "Unknown error"}`);
|
|
26
93
|
}
|
|
27
94
|
async function addDependencies(cwd, pm, packages, dev = false) {
|
|
28
|
-
if (packages.length === 0)
|
|
95
|
+
if (packages.length === 0) {
|
|
96
|
+
logger_1.logger.debug("No packages to add, skipping");
|
|
29
97
|
return;
|
|
98
|
+
}
|
|
99
|
+
const invalidPackages = packages.filter((pkg) => !isValidPackageName(pkg));
|
|
100
|
+
if (invalidPackages.length > 0) {
|
|
101
|
+
throw new Error(`Invalid package names: ${invalidPackages.join(", ")}`);
|
|
102
|
+
}
|
|
30
103
|
const spinner = logger_1.logger.startSpinner(`Adding ${dev ? "dev " : ""}dependencies: ${packages.join(", ")}...`);
|
|
31
104
|
try {
|
|
32
105
|
const stdio = "pipe";
|
|
@@ -44,21 +117,63 @@ async function addDependencies(cwd, pm, packages, dev = false) {
|
|
|
44
117
|
case "bun":
|
|
45
118
|
args = ["add", ...(dev ? ["-d"] : []), ...packages];
|
|
46
119
|
break;
|
|
120
|
+
default:
|
|
121
|
+
throw new Error(`Unsupported package manager: ${pm}`);
|
|
47
122
|
}
|
|
48
|
-
|
|
123
|
+
logger_1.logger.debug(`Running: ${pm} ${args.join(" ")}`);
|
|
124
|
+
await (0, execa_1.default)(pm, args, { cwd, stdio, timeout: constants_1.TIMEOUTS.PACKAGE_INSTALL });
|
|
49
125
|
spinner.succeed(`Dependencies added successfully`);
|
|
50
126
|
}
|
|
51
127
|
catch (error) {
|
|
52
128
|
spinner.fail(`Failed to add dependencies`);
|
|
53
|
-
|
|
129
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
130
|
+
logger_1.logger.debug(`Full error: ${errorMessage}`);
|
|
131
|
+
if (errorMessage.includes("ENOTFOUND") || errorMessage.includes("ETIMEDOUT")) {
|
|
132
|
+
throw new Error(`Network error while adding dependencies. Please check your internet connection and try again.`);
|
|
133
|
+
}
|
|
134
|
+
else if (errorMessage.includes("404")) {
|
|
135
|
+
throw new Error(`One or more packages not found. Please verify package names: ${packages.join(", ")}`);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
throw new Error(`Failed to add dependencies: ${errorMessage}`);
|
|
139
|
+
}
|
|
54
140
|
}
|
|
55
141
|
}
|
|
142
|
+
function isValidPackageName(packageName) {
|
|
143
|
+
const nameOnly = packageName.split("@").filter(Boolean)[0] || packageName;
|
|
144
|
+
const validPattern = /^(@[a-z0-9-~][a-z0-9-._~]*\/)?[a-z0-9-~][a-z0-9-._~]*$/i;
|
|
145
|
+
return validPattern.test(nameOnly);
|
|
146
|
+
}
|
|
56
147
|
async function initGit(cwd) {
|
|
57
148
|
const spinner = logger_1.logger.startSpinner("Initializing git repository...");
|
|
149
|
+
try {
|
|
150
|
+
await (0, execa_1.default)("git", ["--version"], { cwd, stdio: "pipe" });
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
spinner.fail("Git is not installed");
|
|
154
|
+
logger_1.logger.warn("Skipping git initialization. Please install git to enable version control.");
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
if (await fs.pathExists(path.join(cwd, ".git"))) {
|
|
159
|
+
spinner.succeed("Git repository already exists");
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
58
166
|
const run = async (stdio) => {
|
|
59
167
|
await (0, execa_1.default)("git", ["init"], { cwd, stdio });
|
|
60
168
|
await (0, execa_1.default)("git", ["add", "."], { cwd, stdio });
|
|
61
|
-
|
|
169
|
+
try {
|
|
170
|
+
await (0, execa_1.default)("git", ["config", "user.name"], { cwd, stdio: "pipe" });
|
|
171
|
+
await (0, execa_1.default)("git", ["config", "user.email"], { cwd, stdio: "pipe" });
|
|
172
|
+
await (0, execa_1.default)("git", ["commit", "-m", "Initial commit from StackKit"], { cwd, stdio });
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
logger_1.logger.debug("Git config not found, skipping initial commit");
|
|
176
|
+
}
|
|
62
177
|
};
|
|
63
178
|
try {
|
|
64
179
|
await run("pipe");
|
|
@@ -67,7 +182,7 @@ async function initGit(cwd) {
|
|
|
67
182
|
}
|
|
68
183
|
catch (error) {
|
|
69
184
|
const err = error;
|
|
70
|
-
|
|
185
|
+
logger_1.logger.debug(`Git init error: ${err.message}`);
|
|
71
186
|
const isENOBUFS = (e) => {
|
|
72
187
|
if (!e || typeof e !== "object")
|
|
73
188
|
return false;
|
|
@@ -77,19 +192,20 @@ async function initGit(cwd) {
|
|
|
77
192
|
String(obj.message ?? "").includes("ENOBUFS"));
|
|
78
193
|
};
|
|
79
194
|
if (isENOBUFS(err)) {
|
|
80
|
-
|
|
81
|
-
logger_1.logger.info("
|
|
195
|
+
spinner.warn("Skipped git initialization due to system resource limits");
|
|
196
|
+
logger_1.logger.info("You can manually initialize git later with: git init");
|
|
82
197
|
return;
|
|
83
198
|
}
|
|
84
199
|
try {
|
|
85
200
|
await run("inherit");
|
|
86
|
-
spinner.succeed("Git repository initialized
|
|
201
|
+
spinner.succeed("Git repository initialized");
|
|
87
202
|
return;
|
|
88
203
|
}
|
|
89
204
|
catch (fallbackErr) {
|
|
90
205
|
const fe = fallbackErr;
|
|
91
|
-
logger_1.logger.
|
|
92
|
-
spinner.
|
|
206
|
+
logger_1.logger.debug(`Git init fallback error: ${fe.message}`);
|
|
207
|
+
spinner.warn("Git initialization skipped");
|
|
208
|
+
logger_1.logger.info("You can manually initialize git later with: git init");
|
|
93
209
|
return;
|
|
94
210
|
}
|
|
95
211
|
}
|
package/dist/lib/ui/logger.d.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { Ora } from "ora";
|
|
2
2
|
export declare class Logger {
|
|
3
3
|
private spinner;
|
|
4
|
+
private debugMode;
|
|
5
|
+
private silentMode;
|
|
6
|
+
setDebugMode(enabled: boolean): void;
|
|
7
|
+
setSilentMode(enabled: boolean): void;
|
|
4
8
|
info(message: string): void;
|
|
5
9
|
success(message: string): void;
|
|
6
|
-
error(message: string): void;
|
|
10
|
+
error(message: string, error?: Error): void;
|
|
7
11
|
warn(message: string): void;
|
|
12
|
+
debug(message: string): void;
|
|
8
13
|
log(message: string): void;
|
|
9
14
|
newLine(): void;
|
|
10
15
|
startSpinner(text: string): Ora;
|
|
@@ -12,5 +17,7 @@ export declare class Logger {
|
|
|
12
17
|
updateSpinner(text: string): void;
|
|
13
18
|
header(text: string): void;
|
|
14
19
|
footer(): void;
|
|
20
|
+
box(text: string, color?: "cyan" | "green" | "yellow" | "red"): void;
|
|
21
|
+
logWithPrefix(prefix: string, message: string, color?: "blue" | "green" | "yellow" | "red" | "cyan"): void;
|
|
15
22
|
}
|
|
16
23
|
export declare const logger: Logger;
|
package/dist/lib/ui/logger.js
CHANGED
|
@@ -9,31 +9,64 @@ const ora_1 = __importDefault(require("ora"));
|
|
|
9
9
|
class Logger {
|
|
10
10
|
constructor() {
|
|
11
11
|
this.spinner = null;
|
|
12
|
+
this.debugMode = false;
|
|
13
|
+
this.silentMode = false;
|
|
14
|
+
}
|
|
15
|
+
setDebugMode(enabled) {
|
|
16
|
+
this.debugMode = enabled;
|
|
17
|
+
}
|
|
18
|
+
setSilentMode(enabled) {
|
|
19
|
+
this.silentMode = enabled;
|
|
12
20
|
}
|
|
13
21
|
info(message) {
|
|
22
|
+
if (this.silentMode)
|
|
23
|
+
return;
|
|
14
24
|
process.stdout.write(chalk_1.default.blue("ℹ") + " " + message + "\n");
|
|
15
25
|
}
|
|
16
26
|
success(message) {
|
|
27
|
+
if (this.silentMode)
|
|
28
|
+
return;
|
|
17
29
|
process.stdout.write(chalk_1.default.green("✔") + " " + message + "\n");
|
|
18
30
|
}
|
|
19
|
-
error(message) {
|
|
31
|
+
error(message, error) {
|
|
20
32
|
process.stderr.write(chalk_1.default.red("✖") + " " + message + "\n");
|
|
33
|
+
if (error && this.debugMode) {
|
|
34
|
+
this.debug(`Error stack: ${error.stack || error.message}`);
|
|
35
|
+
}
|
|
21
36
|
}
|
|
22
37
|
warn(message) {
|
|
38
|
+
if (this.silentMode)
|
|
39
|
+
return;
|
|
23
40
|
process.stdout.write(chalk_1.default.yellow("⚠") + " " + message + "\n");
|
|
24
41
|
}
|
|
42
|
+
debug(message) {
|
|
43
|
+
if (!this.debugMode)
|
|
44
|
+
return;
|
|
45
|
+
process.stdout.write(chalk_1.default.gray("[DEBUG] ") + chalk_1.default.dim(message) + "\n");
|
|
46
|
+
}
|
|
25
47
|
log(message) {
|
|
48
|
+
if (this.silentMode)
|
|
49
|
+
return;
|
|
26
50
|
process.stdout.write(message + "\n");
|
|
27
51
|
}
|
|
28
52
|
newLine() {
|
|
53
|
+
if (this.silentMode)
|
|
54
|
+
return;
|
|
29
55
|
process.stdout.write("\n");
|
|
30
56
|
}
|
|
31
57
|
startSpinner(text) {
|
|
58
|
+
if (this.silentMode) {
|
|
59
|
+
return {
|
|
60
|
+
succeed: () => { },
|
|
61
|
+
fail: () => { },
|
|
62
|
+
text: text,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
32
65
|
this.spinner = (0, ora_1.default)(text).start();
|
|
33
66
|
return this.spinner;
|
|
34
67
|
}
|
|
35
68
|
stopSpinner(success = true, text) {
|
|
36
|
-
if (this.spinner) {
|
|
69
|
+
if (this.spinner && !this.silentMode) {
|
|
37
70
|
if (success) {
|
|
38
71
|
this.spinner.succeed(text);
|
|
39
72
|
}
|
|
@@ -44,16 +77,40 @@ class Logger {
|
|
|
44
77
|
}
|
|
45
78
|
}
|
|
46
79
|
updateSpinner(text) {
|
|
47
|
-
if (this.spinner) {
|
|
80
|
+
if (this.spinner && !this.silentMode) {
|
|
48
81
|
this.spinner.text = text;
|
|
49
82
|
}
|
|
50
83
|
}
|
|
51
84
|
header(text) {
|
|
85
|
+
if (this.silentMode)
|
|
86
|
+
return;
|
|
52
87
|
process.stdout.write(chalk_1.default.bold.cyan(text) + "\n");
|
|
53
88
|
}
|
|
54
89
|
footer() {
|
|
90
|
+
if (this.silentMode)
|
|
91
|
+
return;
|
|
55
92
|
process.stdout.write("\n");
|
|
56
93
|
}
|
|
94
|
+
box(text, color = "cyan") {
|
|
95
|
+
if (this.silentMode)
|
|
96
|
+
return;
|
|
97
|
+
const lines = text.split("\n");
|
|
98
|
+
const maxLength = Math.max(...lines.map((line) => line.length));
|
|
99
|
+
const border = "─".repeat(maxLength + 2);
|
|
100
|
+
const colorFn = chalk_1.default[color];
|
|
101
|
+
process.stdout.write(colorFn("┌" + border + "┐") + "\n");
|
|
102
|
+
lines.forEach((line) => {
|
|
103
|
+
const padding = " ".repeat(maxLength - line.length);
|
|
104
|
+
process.stdout.write(colorFn("│ ") + line + padding + colorFn(" │") + "\n");
|
|
105
|
+
});
|
|
106
|
+
process.stdout.write(colorFn("└" + border + "┘") + "\n");
|
|
107
|
+
}
|
|
108
|
+
logWithPrefix(prefix, message, color = "blue") {
|
|
109
|
+
if (this.silentMode)
|
|
110
|
+
return;
|
|
111
|
+
const colorFn = chalk_1.default[color];
|
|
112
|
+
process.stdout.write(colorFn(prefix) + " " + message + "\n");
|
|
113
|
+
}
|
|
57
114
|
}
|
|
58
115
|
exports.Logger = Logger;
|
|
59
116
|
exports.logger = new Logger();
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
type CopyFilterFunction = Parameters<typeof fs.copy>[2];
|
|
3
|
+
export declare function pathExists(filePath: string): Promise<boolean>;
|
|
4
|
+
export declare function ensureDir(dirPath: string): Promise<void>;
|
|
5
|
+
export declare function readFile(filePath: string): Promise<string>;
|
|
6
|
+
export declare function writeFile(filePath: string, content: string): Promise<void>;
|
|
7
|
+
export declare function copyDir(source: string, destination: string, options?: CopyFilterFunction): Promise<void>;
|
|
8
|
+
export declare function readDir(dirPath: string): Promise<string[]>;
|
|
9
|
+
export declare function isDirectory(dirPath: string): Promise<boolean>;
|
|
10
|
+
export declare function findFilesInDir(dirPath: string, predicate: (file: string) => boolean): Promise<string[]>;
|
|
11
|
+
export declare function getEnvFilePath(projectRoot: string): Promise<string | null>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,61 @@
|
|
|
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.pathExists = pathExists;
|
|
7
|
+
exports.ensureDir = ensureDir;
|
|
8
|
+
exports.readFile = readFile;
|
|
9
|
+
exports.writeFile = writeFile;
|
|
10
|
+
exports.copyDir = copyDir;
|
|
11
|
+
exports.readDir = readDir;
|
|
12
|
+
exports.isDirectory = isDirectory;
|
|
13
|
+
exports.findFilesInDir = findFilesInDir;
|
|
14
|
+
exports.getEnvFilePath = getEnvFilePath;
|
|
15
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
16
|
+
const path_1 = __importDefault(require("path"));
|
|
17
|
+
const constants_1 = require("../constants");
|
|
18
|
+
async function pathExists(filePath) {
|
|
19
|
+
return fs_extra_1.default.pathExists(filePath);
|
|
20
|
+
}
|
|
21
|
+
async function ensureDir(dirPath) {
|
|
22
|
+
await fs_extra_1.default.ensureDir(dirPath);
|
|
23
|
+
}
|
|
24
|
+
async function readFile(filePath) {
|
|
25
|
+
return fs_extra_1.default.readFile(filePath, "utf-8");
|
|
26
|
+
}
|
|
27
|
+
async function writeFile(filePath, content) {
|
|
28
|
+
await fs_extra_1.default.ensureDir(path_1.default.dirname(filePath));
|
|
29
|
+
await fs_extra_1.default.writeFile(filePath, content, "utf-8");
|
|
30
|
+
}
|
|
31
|
+
async function copyDir(source, destination, options) {
|
|
32
|
+
await fs_extra_1.default.copy(source, destination, options);
|
|
33
|
+
}
|
|
34
|
+
async function readDir(dirPath) {
|
|
35
|
+
return fs_extra_1.default.readdir(dirPath);
|
|
36
|
+
}
|
|
37
|
+
async function isDirectory(dirPath) {
|
|
38
|
+
try {
|
|
39
|
+
const stat = await fs_extra_1.default.stat(dirPath);
|
|
40
|
+
return stat.isDirectory();
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
async function findFilesInDir(dirPath, predicate) {
|
|
47
|
+
const exists = await pathExists(dirPath);
|
|
48
|
+
if (!exists)
|
|
49
|
+
return [];
|
|
50
|
+
const files = await readDir(dirPath);
|
|
51
|
+
return files.filter((file) => predicate(file));
|
|
52
|
+
}
|
|
53
|
+
async function getEnvFilePath(projectRoot) {
|
|
54
|
+
for (const envFile of constants_1.ENV_FILES) {
|
|
55
|
+
const fullPath = path_1.default.join(projectRoot, envFile);
|
|
56
|
+
if (await pathExists(fullPath)) {
|
|
57
|
+
return fullPath;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function loadJsonAsync<T = unknown>(filePath: string): Promise<T | null>;
|
|
2
|
+
export declare function loadJsonSync<T = unknown>(filePath: string): T | null;
|
|
3
|
+
export declare function saveJson<T = unknown>(filePath: string, data: T, options?: {
|
|
4
|
+
spaces?: number;
|
|
5
|
+
}): Promise<void>;
|
|
6
|
+
export declare function loadJsonWithDefault<T>(filePath: string, defaultValue: T): Promise<T>;
|
|
@@ -0,0 +1,34 @@
|
|
|
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.loadJsonAsync = loadJsonAsync;
|
|
7
|
+
exports.loadJsonSync = loadJsonSync;
|
|
8
|
+
exports.saveJson = saveJson;
|
|
9
|
+
exports.loadJsonWithDefault = loadJsonWithDefault;
|
|
10
|
+
const fs_1 = require("fs");
|
|
11
|
+
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
12
|
+
async function loadJsonAsync(filePath) {
|
|
13
|
+
try {
|
|
14
|
+
return await fs_extra_1.default.readJSON(filePath);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function loadJsonSync(filePath) {
|
|
21
|
+
try {
|
|
22
|
+
return JSON.parse((0, fs_1.readFileSync)(filePath, "utf-8"));
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async function saveJson(filePath, data, options) {
|
|
29
|
+
await fs_extra_1.default.writeJSON(filePath, data, { spaces: options?.spaces ?? 2 });
|
|
30
|
+
}
|
|
31
|
+
async function loadJsonWithDefault(filePath, defaultValue) {
|
|
32
|
+
const data = await loadJsonAsync(filePath);
|
|
33
|
+
return data ?? defaultValue;
|
|
34
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ModuleMetadata } from "../../types";
|
|
2
|
+
export declare function loadModuleMetadata(category: string, moduleName: string): Promise<ModuleMetadata | null>;
|
|
3
|
+
export declare function loadGeneratorConfig<T = unknown>(category: string, moduleName: string): Promise<T | null>;
|
|
4
|
+
export declare function findModuleByName(moduleName: string, provider?: string): Promise<{
|
|
5
|
+
category: string;
|
|
6
|
+
metadata: ModuleMetadata;
|
|
7
|
+
} | null>;
|
|
8
|
+
export declare function getAllModules(): Promise<ModuleMetadata[]>;
|
|
9
|
+
export declare function getModulesByCategory(category: string): Promise<ModuleMetadata[]>;
|
|
@@ -0,0 +1,98 @@
|
|
|
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.loadModuleMetadata = loadModuleMetadata;
|
|
7
|
+
exports.loadGeneratorConfig = loadGeneratorConfig;
|
|
8
|
+
exports.findModuleByName = findModuleByName;
|
|
9
|
+
exports.getAllModules = getAllModules;
|
|
10
|
+
exports.getModulesByCategory = getModulesByCategory;
|
|
11
|
+
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const fs_helpers_1 = require("./fs-helpers");
|
|
13
|
+
const json_loader_1 = require("./json-loader");
|
|
14
|
+
const path_resolver_1 = require("./path-resolver");
|
|
15
|
+
async function loadModuleMetadata(category, moduleName) {
|
|
16
|
+
const moduleJsonPath = (0, path_resolver_1.getModuleJsonPath)(category, moduleName);
|
|
17
|
+
return (0, json_loader_1.loadJsonAsync)(moduleJsonPath);
|
|
18
|
+
}
|
|
19
|
+
async function loadGeneratorConfig(category, moduleName) {
|
|
20
|
+
const generatorPath = (0, path_resolver_1.getGeneratorJsonPath)(category, moduleName);
|
|
21
|
+
return (0, json_loader_1.loadJsonAsync)(generatorPath);
|
|
22
|
+
}
|
|
23
|
+
async function findModuleByName(moduleName, provider) {
|
|
24
|
+
const modulesDir = (0, path_resolver_1.getModulesPath)();
|
|
25
|
+
if (!(await (0, fs_helpers_1.pathExists)(modulesDir))) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
const categories = await (0, fs_helpers_1.readDir)(modulesDir);
|
|
29
|
+
for (const category of categories) {
|
|
30
|
+
const categoryPath = path_1.default.join(modulesDir, category);
|
|
31
|
+
if (!(await (0, fs_helpers_1.isDirectory)(categoryPath))) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const moduleDirs = await (0, fs_helpers_1.readDir)(categoryPath);
|
|
35
|
+
for (const moduleDir of moduleDirs) {
|
|
36
|
+
const modulePath = path_1.default.join(categoryPath, moduleDir);
|
|
37
|
+
if (!(await (0, fs_helpers_1.isDirectory)(modulePath))) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const metadataPath = path_1.default.join(modulePath, "module.json");
|
|
41
|
+
if (await (0, fs_helpers_1.pathExists)(metadataPath)) {
|
|
42
|
+
const metadata = await (0, json_loader_1.loadJsonAsync)(metadataPath);
|
|
43
|
+
if (!metadata)
|
|
44
|
+
continue;
|
|
45
|
+
if (provider && moduleDir === provider) {
|
|
46
|
+
return { category, metadata };
|
|
47
|
+
}
|
|
48
|
+
if (!provider && (metadata.category === moduleName || moduleDir === moduleName)) {
|
|
49
|
+
return { category, metadata };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
async function getAllModules() {
|
|
57
|
+
const modulesDir = (0, path_resolver_1.getModulesPath)();
|
|
58
|
+
if (!(await (0, fs_helpers_1.pathExists)(modulesDir))) {
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
const modules = [];
|
|
62
|
+
const categories = await (0, fs_helpers_1.readDir)(modulesDir);
|
|
63
|
+
for (const category of categories) {
|
|
64
|
+
const categoryPath = path_1.default.join(modulesDir, category);
|
|
65
|
+
if (!(await (0, fs_helpers_1.isDirectory)(categoryPath))) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const moduleDirs = await (0, fs_helpers_1.readDir)(categoryPath);
|
|
69
|
+
for (const moduleDir of moduleDirs) {
|
|
70
|
+
const metadataPath = path_1.default.join(categoryPath, moduleDir, "module.json");
|
|
71
|
+
if (await (0, fs_helpers_1.pathExists)(metadataPath)) {
|
|
72
|
+
const metadata = await (0, json_loader_1.loadJsonAsync)(metadataPath);
|
|
73
|
+
if (metadata) {
|
|
74
|
+
modules.push(metadata);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return modules;
|
|
80
|
+
}
|
|
81
|
+
async function getModulesByCategory(category) {
|
|
82
|
+
const categoryPath = path_1.default.join((0, path_resolver_1.getModulesPath)(), category);
|
|
83
|
+
if (!(await (0, fs_helpers_1.pathExists)(categoryPath))) {
|
|
84
|
+
return [];
|
|
85
|
+
}
|
|
86
|
+
const modules = [];
|
|
87
|
+
const moduleDirs = await (0, fs_helpers_1.readDir)(categoryPath);
|
|
88
|
+
for (const moduleDir of moduleDirs) {
|
|
89
|
+
const metadataPath = path_1.default.join(categoryPath, moduleDir, "module.json");
|
|
90
|
+
if (await (0, fs_helpers_1.pathExists)(metadataPath)) {
|
|
91
|
+
const metadata = await (0, json_loader_1.loadJsonAsync)(metadataPath);
|
|
92
|
+
if (metadata) {
|
|
93
|
+
modules.push(metadata);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return modules;
|
|
98
|
+
}
|
|
@@ -34,12 +34,85 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.getPackageRoot = getPackageRoot;
|
|
37
|
+
exports.isPackageRoot = isPackageRoot;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
37
39
|
const path = __importStar(require("path"));
|
|
40
|
+
const constants_1 = require("../constants");
|
|
38
41
|
function getPackageRoot() {
|
|
39
42
|
try {
|
|
40
|
-
|
|
43
|
+
const packageJsonPath = require.resolve("stackkit/package.json");
|
|
44
|
+
const root = path.dirname(packageJsonPath);
|
|
45
|
+
if (fs.existsSync(root) && fs.existsSync(path.join(root, constants_1.FILE_NAMES.PACKAGE_JSON))) {
|
|
46
|
+
return root;
|
|
47
|
+
}
|
|
41
48
|
}
|
|
42
49
|
catch {
|
|
43
|
-
|
|
50
|
+
void 0;
|
|
51
|
+
}
|
|
52
|
+
try {
|
|
53
|
+
let current = __dirname;
|
|
54
|
+
let attempts = 0;
|
|
55
|
+
const maxAttempts = constants_1.RETRY_CONFIG.PACKAGE_ROOT_MAX_ATTEMPTS;
|
|
56
|
+
while (attempts < maxAttempts) {
|
|
57
|
+
const packageJsonPath = path.join(current, constants_1.FILE_NAMES.PACKAGE_JSON);
|
|
58
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
59
|
+
try {
|
|
60
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
61
|
+
if (packageJson.name === "stackkit") {
|
|
62
|
+
return current;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
void 0;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const parent = path.dirname(current);
|
|
70
|
+
if (parent === current) {
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
current = parent;
|
|
74
|
+
attempts++;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
void 0;
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
const fallbackRoot = path.resolve(__dirname, "..", "..", "..");
|
|
82
|
+
const packageJsonPath = path.join(fallbackRoot, constants_1.FILE_NAMES.PACKAGE_JSON);
|
|
83
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
84
|
+
try {
|
|
85
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
86
|
+
if (packageJson.name === "stackkit") {
|
|
87
|
+
return fallbackRoot;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
void 0;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
void 0;
|
|
97
|
+
}
|
|
98
|
+
const lastResortPath = path.resolve(__dirname, "..", "..", "..");
|
|
99
|
+
if (!fs.existsSync(lastResortPath)) {
|
|
100
|
+
throw new Error("Unable to determine stackkit package root. " +
|
|
101
|
+
"Please ensure stackkit is properly installed and run from a valid location. " +
|
|
102
|
+
`Attempted path: ${lastResortPath}`);
|
|
103
|
+
}
|
|
104
|
+
return lastResortPath;
|
|
105
|
+
}
|
|
106
|
+
function isPackageRoot(dir) {
|
|
107
|
+
try {
|
|
108
|
+
const packageJsonPath = path.join(dir, constants_1.FILE_NAMES.PACKAGE_JSON);
|
|
109
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
|
|
113
|
+
return packageJson.name === "stackkit";
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return false;
|
|
44
117
|
}
|
|
45
118
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function getModulesPath(): string;
|
|
2
|
+
export declare function getTemplatesPath(): string;
|
|
3
|
+
export declare function getModulePath(category: string, moduleName: string): string;
|
|
4
|
+
export declare function getModuleJsonPath(category: string, moduleName: string): string;
|
|
5
|
+
export declare function getGeneratorJsonPath(category: string, moduleName: string): string;
|
|
6
|
+
export declare function getModuleFilesPath(category: string, moduleName: string): string;
|
|
7
|
+
export declare function getTemplateJsonPath(frameworkName: string): string;
|
|
8
|
+
export declare function getDatabaseModulesPath(): string;
|
|
9
|
+
export declare function getAuthModulesPath(): string;
|