stackkit-cli 0.4.1 → 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.
Files changed (133) hide show
  1. package/README.md +17 -10
  2. package/bin/stackkit.js +1 -1
  3. package/dist/commands/add.js +26 -24
  4. package/dist/commands/init.d.ts +1 -1
  5. package/dist/commands/init.js +34 -29
  6. package/dist/commands/list.js +20 -17
  7. package/dist/index.js +25 -23
  8. package/dist/types/index.d.ts +14 -14
  9. package/dist/utils/code-inject.d.ts +1 -1
  10. package/dist/utils/code-inject.js +6 -6
  11. package/dist/utils/detect.d.ts +1 -1
  12. package/dist/utils/detect.js +48 -44
  13. package/dist/utils/env-editor.js +20 -20
  14. package/dist/utils/files.js +4 -4
  15. package/dist/utils/json-editor.d.ts +3 -3
  16. package/dist/utils/json-editor.js +10 -14
  17. package/dist/utils/logger.d.ts +1 -1
  18. package/dist/utils/logger.js +8 -8
  19. package/dist/utils/package-manager.d.ts +2 -2
  20. package/dist/utils/package-manager.js +33 -26
  21. package/modules/auth/better-auth-express/adapters/mongoose-mongodb.ts +13 -0
  22. package/modules/auth/better-auth-express/adapters/prisma-mongodb.ts +15 -0
  23. package/modules/auth/better-auth-express/adapters/prisma-postgresql.ts +15 -0
  24. package/modules/auth/better-auth-express/files/lib/auth.ts +1 -1
  25. package/modules/auth/better-auth-express/files/routes/auth.ts +3 -3
  26. package/modules/auth/better-auth-express/files/schemas/prisma-mongodb-schema.prisma +72 -0
  27. package/modules/auth/better-auth-express/files/schemas/prisma-postgresql-schema.prisma +72 -0
  28. package/modules/auth/better-auth-express/module.json +26 -3
  29. package/modules/auth/better-auth-nextjs/adapters/mongoose-mongodb.ts +24 -0
  30. package/modules/auth/better-auth-nextjs/adapters/prisma-mongodb.ts +26 -0
  31. package/modules/auth/better-auth-nextjs/adapters/prisma-postgresql.ts +26 -0
  32. package/modules/auth/better-auth-nextjs/files/api/auth/[...all]/route.ts +2 -3
  33. package/modules/auth/better-auth-nextjs/files/lib/auth.ts +4 -4
  34. package/modules/auth/better-auth-nextjs/files/schemas/prisma-mongodb-schema.prisma +72 -0
  35. package/modules/auth/better-auth-nextjs/files/schemas/prisma-postgresql-schema.prisma +72 -0
  36. package/modules/auth/better-auth-nextjs/module.json +26 -5
  37. package/modules/auth/better-auth-react/files/lib/auth-client.ts +2 -2
  38. package/modules/auth/better-auth-react/module.json +7 -5
  39. package/modules/auth/clerk-express/files/lib/auth.ts +1 -1
  40. package/modules/auth/clerk-express/module.json +23 -8
  41. package/modules/auth/clerk-nextjs/files/lib/auth-provider.tsx +1 -1
  42. package/modules/auth/clerk-nextjs/files/middleware.ts +3 -3
  43. package/modules/auth/clerk-nextjs/module.json +51 -14
  44. package/modules/auth/clerk-react/files/lib/auth-provider.tsx +2 -2
  45. package/modules/auth/clerk-react/module.json +17 -7
  46. package/modules/database/mongoose-mongodb/files/lib/db.ts +3 -3
  47. package/modules/database/mongoose-mongodb/module.json +44 -6
  48. package/modules/database/prisma-mongodb/files/lib/db.ts +2 -2
  49. package/modules/database/prisma-mongodb/files/prisma/schema.prisma +1 -1
  50. package/modules/database/prisma-mongodb/module.json +28 -4
  51. package/modules/database/prisma-postgresql/files/lib/db.ts +2 -2
  52. package/modules/database/prisma-postgresql/files/prisma/schema.prisma +1 -1
  53. package/modules/database/prisma-postgresql/module.json +28 -4
  54. package/package.json +1 -1
  55. package/templates/express/.env.example +11 -0
  56. package/templates/express/eslint.config.cjs +42 -0
  57. package/templates/express/package.json +39 -0
  58. package/templates/express/src/app.ts +71 -0
  59. package/templates/express/src/config/env.ts +23 -0
  60. package/templates/express/src/middlewares/error.middleware.ts +18 -0
  61. package/templates/{bases/express-base → express}/src/server.ts +2 -2
  62. package/templates/express/template.json +44 -0
  63. package/templates/express/tsconfig.json +31 -0
  64. package/templates/{bases/nextjs-base → nextjs}/app/layout.tsx +1 -5
  65. package/templates/nextjs/app/page.tsx +57 -0
  66. package/templates/{bases/nextjs-base → nextjs}/package.json +2 -1
  67. package/templates/{bases/nextjs-base → nextjs}/template.json +13 -1
  68. package/templates/react-vite/.env.example +2 -0
  69. package/templates/react-vite/README.md +85 -0
  70. package/templates/react-vite/eslint.config.js +23 -0
  71. package/templates/{bases/react-vite-base → react-vite}/index.html +1 -0
  72. package/templates/{bases/react-vite-base → react-vite}/package.json +16 -2
  73. package/templates/react-vite/src/api/client.ts +47 -0
  74. package/templates/react-vite/src/api/services/user.service.ts +18 -0
  75. package/templates/react-vite/src/components/ErrorBoundary.tsx +51 -0
  76. package/templates/react-vite/src/components/Layout.tsx +13 -0
  77. package/templates/react-vite/src/components/Loading.tsx +8 -0
  78. package/templates/react-vite/src/components/SEO.tsx +49 -0
  79. package/templates/react-vite/src/config/constants.ts +5 -0
  80. package/templates/react-vite/src/hooks/index.ts +64 -0
  81. package/templates/react-vite/src/index.css +1 -0
  82. package/templates/react-vite/src/lib/queryClient.ts +12 -0
  83. package/templates/react-vite/src/main.tsx +22 -0
  84. package/templates/react-vite/src/pages/About.tsx +78 -0
  85. package/templates/react-vite/src/pages/Home.tsx +49 -0
  86. package/templates/react-vite/src/pages/NotFound.tsx +24 -0
  87. package/templates/react-vite/src/pages/UserProfile.tsx +40 -0
  88. package/templates/react-vite/src/router.tsx +33 -0
  89. package/templates/react-vite/src/types/api.d.ts +20 -0
  90. package/templates/react-vite/src/types/user.d.ts +6 -0
  91. package/templates/react-vite/src/utils/helpers.ts +51 -0
  92. package/templates/react-vite/src/utils/storage.ts +35 -0
  93. package/templates/react-vite/src/vite-env.d.ts +11 -0
  94. package/templates/react-vite/template.json +46 -0
  95. package/templates/react-vite/tsconfig.json +4 -0
  96. package/templates/react-vite/vite.config.ts +13 -0
  97. package/modules/database/drizzle-postgresql/files/drizzle.config.ts +0 -10
  98. package/modules/database/drizzle-postgresql/files/lib/db.ts +0 -7
  99. package/modules/database/drizzle-postgresql/files/lib/schema.ts +0 -8
  100. package/modules/database/drizzle-postgresql/module.json +0 -34
  101. package/templates/bases/express-base/.env.example +0 -2
  102. package/templates/bases/express-base/package.json +0 -23
  103. package/templates/bases/express-base/src/app.ts +0 -34
  104. package/templates/bases/express-base/src/config/env.ts +0 -14
  105. package/templates/bases/express-base/src/middlewares/error.middleware.ts +0 -12
  106. package/templates/bases/express-base/template.json +0 -7
  107. package/templates/bases/express-base/tsconfig.json +0 -14
  108. package/templates/bases/nextjs-base/app/page.tsx +0 -65
  109. package/templates/bases/react-vite-base/README.md +0 -73
  110. package/templates/bases/react-vite-base/eslint.config.js +0 -23
  111. package/templates/bases/react-vite-base/src/App.css +0 -42
  112. package/templates/bases/react-vite-base/src/App.tsx +0 -35
  113. package/templates/bases/react-vite-base/src/index.css +0 -68
  114. package/templates/bases/react-vite-base/src/main.tsx +0 -10
  115. package/templates/bases/react-vite-base/template.json +0 -19
  116. package/templates/bases/react-vite-base/tsconfig.json +0 -7
  117. package/templates/bases/react-vite-base/vite.config.ts +0 -7
  118. /package/templates/{bases/nextjs-base → nextjs}/README.md +0 -0
  119. /package/templates/{bases/nextjs-base → nextjs}/app/favicon.ico +0 -0
  120. /package/templates/{bases/nextjs-base → nextjs}/app/globals.css +0 -0
  121. /package/templates/{bases/nextjs-base → nextjs}/eslint.config.mjs +0 -0
  122. /package/templates/{bases/nextjs-base → nextjs}/next.config.ts +0 -0
  123. /package/templates/{bases/nextjs-base → nextjs}/postcss.config.mjs +0 -0
  124. /package/templates/{bases/nextjs-base → nextjs}/public/file.svg +0 -0
  125. /package/templates/{bases/nextjs-base → nextjs}/public/globe.svg +0 -0
  126. /package/templates/{bases/nextjs-base → nextjs}/public/next.svg +0 -0
  127. /package/templates/{bases/nextjs-base → nextjs}/public/vercel.svg +0 -0
  128. /package/templates/{bases/nextjs-base → nextjs}/public/window.svg +0 -0
  129. /package/templates/{bases/nextjs-base → nextjs}/tsconfig.json +0 -0
  130. /package/templates/{bases/react-vite-base → react-vite}/public/vite.svg +0 -0
  131. /package/templates/{bases/react-vite-base → react-vite}/src/assets/react.svg +0 -0
  132. /package/templates/{bases/react-vite-base → react-vite}/tsconfig.app.json +0 -0
  133. /package/templates/{bases/react-vite-base → react-vite}/tsconfig.node.json +0 -0
