stackkit-cli 0.4.2 → 0.4.3
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 +17 -10
- package/bin/stackkit.js +1 -1
- package/dist/commands/add.js +26 -24
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.js +34 -29
- package/dist/commands/list.js +12 -12
- package/dist/index.js +25 -23
- package/dist/types/index.d.ts +14 -14
- package/dist/utils/code-inject.d.ts +1 -1
- package/dist/utils/code-inject.js +6 -6
- package/dist/utils/detect.d.ts +1 -1
- package/dist/utils/detect.js +48 -44
- package/dist/utils/env-editor.js +20 -20
- package/dist/utils/files.js +4 -4
- package/dist/utils/json-editor.d.ts +3 -3
- package/dist/utils/json-editor.js +10 -14
- package/dist/utils/logger.d.ts +1 -1
- package/dist/utils/logger.js +8 -8
- package/dist/utils/package-manager.d.ts +2 -2
- package/dist/utils/package-manager.js +33 -26
- package/modules/auth/better-auth-express/adapters/mongoose-mongodb.ts +13 -0
- package/modules/auth/better-auth-express/adapters/prisma-mongodb.ts +15 -0
- package/modules/auth/better-auth-express/adapters/prisma-postgresql.ts +15 -0
- package/modules/auth/better-auth-express/files/lib/auth.ts +1 -1
- package/modules/auth/better-auth-express/files/routes/auth.ts +3 -3
- package/modules/auth/better-auth-express/files/schemas/prisma-mongodb-schema.prisma +72 -0
- package/modules/auth/better-auth-express/files/schemas/prisma-postgresql-schema.prisma +72 -0
- package/modules/auth/better-auth-express/module.json +26 -3
- package/modules/auth/better-auth-nextjs/adapters/mongoose-mongodb.ts +24 -0
- package/modules/auth/better-auth-nextjs/adapters/prisma-mongodb.ts +26 -0
- package/modules/auth/better-auth-nextjs/adapters/prisma-postgresql.ts +26 -0
- package/modules/auth/better-auth-nextjs/files/api/auth/[...all]/route.ts +2 -3
- package/modules/auth/better-auth-nextjs/files/lib/auth.ts +4 -4
- package/modules/auth/better-auth-nextjs/files/schemas/prisma-mongodb-schema.prisma +72 -0
- package/modules/auth/better-auth-nextjs/files/schemas/prisma-postgresql-schema.prisma +72 -0
- package/modules/auth/better-auth-nextjs/module.json +26 -5
- package/modules/auth/better-auth-react/files/lib/auth-client.ts +2 -2
- package/modules/auth/better-auth-react/module.json +7 -5
- package/modules/auth/clerk-express/files/lib/auth.ts +1 -1
- package/modules/auth/clerk-express/module.json +22 -8
- package/modules/auth/clerk-nextjs/files/lib/auth-provider.tsx +1 -1
- package/modules/auth/clerk-nextjs/files/middleware.ts +3 -3
- package/modules/auth/clerk-nextjs/module.json +50 -14
- package/modules/auth/clerk-react/files/lib/auth-provider.tsx +2 -2
- package/modules/auth/clerk-react/module.json +16 -7
- package/modules/database/mongoose-mongodb/files/lib/db.ts +3 -3
- package/modules/database/mongoose-mongodb/module.json +43 -6
- package/modules/database/prisma-mongodb/files/lib/db.ts +2 -2
- package/modules/database/prisma-mongodb/files/prisma/schema.prisma +1 -1
- package/modules/database/prisma-mongodb/module.json +28 -4
- package/modules/database/prisma-postgresql/files/lib/db.ts +2 -2
- package/modules/database/prisma-postgresql/files/prisma/schema.prisma +1 -1
- package/modules/database/prisma-postgresql/module.json +28 -4
- package/package.json +1 -1
- package/templates/express/.env.example +11 -0
- package/templates/express/eslint.config.cjs +42 -0
- package/templates/express/package.json +39 -0
- package/templates/express/src/app.ts +71 -0
- package/templates/express/src/config/env.ts +23 -0
- package/templates/express/src/middlewares/error.middleware.ts +18 -0
- package/templates/{bases/express-base → express}/src/server.ts +2 -2
- package/templates/express/template.json +44 -0
- package/templates/express/tsconfig.json +31 -0
- package/templates/{bases/nextjs-base → nextjs}/app/layout.tsx +1 -5
- package/templates/nextjs/app/page.tsx +57 -0
- package/templates/{bases/nextjs-base → nextjs}/package.json +2 -1
- package/templates/{bases/nextjs-base → nextjs}/template.json +13 -1
- package/templates/react-vite/.env.example +2 -0
- package/templates/react-vite/README.md +85 -0
- package/templates/react-vite/eslint.config.js +23 -0
- package/templates/{bases/react-vite-base → react-vite}/index.html +1 -0
- package/templates/{bases/react-vite-base → react-vite}/package.json +16 -2
- package/templates/react-vite/src/api/client.ts +47 -0
- package/templates/react-vite/src/api/services/user.service.ts +18 -0
- package/templates/react-vite/src/components/ErrorBoundary.tsx +51 -0
- package/templates/react-vite/src/components/Layout.tsx +13 -0
- package/templates/react-vite/src/components/Loading.tsx +8 -0
- package/templates/react-vite/src/components/SEO.tsx +49 -0
- package/templates/react-vite/src/config/constants.ts +5 -0
- package/templates/react-vite/src/hooks/index.ts +64 -0
- package/templates/react-vite/src/index.css +1 -0
- package/templates/react-vite/src/lib/queryClient.ts +12 -0
- package/templates/react-vite/src/main.tsx +22 -0
- package/templates/react-vite/src/pages/About.tsx +78 -0
- package/templates/react-vite/src/pages/Home.tsx +49 -0
- package/templates/react-vite/src/pages/NotFound.tsx +24 -0
- package/templates/react-vite/src/pages/UserProfile.tsx +40 -0
- package/templates/react-vite/src/router.tsx +33 -0
- package/templates/react-vite/src/types/api.d.ts +20 -0
- package/templates/react-vite/src/types/user.d.ts +6 -0
- package/templates/react-vite/src/utils/helpers.ts +51 -0
- package/templates/react-vite/src/utils/storage.ts +35 -0
- package/templates/react-vite/src/vite-env.d.ts +11 -0
- package/templates/react-vite/template.json +46 -0
- package/templates/react-vite/tsconfig.json +4 -0
- package/templates/react-vite/vite.config.ts +13 -0
- package/modules/database/drizzle-postgresql/files/drizzle.config.ts +0 -10
- package/modules/database/drizzle-postgresql/files/lib/db.ts +0 -7
- package/modules/database/drizzle-postgresql/files/lib/schema.ts +0 -8
- package/modules/database/drizzle-postgresql/module.json +0 -35
- package/templates/bases/express-base/.env.example +0 -2
- package/templates/bases/express-base/package.json +0 -23
- package/templates/bases/express-base/src/app.ts +0 -34
- package/templates/bases/express-base/src/config/env.ts +0 -14
- package/templates/bases/express-base/src/middlewares/error.middleware.ts +0 -12
- package/templates/bases/express-base/template.json +0 -7
- package/templates/bases/express-base/tsconfig.json +0 -14
- package/templates/bases/nextjs-base/app/page.tsx +0 -65
- package/templates/bases/react-vite-base/README.md +0 -73
- package/templates/bases/react-vite-base/eslint.config.js +0 -23
- package/templates/bases/react-vite-base/src/App.css +0 -42
- package/templates/bases/react-vite-base/src/App.tsx +0 -35
- package/templates/bases/react-vite-base/src/index.css +0 -68
- package/templates/bases/react-vite-base/src/main.tsx +0 -10
- package/templates/bases/react-vite-base/template.json +0 -19
- package/templates/bases/react-vite-base/tsconfig.json +0 -7
- package/templates/bases/react-vite-base/vite.config.ts +0 -7
- /package/templates/{bases/nextjs-base → nextjs}/README.md +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/app/favicon.ico +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/app/globals.css +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/eslint.config.mjs +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/next.config.ts +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/postcss.config.mjs +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/public/file.svg +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/public/globe.svg +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/public/next.svg +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/public/vercel.svg +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/public/window.svg +0 -0
- /package/templates/{bases/nextjs-base → nextjs}/tsconfig.json +0 -0
- /package/templates/{bases/react-vite-base → react-vite}/public/vite.svg +0 -0
- /package/templates/{bases/react-vite-base → react-vite}/src/assets/react.svg +0 -0
- /package/templates/{bases/react-vite-base → react-vite}/tsconfig.app.json +0 -0
- /package/templates/{bases/react-vite-base → react-vite}/tsconfig.node.json +0 -0
package/dist/utils/detect.js
CHANGED
|
@@ -9,9 +9,9 @@ exports.getLibPath = getLibPath;
|
|
|
9
9
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
10
10
|
const path_1 = __importDefault(require("path"));
|
|
11
11
|
async function detectProjectInfo(targetDir) {
|
|
12
|
-
const packageJsonPath = path_1.default.join(targetDir,
|
|
12
|
+
const packageJsonPath = path_1.default.join(targetDir, "package.json");
|
|
13
13
|
if (!(await fs_extra_1.default.pathExists(packageJsonPath))) {
|
|
14
|
-
throw new Error(
|
|
14
|
+
throw new Error("No package.json found. This does not appear to be a Node.js project.");
|
|
15
15
|
}
|
|
16
16
|
const packageJson = await fs_extra_1.default.readJSON(packageJsonPath);
|
|
17
17
|
// Detect framework
|
|
@@ -21,62 +21,66 @@ async function detectProjectInfo(targetDir) {
|
|
|
21
21
|
const isVite = packageJson.dependencies?.vite || packageJson.devDependencies?.vite;
|
|
22
22
|
let framework;
|
|
23
23
|
if (isNextJs) {
|
|
24
|
-
framework =
|
|
24
|
+
framework = "nextjs";
|
|
25
25
|
}
|
|
26
26
|
else if (isExpress) {
|
|
27
|
-
framework =
|
|
27
|
+
framework = "express";
|
|
28
28
|
}
|
|
29
29
|
else if (isReact && isVite) {
|
|
30
|
-
framework =
|
|
30
|
+
framework = "react-vite";
|
|
31
31
|
}
|
|
32
32
|
else if (isReact) {
|
|
33
|
-
framework =
|
|
33
|
+
framework = "react";
|
|
34
34
|
}
|
|
35
35
|
else {
|
|
36
|
-
framework =
|
|
36
|
+
framework = "unknown";
|
|
37
37
|
}
|
|
38
|
-
if (framework ===
|
|
39
|
-
throw new Error(
|
|
38
|
+
if (framework === "unknown") {
|
|
39
|
+
throw new Error("Only Next.js, Express, and React projects are currently supported.");
|
|
40
40
|
}
|
|
41
41
|
// Detect router type (only for Next.js)
|
|
42
|
-
let router =
|
|
43
|
-
if (framework ===
|
|
44
|
-
const appDirExists = await fs_extra_1.default.pathExists(path_1.default.join(targetDir,
|
|
45
|
-
const pagesDirExists = await fs_extra_1.default.pathExists(path_1.default.join(targetDir,
|
|
46
|
-
const srcAppDirExists = await fs_extra_1.default.pathExists(path_1.default.join(targetDir,
|
|
47
|
-
const srcPagesDirExists = await fs_extra_1.default.pathExists(path_1.default.join(targetDir,
|
|
42
|
+
let router = "unknown";
|
|
43
|
+
if (framework === "nextjs") {
|
|
44
|
+
const appDirExists = await fs_extra_1.default.pathExists(path_1.default.join(targetDir, "app"));
|
|
45
|
+
const pagesDirExists = await fs_extra_1.default.pathExists(path_1.default.join(targetDir, "pages"));
|
|
46
|
+
const srcAppDirExists = await fs_extra_1.default.pathExists(path_1.default.join(targetDir, "src", "app"));
|
|
47
|
+
const srcPagesDirExists = await fs_extra_1.default.pathExists(path_1.default.join(targetDir, "src", "pages"));
|
|
48
48
|
if (appDirExists || srcAppDirExists) {
|
|
49
|
-
router =
|
|
49
|
+
router = "app";
|
|
50
50
|
}
|
|
51
51
|
else if (pagesDirExists || srcPagesDirExists) {
|
|
52
|
-
router =
|
|
52
|
+
router = "pages";
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
// Detect TypeScript vs JavaScript
|
|
56
|
-
const tsconfigExists = await fs_extra_1.default.pathExists(path_1.default.join(targetDir,
|
|
57
|
-
const language = tsconfigExists ?
|
|
56
|
+
const tsconfigExists = await fs_extra_1.default.pathExists(path_1.default.join(targetDir, "tsconfig.json"));
|
|
57
|
+
const language = tsconfigExists ? "ts" : "js";
|
|
58
58
|
// Detect package manager
|
|
59
|
-
const yarnLockExists = await fs_extra_1.default.pathExists(path_1.default.join(targetDir,
|
|
60
|
-
const pnpmLockExists = await fs_extra_1.default.pathExists(path_1.default.join(targetDir,
|
|
61
|
-
|
|
59
|
+
const yarnLockExists = await fs_extra_1.default.pathExists(path_1.default.join(targetDir, "yarn.lock"));
|
|
60
|
+
const pnpmLockExists = await fs_extra_1.default.pathExists(path_1.default.join(targetDir, "pnpm-lock.yaml"));
|
|
61
|
+
const bunLockExists = await fs_extra_1.default.pathExists(path_1.default.join(targetDir, "bun.lockb"));
|
|
62
|
+
let packageManager = "npm";
|
|
62
63
|
if (pnpmLockExists) {
|
|
63
|
-
packageManager =
|
|
64
|
+
packageManager = "pnpm";
|
|
64
65
|
}
|
|
65
66
|
else if (yarnLockExists) {
|
|
66
|
-
packageManager =
|
|
67
|
+
packageManager = "yarn";
|
|
68
|
+
}
|
|
69
|
+
else if (bunLockExists) {
|
|
70
|
+
packageManager = "bun";
|
|
67
71
|
}
|
|
68
72
|
// Check for existing integrations
|
|
69
|
-
const hasAuth = !!(packageJson.dependencies?.[
|
|
70
|
-
packageJson.dependencies?.[
|
|
71
|
-
packageJson.dependencies?.[
|
|
72
|
-
packageJson.dependencies?.[
|
|
73
|
-
packageJson.dependencies?.[
|
|
74
|
-
packageJson.dependencies?.[
|
|
75
|
-
const hasPrisma = !!(packageJson.dependencies?.[
|
|
73
|
+
const hasAuth = !!(packageJson.dependencies?.["next-auth"] ||
|
|
74
|
+
packageJson.dependencies?.["better-auth"] ||
|
|
75
|
+
packageJson.dependencies?.["@auth/core"] ||
|
|
76
|
+
packageJson.dependencies?.["@clerk/nextjs"] ||
|
|
77
|
+
packageJson.dependencies?.["@kinde-oss/kinde-auth-nextjs"] ||
|
|
78
|
+
packageJson.dependencies?.["passport"]);
|
|
79
|
+
const hasPrisma = !!(packageJson.dependencies?.["@prisma/client"] || packageJson.devDependencies?.["prisma"]);
|
|
76
80
|
const hasDatabase = hasPrisma ||
|
|
77
|
-
!!(packageJson.dependencies?.[
|
|
78
|
-
packageJson.dependencies?.[
|
|
79
|
-
packageJson.dependencies?.[
|
|
81
|
+
!!(packageJson.dependencies?.["mongoose"] ||
|
|
82
|
+
packageJson.dependencies?.["typeorm"] ||
|
|
83
|
+
packageJson.dependencies?.["drizzle-orm"]);
|
|
80
84
|
return {
|
|
81
85
|
framework,
|
|
82
86
|
router,
|
|
@@ -89,19 +93,19 @@ async function detectProjectInfo(targetDir) {
|
|
|
89
93
|
};
|
|
90
94
|
}
|
|
91
95
|
function getRouterBasePath(projectInfo) {
|
|
92
|
-
const srcExists = fs_extra_1.default.existsSync(path_1.default.join(projectInfo.rootDir,
|
|
93
|
-
if (projectInfo.router ===
|
|
94
|
-
return srcExists ?
|
|
96
|
+
const srcExists = fs_extra_1.default.existsSync(path_1.default.join(projectInfo.rootDir, "src"));
|
|
97
|
+
if (projectInfo.router === "app") {
|
|
98
|
+
return srcExists ? "src/app" : "app";
|
|
95
99
|
}
|
|
96
|
-
else if (projectInfo.router ===
|
|
97
|
-
return srcExists ?
|
|
100
|
+
else if (projectInfo.router === "pages") {
|
|
101
|
+
return srcExists ? "src/pages" : "pages";
|
|
98
102
|
}
|
|
99
|
-
throw new Error(
|
|
103
|
+
throw new Error("Unknown router type");
|
|
100
104
|
}
|
|
101
105
|
function getLibPath(projectInfo) {
|
|
102
|
-
if (projectInfo.framework ===
|
|
103
|
-
return
|
|
106
|
+
if (projectInfo.framework === "express") {
|
|
107
|
+
return "src/lib";
|
|
104
108
|
}
|
|
105
|
-
const srcExists = fs_extra_1.default.existsSync(path_1.default.join(projectInfo.rootDir,
|
|
106
|
-
return srcExists ?
|
|
109
|
+
const srcExists = fs_extra_1.default.existsSync(path_1.default.join(projectInfo.rootDir, "src"));
|
|
110
|
+
return srcExists ? "src/lib" : "lib";
|
|
107
111
|
}
|
package/dist/utils/env-editor.js
CHANGED
|
@@ -8,28 +8,28 @@ exports.removeEnvVariables = removeEnvVariables;
|
|
|
8
8
|
const fs_extra_1 = __importDefault(require("fs-extra"));
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
10
|
const logger_1 = require("./logger");
|
|
11
|
-
const ENV_MARKER_START =
|
|
12
|
-
const ENV_MARKER_END =
|
|
11
|
+
const ENV_MARKER_START = "# StackKit:";
|
|
12
|
+
const ENV_MARKER_END = "# End StackKit";
|
|
13
13
|
async function addEnvVariables(projectRoot, variables, options = {}) {
|
|
14
|
-
const envExamplePath = path_1.default.join(projectRoot,
|
|
15
|
-
const envPath = path_1.default.join(projectRoot,
|
|
14
|
+
const envExamplePath = path_1.default.join(projectRoot, ".env.example");
|
|
15
|
+
const envPath = path_1.default.join(projectRoot, ".env");
|
|
16
16
|
// Add to .env.example
|
|
17
|
-
await appendToEnvFile(envExamplePath, variables,
|
|
17
|
+
await appendToEnvFile(envExamplePath, variables, "example", options);
|
|
18
18
|
// Add to .env if it exists or create it
|
|
19
19
|
const envExists = await fs_extra_1.default.pathExists(envPath);
|
|
20
20
|
if (envExists || options.force) {
|
|
21
|
-
await appendToEnvFile(envPath, variables,
|
|
21
|
+
await appendToEnvFile(envPath, variables, "local", options);
|
|
22
22
|
}
|
|
23
|
-
logger_1.logger.success(
|
|
23
|
+
logger_1.logger.success("Environment variables added");
|
|
24
24
|
}
|
|
25
25
|
async function appendToEnvFile(filePath, variables, fileType, options = {}) {
|
|
26
|
-
let content =
|
|
26
|
+
let content = "";
|
|
27
27
|
if (await fs_extra_1.default.pathExists(filePath)) {
|
|
28
|
-
content = await fs_extra_1.default.readFile(filePath,
|
|
28
|
+
content = await fs_extra_1.default.readFile(filePath, "utf-8");
|
|
29
29
|
}
|
|
30
30
|
// Check if variables already exist
|
|
31
31
|
const existingKeys = new Set();
|
|
32
|
-
const lines = content.split(
|
|
32
|
+
const lines = content.split("\n");
|
|
33
33
|
for (const line of lines) {
|
|
34
34
|
const match = line.match(/^([A-Z_][A-Z0-9_]*)=/);
|
|
35
35
|
if (match) {
|
|
@@ -49,25 +49,25 @@ async function appendToEnvFile(filePath, variables, fileType, options = {}) {
|
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
51
51
|
// Ensure file ends with newline
|
|
52
|
-
if (content && !content.endsWith(
|
|
53
|
-
content +=
|
|
52
|
+
if (content && !content.endsWith("\n")) {
|
|
53
|
+
content += "\n";
|
|
54
54
|
}
|
|
55
55
|
// Add marker and variables
|
|
56
|
-
content +=
|
|
56
|
+
content += "\n";
|
|
57
57
|
content += `${ENV_MARKER_START} Added by StackKit\n`;
|
|
58
58
|
for (const variable of newVariables) {
|
|
59
59
|
if (variable.description) {
|
|
60
60
|
content += `# ${variable.description}\n`;
|
|
61
61
|
}
|
|
62
|
-
const value = fileType ===
|
|
62
|
+
const value = fileType === "example" ? variable.value || "" : variable.value || "";
|
|
63
63
|
content += `${variable.key}=${value}\n`;
|
|
64
64
|
}
|
|
65
65
|
content += `${ENV_MARKER_END}\n`;
|
|
66
|
-
await fs_extra_1.default.writeFile(filePath, content,
|
|
66
|
+
await fs_extra_1.default.writeFile(filePath, content, "utf-8");
|
|
67
67
|
}
|
|
68
68
|
async function removeEnvVariables(projectRoot, keys) {
|
|
69
|
-
const envExamplePath = path_1.default.join(projectRoot,
|
|
70
|
-
const envPath = path_1.default.join(projectRoot,
|
|
69
|
+
const envExamplePath = path_1.default.join(projectRoot, ".env.example");
|
|
70
|
+
const envPath = path_1.default.join(projectRoot, ".env");
|
|
71
71
|
await removeFromEnvFile(envExamplePath, keys);
|
|
72
72
|
if (await fs_extra_1.default.pathExists(envPath)) {
|
|
73
73
|
await removeFromEnvFile(envPath, keys);
|
|
@@ -77,8 +77,8 @@ async function removeFromEnvFile(filePath, keys) {
|
|
|
77
77
|
if (!(await fs_extra_1.default.pathExists(filePath))) {
|
|
78
78
|
return;
|
|
79
79
|
}
|
|
80
|
-
|
|
81
|
-
const lines = content.split(
|
|
80
|
+
const content = await fs_extra_1.default.readFile(filePath, "utf-8");
|
|
81
|
+
const lines = content.split("\n");
|
|
82
82
|
const newLines = [];
|
|
83
83
|
for (const line of lines) {
|
|
84
84
|
const match = line.match(/^([A-Z_][A-Z0-9_]*)=/);
|
|
@@ -87,5 +87,5 @@ async function removeFromEnvFile(filePath, keys) {
|
|
|
87
87
|
}
|
|
88
88
|
newLines.push(line);
|
|
89
89
|
}
|
|
90
|
-
await fs_extra_1.default.writeFile(filePath, newLines.join(
|
|
90
|
+
await fs_extra_1.default.writeFile(filePath, newLines.join("\n"), "utf-8");
|
|
91
91
|
}
|
package/dist/utils/files.js
CHANGED
|
@@ -21,11 +21,11 @@ async function copyTemplate(templatePath, targetPath, projectName) {
|
|
|
21
21
|
filter: (src) => {
|
|
22
22
|
const basename = path_1.default.basename(src);
|
|
23
23
|
// Skip template.json metadata file and node_modules
|
|
24
|
-
return basename !==
|
|
24
|
+
return basename !== "template.json" && basename !== "node_modules";
|
|
25
25
|
},
|
|
26
26
|
});
|
|
27
27
|
// Update package.json with project name
|
|
28
|
-
const packageJsonPath = path_1.default.join(targetPath,
|
|
28
|
+
const packageJsonPath = path_1.default.join(targetPath, "package.json");
|
|
29
29
|
if (await fs_extra_1.default.pathExists(packageJsonPath)) {
|
|
30
30
|
const packageJson = await fs_extra_1.default.readJSON(packageJsonPath);
|
|
31
31
|
packageJson.name = projectName;
|
|
@@ -40,10 +40,10 @@ async function createFile(targetPath, content, options = {}) {
|
|
|
40
40
|
return;
|
|
41
41
|
}
|
|
42
42
|
await fs_extra_1.default.ensureDir(path_1.default.dirname(targetPath));
|
|
43
|
-
await fs_extra_1.default.writeFile(targetPath, content,
|
|
43
|
+
await fs_extra_1.default.writeFile(targetPath, content, "utf-8");
|
|
44
44
|
}
|
|
45
45
|
async function readFile(filePath) {
|
|
46
|
-
return fs_extra_1.default.readFile(filePath,
|
|
46
|
+
return fs_extra_1.default.readFile(filePath, "utf-8");
|
|
47
47
|
}
|
|
48
48
|
async function fileExists(filePath) {
|
|
49
49
|
return fs_extra_1.default.pathExists(filePath);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
export declare function modifyJson(filePath: string, modifier: (
|
|
1
|
+
export declare function modifyJson(filePath: string, modifier: (_json: Record<string, unknown>) => Record<string, unknown>, options?: {
|
|
2
2
|
create?: boolean;
|
|
3
3
|
force?: boolean;
|
|
4
4
|
}): Promise<void>;
|
|
5
|
-
export declare function addToPackageJson(filePath: string, section:
|
|
6
|
-
export declare function setJsonValue(filePath: string, path: string, value:
|
|
5
|
+
export declare function addToPackageJson(filePath: string, section: "dependencies" | "devDependencies" | "scripts", additions: Record<string, string>): Promise<void>;
|
|
6
|
+
export declare function setJsonValue(filePath: string, path: string, value: unknown, options?: {
|
|
7
7
|
merge?: boolean;
|
|
8
8
|
}): Promise<void>;
|
|
@@ -12,24 +12,20 @@ async function modifyJson(filePath, modifier, options = {}) {
|
|
|
12
12
|
if (!exists && !options.create) {
|
|
13
13
|
throw new Error(`File not found: ${filePath}`);
|
|
14
14
|
}
|
|
15
|
-
|
|
16
|
-
if (exists) {
|
|
17
|
-
json = await fs_extra_1.default.readJSON(filePath);
|
|
18
|
-
}
|
|
19
|
-
const modified = modifier(json);
|
|
15
|
+
const modified = modifier(exists ? await fs_extra_1.default.readJSON(filePath) : {});
|
|
20
16
|
await fs_extra_1.default.writeJSON(filePath, modified, { spaces: 2 });
|
|
21
17
|
}
|
|
22
18
|
async function addToPackageJson(filePath, section, additions) {
|
|
23
|
-
await modifyJson(filePath, (
|
|
24
|
-
|
|
25
|
-
Object.assign(
|
|
26
|
-
return
|
|
19
|
+
await modifyJson(filePath, (_json) => {
|
|
20
|
+
_json[section] = _json[section] || {};
|
|
21
|
+
Object.assign(_json[section], additions);
|
|
22
|
+
return _json;
|
|
27
23
|
});
|
|
28
24
|
}
|
|
29
25
|
async function setJsonValue(filePath, path, value, options = {}) {
|
|
30
|
-
await modifyJson(filePath, (
|
|
31
|
-
const keys = path.split(
|
|
32
|
-
let current =
|
|
26
|
+
await modifyJson(filePath, (_json) => {
|
|
27
|
+
const keys = path.split(".");
|
|
28
|
+
let current = _json;
|
|
33
29
|
for (let i = 0; i < keys.length - 1; i++) {
|
|
34
30
|
const key = keys[i];
|
|
35
31
|
if (!current[key]) {
|
|
@@ -38,12 +34,12 @@ async function setJsonValue(filePath, path, value, options = {}) {
|
|
|
38
34
|
current = current[key];
|
|
39
35
|
}
|
|
40
36
|
const lastKey = keys[keys.length - 1];
|
|
41
|
-
if (options.merge && typeof current[lastKey] ===
|
|
37
|
+
if (options.merge && typeof current[lastKey] === "object" && typeof value === "object") {
|
|
42
38
|
current[lastKey] = { ...current[lastKey], ...value };
|
|
43
39
|
}
|
|
44
40
|
else {
|
|
45
41
|
current[lastKey] = value;
|
|
46
42
|
}
|
|
47
|
-
return
|
|
43
|
+
return _json;
|
|
48
44
|
});
|
|
49
45
|
}
|
package/dist/utils/logger.d.ts
CHANGED
package/dist/utils/logger.js
CHANGED
|
@@ -11,22 +11,22 @@ class Logger {
|
|
|
11
11
|
this.spinner = null;
|
|
12
12
|
}
|
|
13
13
|
info(message) {
|
|
14
|
-
|
|
14
|
+
process.stdout.write(chalk_1.default.blue("ℹ") + " " + message + "\n");
|
|
15
15
|
}
|
|
16
16
|
success(message) {
|
|
17
|
-
|
|
17
|
+
process.stdout.write(chalk_1.default.green("✔") + " " + message + "\n");
|
|
18
18
|
}
|
|
19
19
|
error(message) {
|
|
20
|
-
|
|
20
|
+
process.stderr.write(chalk_1.default.red("✖") + " " + message + "\n");
|
|
21
21
|
}
|
|
22
22
|
warn(message) {
|
|
23
|
-
|
|
23
|
+
process.stdout.write(chalk_1.default.yellow("⚠") + " " + message + "\n");
|
|
24
24
|
}
|
|
25
25
|
log(message) {
|
|
26
|
-
|
|
26
|
+
process.stdout.write(message + "\n");
|
|
27
27
|
}
|
|
28
28
|
newLine() {
|
|
29
|
-
|
|
29
|
+
process.stdout.write("\n");
|
|
30
30
|
}
|
|
31
31
|
startSpinner(text) {
|
|
32
32
|
this.spinner = (0, ora_1.default)(text).start();
|
|
@@ -49,10 +49,10 @@ class Logger {
|
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
header(text) {
|
|
52
|
-
|
|
52
|
+
process.stdout.write(chalk_1.default.bold.cyan(text) + "\n");
|
|
53
53
|
}
|
|
54
54
|
footer() {
|
|
55
|
-
|
|
55
|
+
process.stdout.write("\n");
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
exports.Logger = Logger;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export type PackageManager =
|
|
1
|
+
export type PackageManager = "npm" | "yarn" | "pnpm" | "bun";
|
|
2
2
|
export declare function detectPackageManager(cwd: string): Promise<PackageManager>;
|
|
3
|
-
export declare function installDependencies(cwd: string, pm: PackageManager
|
|
3
|
+
export declare function installDependencies(cwd: string, pm: PackageManager): Promise<void>;
|
|
4
4
|
export declare function addDependencies(cwd: string, pm: PackageManager, packages: string[], dev?: boolean): Promise<void>;
|
|
5
5
|
export declare function initGit(cwd: string): Promise<void>;
|
|
@@ -16,63 +16,70 @@ async function detectPackageManager(cwd) {
|
|
|
16
16
|
return pm;
|
|
17
17
|
}
|
|
18
18
|
catch {
|
|
19
|
-
return
|
|
19
|
+
return "npm";
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
|
-
async function installDependencies(cwd, pm
|
|
22
|
+
async function installDependencies(cwd, pm) {
|
|
23
23
|
const spinner = logger_1.logger.startSpinner(`Installing dependencies with ${pm}...`);
|
|
24
24
|
try {
|
|
25
25
|
const args = [];
|
|
26
|
-
if (pm ===
|
|
27
|
-
args.push(
|
|
26
|
+
if (pm === "npm") {
|
|
27
|
+
args.push("install");
|
|
28
28
|
}
|
|
29
|
-
else if (pm ===
|
|
30
|
-
args.push(
|
|
29
|
+
else if (pm === "yarn") {
|
|
30
|
+
args.push("install");
|
|
31
31
|
}
|
|
32
|
-
else if (pm ===
|
|
33
|
-
args.push(
|
|
32
|
+
else if (pm === "pnpm") {
|
|
33
|
+
args.push("install");
|
|
34
34
|
}
|
|
35
|
-
|
|
35
|
+
else if (pm === "bun") {
|
|
36
|
+
args.push("install");
|
|
37
|
+
}
|
|
38
|
+
await (0, execa_1.default)(pm, args, { cwd, stdio: "pipe" });
|
|
36
39
|
spinner.succeed(`Dependencies installed successfully`);
|
|
37
40
|
}
|
|
38
41
|
catch (error) {
|
|
39
42
|
spinner.fail(`Failed to install dependencies`);
|
|
40
|
-
throw error;
|
|
43
|
+
throw new Error(`Failed to install dependencies: ${error}`);
|
|
41
44
|
}
|
|
42
45
|
}
|
|
43
46
|
async function addDependencies(cwd, pm, packages, dev = false) {
|
|
44
47
|
if (packages.length === 0)
|
|
45
48
|
return;
|
|
46
|
-
const spinner = logger_1.logger.startSpinner(`Adding ${dev ?
|
|
49
|
+
const spinner = logger_1.logger.startSpinner(`Adding ${dev ? "dev " : ""}dependencies: ${packages.join(", ")}...`);
|
|
47
50
|
try {
|
|
48
51
|
const args = [];
|
|
49
|
-
if (pm ===
|
|
50
|
-
args.push(
|
|
52
|
+
if (pm === "npm") {
|
|
53
|
+
args.push("install", dev ? "--save-dev" : "--save", ...packages);
|
|
54
|
+
}
|
|
55
|
+
else if (pm === "yarn") {
|
|
56
|
+
args.push("add", dev ? "--dev" : "", ...packages);
|
|
51
57
|
}
|
|
52
|
-
else if (pm ===
|
|
53
|
-
args.push(
|
|
58
|
+
else if (pm === "pnpm") {
|
|
59
|
+
args.push("add", dev ? "-D" : "", ...packages);
|
|
54
60
|
}
|
|
55
|
-
else if (pm ===
|
|
56
|
-
|
|
61
|
+
else if (pm === "bun") {
|
|
62
|
+
// bun uses `bun add` and `-d` for dev dependencies
|
|
63
|
+
args.push("add", ...(dev ? ["-d"] : []), ...packages);
|
|
57
64
|
}
|
|
58
|
-
await (0, execa_1.default)(pm, args.filter(Boolean), { cwd, stdio:
|
|
65
|
+
await (0, execa_1.default)(pm, args.filter(Boolean), { cwd, stdio: "pipe" });
|
|
59
66
|
spinner.succeed(`Dependencies added successfully`);
|
|
60
67
|
}
|
|
61
68
|
catch (error) {
|
|
62
69
|
spinner.fail(`Failed to add dependencies`);
|
|
63
|
-
throw error;
|
|
70
|
+
throw new Error(`Failed to add dependencies: ${error}`); // error is used here
|
|
64
71
|
}
|
|
65
72
|
}
|
|
66
73
|
async function initGit(cwd) {
|
|
67
|
-
const spinner = logger_1.logger.startSpinner(
|
|
74
|
+
const spinner = logger_1.logger.startSpinner("Initializing git repository...");
|
|
68
75
|
try {
|
|
69
|
-
await (0, execa_1.default)(
|
|
70
|
-
await (0, execa_1.default)(
|
|
71
|
-
await (0, execa_1.default)(
|
|
72
|
-
spinner.succeed(
|
|
76
|
+
await (0, execa_1.default)("git", ["init"], { cwd });
|
|
77
|
+
await (0, execa_1.default)("git", ["add", "."], { cwd });
|
|
78
|
+
await (0, execa_1.default)("git", ["commit", "-m", "Initial commit from StackKit"], { cwd });
|
|
79
|
+
spinner.succeed("Git repository initialized");
|
|
73
80
|
}
|
|
74
|
-
catch
|
|
75
|
-
spinner.fail(
|
|
81
|
+
catch {
|
|
82
|
+
spinner.fail("Failed to initialize git repository");
|
|
76
83
|
// Don't throw - git init is optional
|
|
77
84
|
}
|
|
78
85
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { betterAuth } from "better-auth";
|
|
2
|
+
import { mongodbAdapter } from "better-auth/adapters/mongodb";
|
|
3
|
+
import { client } from "./db";
|
|
4
|
+
|
|
5
|
+
export const auth = betterAuth({
|
|
6
|
+
database: mongodbAdapter(client),
|
|
7
|
+
emailAndPassword: {
|
|
8
|
+
enabled: true,
|
|
9
|
+
},
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export type Session = typeof auth.$Infer.Session;
|
|
13
|
+
export type User = typeof auth.$Infer.User;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { prismaAdapter } from "@better-auth/prisma";
|
|
2
|
+
import { betterAuth } from "better-auth";
|
|
3
|
+
import { prisma } from "./db";
|
|
4
|
+
|
|
5
|
+
export const auth = betterAuth({
|
|
6
|
+
database: prismaAdapter(prisma, {
|
|
7
|
+
provider: "mongodb",
|
|
8
|
+
}),
|
|
9
|
+
emailAndPassword: {
|
|
10
|
+
enabled: true,
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export type Session = typeof auth.$Infer.Session;
|
|
15
|
+
export type User = typeof auth.$Infer.User;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { prismaAdapter } from "@better-auth/prisma";
|
|
2
|
+
import { betterAuth } from "better-auth";
|
|
3
|
+
import { prisma } from "./db";
|
|
4
|
+
|
|
5
|
+
export const auth = betterAuth({
|
|
6
|
+
database: prismaAdapter(prisma, {
|
|
7
|
+
provider: "postgresql",
|
|
8
|
+
}),
|
|
9
|
+
emailAndPassword: {
|
|
10
|
+
enabled: true,
|
|
11
|
+
},
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export type Session = typeof auth.$Infer.Session;
|
|
15
|
+
export type User = typeof auth.$Infer.User;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { Router } from
|
|
2
|
-
import { auth } from
|
|
1
|
+
import { Router } from "express";
|
|
2
|
+
import { auth } from "../lib/auth";
|
|
3
3
|
|
|
4
4
|
const router = Router();
|
|
5
5
|
|
|
6
6
|
// Mount Better Auth handlers
|
|
7
|
-
router.all(
|
|
7
|
+
router.all("/auth/*", async (req, res) => {
|
|
8
8
|
const response = await auth.handler(req);
|
|
9
9
|
return res.status(response.status).json(response.body);
|
|
10
10
|
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
generator client {
|
|
2
|
+
provider = "prisma-client-js"
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
datasource db {
|
|
6
|
+
provider = "mongodb"
|
|
7
|
+
url = env("DATABASE_URL")
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Better Auth models for MongoDB
|
|
11
|
+
model User {
|
|
12
|
+
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
13
|
+
name String
|
|
14
|
+
email String
|
|
15
|
+
emailVerified Boolean @default(false)
|
|
16
|
+
image String?
|
|
17
|
+
createdAt DateTime @default(now())
|
|
18
|
+
updatedAt DateTime @updatedAt
|
|
19
|
+
sessions Session[]
|
|
20
|
+
accounts Account[]
|
|
21
|
+
role String @default("USER")
|
|
22
|
+
|
|
23
|
+
@@unique([email])
|
|
24
|
+
@@map("user")
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
model Session {
|
|
28
|
+
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
29
|
+
expiresAt DateTime
|
|
30
|
+
token String @unique
|
|
31
|
+
createdAt DateTime @default(now())
|
|
32
|
+
updatedAt DateTime @updatedAt
|
|
33
|
+
ipAddress String?
|
|
34
|
+
userAgent String?
|
|
35
|
+
userId String @db.ObjectId
|
|
36
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
37
|
+
|
|
38
|
+
@@index([userId])
|
|
39
|
+
@@map("session")
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
model Account {
|
|
43
|
+
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
44
|
+
accountId String
|
|
45
|
+
providerId String
|
|
46
|
+
userId String @db.ObjectId
|
|
47
|
+
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
48
|
+
accessToken String?
|
|
49
|
+
refreshToken String?
|
|
50
|
+
idToken String?
|
|
51
|
+
accessTokenExpiresAt DateTime?
|
|
52
|
+
refreshTokenExpiresAt DateTime?
|
|
53
|
+
scope String?
|
|
54
|
+
password String?
|
|
55
|
+
createdAt DateTime @default(now())
|
|
56
|
+
updatedAt DateTime @updatedAt
|
|
57
|
+
|
|
58
|
+
@@index([userId])
|
|
59
|
+
@@map("account")
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
model Verification {
|
|
63
|
+
id String @id @default(auto()) @map("_id") @db.ObjectId
|
|
64
|
+
identifier String
|
|
65
|
+
value String
|
|
66
|
+
expiresAt DateTime
|
|
67
|
+
createdAt DateTime @default(now())
|
|
68
|
+
updatedAt DateTime @updatedAt
|
|
69
|
+
|
|
70
|
+
@@index([identifier])
|
|
71
|
+
@@map("verification")
|
|
72
|
+
}
|