@@ -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, 'package.json');
12
+ const packageJsonPath = path_1.default.join(targetDir, "package.json");
13
13
  if (!(await fs_extra_1.default.pathExists(packageJsonPath))) {
14
- throw new Error('No package.json found. This does not appear to be a Node.js project.');
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 = 'nextjs';
24
+ framework = "nextjs";
25
25
  }
26
26
  else if (isExpress) {
27
- framework = 'express';
27
+ framework = "express";
28
28
  }
29
29
  else if (isReact && isVite) {
30
- framework = 'react-vite';
30
+ framework = "react-vite";
31
31
  }
32
32
  else if (isReact) {
33
- framework = 'react';
33
+ framework = "react";
34
34
  }
35
35
  else {
36
- framework = 'unknown';
36
+ framework = "unknown";
37
37
  }
38
- if (framework === 'unknown') {
39
- throw new Error('Only Next.js, Express, and React projects are currently supported.');
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 = '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'));
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 = 'app';
49
+ router = "app";
50
50
  }
51
51
  else if (pagesDirExists || srcPagesDirExists) {
52
- router = 'pages';
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, 'tsconfig.json'));
57
- const language = tsconfigExists ? 'ts' : 'js';
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, 'yarn.lock'));
60
- const pnpmLockExists = await fs_extra_1.default.pathExists(path_1.default.join(targetDir, 'pnpm-lock.yaml'));
61
- let packageManager = 'npm';
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 = 'pnpm';
64
+ packageManager = "pnpm";
64
65
  }
65
66
  else if (yarnLockExists) {
66
- packageManager = 'yarn';
67
+ packageManager = "yarn";
68
+ }
69
+ else if (bunLockExists) {
70
+ packageManager = "bun";
67
71
  }
68
72
  // Check for existing integrations
69
- const hasAuth = !!(packageJson.dependencies?.['next-auth'] ||
70
- packageJson.dependencies?.['better-auth'] ||
71
- packageJson.dependencies?.['@auth/core'] ||
72
- packageJson.dependencies?.['@clerk/nextjs'] ||
73
- packageJson.dependencies?.['@kinde-oss/kinde-auth-nextjs'] ||
74
- packageJson.dependencies?.['passport']);
75
- const hasPrisma = !!(packageJson.dependencies?.['@prisma/client'] || packageJson.devDependencies?.['prisma']);
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?.['mongoose'] ||
78
- packageJson.dependencies?.['typeorm'] ||
79
- packageJson.dependencies?.['drizzle-orm']);
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, 'src'));
93
- if (projectInfo.router === 'app') {
94
- return srcExists ? 'src/app' : 'app';
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 === 'pages') {
97
- return srcExists ? 'src/pages' : 'pages';
100
+ else if (projectInfo.router === "pages") {
101
+ return srcExists ? "src/pages" : "pages";
98
102
  }
99
- throw new Error('Unknown router type');
103
+ throw new Error("Unknown router type");
100
104
  }
101
105
  function getLibPath(projectInfo) {
102
- if (projectInfo.framework === 'express') {
103
- return 'src/lib';
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, 'src'));
106
- return srcExists ? 'src/lib' : 'lib';
109
+ const srcExists = fs_extra_1.default.existsSync(path_1.default.join(projectInfo.rootDir, "src"));
110
+ return srcExists ? "src/lib" : "lib";
107
111
  }
@@ -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 = '# StackKit:';
12
- const ENV_MARKER_END = '# End StackKit';
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, '.env.example');
15
- const envPath = path_1.default.join(projectRoot, '.env');
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, 'example', options);
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, 'local', options);
21
+ await appendToEnvFile(envPath, variables, "local", options);
22
22
  }
23
- logger_1.logger.success('Environment variables added');
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, 'utf-8');
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('\n');
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('\n')) {
53
- content += '\n';
52
+ if (content && !content.endsWith("\n")) {
53
+ content += "\n";
54
54
  }
55
55
  // Add marker and variables
56
- content += '\n';
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 === 'example' ? variable.value || '' : variable.value || '';
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, 'utf-8');
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, '.env.example');
70
- const envPath = path_1.default.join(projectRoot, '.env');
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
- let content = await fs_extra_1.default.readFile(filePath, 'utf-8');
81
- const lines = content.split('\n');
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('\n'), 'utf-8');
90
+ await fs_extra_1.default.writeFile(filePath, newLines.join("\n"), "utf-8");
91
91
  }
@@ -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 !== 'template.json' && basename !== 'node_modules';
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, 'package.json');
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, 'utf-8');
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, 'utf-8');
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: (json: any) => any, options?: {
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: 'dependencies' | 'devDependencies' | 'scripts', additions: Record<string, string>): Promise<void>;
6
- export declare function setJsonValue(filePath: string, path: string, value: any, options?: {
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
- let json = {};
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, (json) => {
24
- json[section] = json[section] || {};
25
- Object.assign(json[section], additions);
26
- return json;
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, (json) => {
31
- const keys = path.split('.');
32
- let current = json;
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] === 'object' && typeof value === 'object') {
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 json;
43
+ return _json;
48
44
  });
49
45
  }
@@ -1,4 +1,4 @@
1
- import { Ora } from 'ora';
1
+ import { Ora } from "ora";
2
2
  export declare class Logger {
3
3
  private spinner;
4
4
  info(message: string): void;
@@ -11,22 +11,22 @@ class Logger {
11
11
  this.spinner = null;
12
12
  }
13
13
  info(message) {
14
- console.log(chalk_1.default.blue(''), message);
14
+ process.stdout.write(chalk_1.default.blue("") + " " + message + "\n");
15
15
  }
16
16
  success(message) {
17
- console.log(chalk_1.default.green(''), message);
17
+ process.stdout.write(chalk_1.default.green("") + " " + message + "\n");
18
18
  }
19
19
  error(message) {
20
- console.log(chalk_1.default.red(''), message);
20
+ process.stderr.write(chalk_1.default.red("") + " " + message + "\n");
21
21
  }
22
22
  warn(message) {
23
- console.log(chalk_1.default.yellow(''), message);
23
+ process.stdout.write(chalk_1.default.yellow("") + " " + message + "\n");
24
24
  }
25
25
  log(message) {
26
- console.log(message);
26
+ process.stdout.write(message + "\n");
27
27
  }
28
28
  newLine() {
29
- console.log();
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
- console.log(chalk_1.default.bold.cyan(text));
52
+ process.stdout.write(chalk_1.default.bold.cyan(text) + "\n");
53
53
  }
54
54
  footer() {
55
- console.log();
55
+ process.stdout.write("\n");
56
56
  }
57
57
  }
58
58
  exports.Logger = Logger;
@@ -1,5 +1,5 @@
1
- export type PackageManager = 'npm' | 'yarn' | 'pnpm';
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, dev?: boolean): Promise<void>;
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 'npm';
19
+ return "npm";
20
20
  }
21
21
  }
22
- async function installDependencies(cwd, pm, dev = false) {
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 === 'npm') {
27
- args.push('install');
26
+ if (pm === "npm") {
27
+ args.push("install");
28
28
  }
29
- else if (pm === 'yarn') {
30
- args.push('install');
29
+ else if (pm === "yarn") {
30
+ args.push("install");
31
31
  }
32
- else if (pm === 'pnpm') {
33
- args.push('install');
32
+ else if (pm === "pnpm") {
33
+ args.push("install");
34
34
  }
35
- await (0, execa_1.default)(pm, args, { cwd, stdio: 'pipe' });
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 ? 'dev ' : ''}dependencies: ${packages.join(', ')}...`);
49
+ const spinner = logger_1.logger.startSpinner(`Adding ${dev ? "dev " : ""}dependencies: ${packages.join(", ")}...`);
47
50
  try {
48
51
  const args = [];
49
- if (pm === 'npm') {
50
- args.push('install', dev ? '--save-dev' : '--save', ...packages);
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 === 'yarn') {
53
- args.push('add', dev ? '--dev' : '', ...packages);
58
+ else if (pm === "pnpm") {
59
+ args.push("add", dev ? "-D" : "", ...packages);
54
60
  }
55
- else if (pm === 'pnpm') {
56
- args.push('add', dev ? '-D' : '', ...packages);
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: 'pipe' });
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('Initializing git repository...');
74
+ const spinner = logger_1.logger.startSpinner("Initializing git repository...");
68
75
  try {
69
- await (0, execa_1.default)('git', ['init'], { cwd });
70
- await (0, execa_1.default)('git', ['add', '.'], { cwd });
71
- await (0, execa_1.default)('git', ['commit', '-m', 'Initial commit from StackKit'], { cwd });
72
- spinner.succeed('Git repository initialized');
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 (error) {
75
- spinner.fail('Failed to initialize git repository');
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,4 +1,4 @@
1
- import { betterAuth } from 'better-auth';
1
+ import { betterAuth } from "better-auth";
2
2
 
3
3
  export const auth = betterAuth({
4
4
  secret: process.env.BETTER_AUTH_SECRET!,
@@ -1,10 +1,10 @@
1
- import { Router } from 'express';
2
- import { auth } from '../lib/auth';
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('/auth/*', async (req, res) => {
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
+ }