stackkit 0.3.4 → 0.3.6

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 (203) hide show
  1. package/README.md +50 -42
  2. package/dist/cli/add.js +122 -56
  3. package/dist/cli/create.d.ts +2 -0
  4. package/dist/cli/create.js +271 -95
  5. package/dist/cli/doctor.js +1 -0
  6. package/dist/cli/list.d.ts +1 -1
  7. package/dist/cli/list.js +6 -4
  8. package/dist/index.js +234 -191
  9. package/dist/lib/constants.d.ts +4 -0
  10. package/dist/lib/constants.js +4 -0
  11. package/dist/lib/discovery/module-discovery.d.ts +4 -0
  12. package/dist/lib/discovery/module-discovery.js +56 -0
  13. package/dist/lib/generation/code-generator.d.ts +11 -2
  14. package/dist/lib/generation/code-generator.js +42 -3
  15. package/dist/lib/generation/generator-utils.js +3 -1
  16. package/dist/lib/pm/package-manager.js +16 -13
  17. package/dist/lib/ui/logger.js +3 -2
  18. package/dist/lib/utils/path-resolver.d.ts +2 -0
  19. package/dist/lib/utils/path-resolver.js +8 -0
  20. package/dist/meta.json +8312 -0
  21. package/modules/auth/better-auth/files/{shared → express}/config/env.ts +48 -52
  22. package/modules/auth/better-auth/files/express/middlewares/authorize.ts +20 -1
  23. package/modules/auth/better-auth/files/express/modules/auth.controller.ts +349 -0
  24. package/modules/auth/better-auth/files/express/modules/{auth/auth.route.ts → auth.route.ts} +12 -7
  25. package/modules/auth/better-auth/files/express/modules/auth.service.ts +664 -0
  26. package/modules/auth/better-auth/files/express/modules/{auth/auth.type.ts → auth.type.ts} +22 -9
  27. package/modules/auth/better-auth/files/{shared/mongoose/auth/constants.ts → express/mongo-modules/auth.constants.ts} +0 -1
  28. package/modules/auth/better-auth/files/{shared/mongoose/auth/helper.ts → express/mongo-modules/auth.helper.ts} +11 -1
  29. package/modules/auth/better-auth/files/express/types/express.d.ts +11 -0
  30. package/modules/auth/better-auth/files/nextjs/api-route.ts +74 -0
  31. package/modules/auth/better-auth/files/nextjs/dashboard/pages/(user)/page.tsx +6 -0
  32. package/modules/auth/better-auth/files/nextjs/dashboard/pages/admin/page.tsx +6 -0
  33. package/modules/auth/better-auth/files/nextjs/dashboard/pages/layout.tsx +48 -0
  34. package/modules/auth/better-auth/files/nextjs/dashboard/pages/my-profile/page.tsx +5 -0
  35. package/modules/auth/better-auth/files/nextjs/features/services/auth.service.ts +102 -0
  36. package/modules/auth/better-auth/files/nextjs/layout/layout.tsx +13 -0
  37. package/modules/auth/better-auth/files/nextjs/lib/axios/http.ts +158 -0
  38. package/modules/auth/better-auth/files/nextjs/lib/env.ts +35 -0
  39. package/modules/auth/better-auth/files/nextjs/lib/utils/auth.ts +75 -0
  40. package/modules/auth/better-auth/files/nextjs/lib/utils/cookie.ts +29 -0
  41. package/modules/auth/better-auth/files/nextjs/lib/utils/jwt.ts +28 -0
  42. package/modules/auth/better-auth/files/nextjs/lib/utils/token.ts +49 -0
  43. package/modules/auth/better-auth/files/nextjs/pages/forgot-password/page.tsx +5 -0
  44. package/modules/auth/better-auth/files/nextjs/pages/layout.tsx +11 -0
  45. package/modules/auth/better-auth/files/nextjs/pages/login/page.tsx +9 -0
  46. package/modules/auth/better-auth/files/nextjs/pages/register/page.tsx +5 -0
  47. package/modules/auth/better-auth/files/nextjs/pages/reset-password/page.tsx +10 -0
  48. package/modules/auth/better-auth/files/nextjs/pages/verify-email/page.tsx +10 -0
  49. package/modules/auth/better-auth/files/nextjs/proxy.ts +157 -22
  50. package/modules/auth/better-auth/files/nextjs/theme/providers/theme-provider.tsx +11 -0
  51. package/modules/auth/better-auth/files/nextjs/types/api.types.ts +18 -0
  52. package/modules/auth/better-auth/files/react/components/protected-route.tsx +39 -0
  53. package/modules/auth/better-auth/files/react/components/route-guards.tsx +13 -0
  54. package/modules/auth/better-auth/files/react/dashboard/admin/pages/overview.tsx +3 -0
  55. package/modules/auth/better-auth/files/react/dashboard/pages/overview.tsx +3 -0
  56. package/modules/auth/better-auth/files/react/features/pages/forgot-password.tsx +5 -0
  57. package/modules/auth/better-auth/files/react/features/pages/login.tsx +5 -0
  58. package/modules/auth/better-auth/files/react/features/pages/my-profile.tsx +5 -0
  59. package/modules/auth/better-auth/files/react/features/pages/oauth-callback.tsx +59 -0
  60. package/modules/auth/better-auth/files/react/features/pages/register.tsx +5 -0
  61. package/modules/auth/better-auth/files/react/features/pages/reset-password.tsx +10 -0
  62. package/modules/auth/better-auth/files/react/features/pages/verify-email.tsx +10 -0
  63. package/modules/auth/better-auth/files/react/layout/dashboard-layout.tsx +54 -0
  64. package/modules/auth/better-auth/files/react/lib/axios/http.ts +68 -0
  65. package/modules/auth/better-auth/files/react/lib/env.ts +25 -0
  66. package/modules/auth/better-auth/files/react/router.tsx +73 -0
  67. package/modules/auth/better-auth/files/react/theme/components/providers/theme-provider-context.ts +13 -0
  68. package/modules/auth/better-auth/files/react/theme/components/providers/theme-provider.tsx +51 -0
  69. package/modules/auth/better-auth/files/react/theme/hooks/use-theme.ts +8 -0
  70. package/modules/auth/better-auth/files/shared/features/components/change-password-dialog.tsx +113 -0
  71. package/modules/auth/better-auth/files/shared/features/components/forgot-password-form.tsx +84 -0
  72. package/modules/auth/better-auth/files/shared/features/components/login-form.tsx +134 -0
  73. package/modules/auth/better-auth/files/shared/features/components/my-profile.tsx +147 -0
  74. package/modules/auth/better-auth/files/shared/features/components/profile-form.tsx +205 -0
  75. package/modules/auth/better-auth/files/shared/features/components/register-form.tsx +100 -0
  76. package/modules/auth/better-auth/files/shared/features/components/reset-password-form.tsx +111 -0
  77. package/modules/auth/better-auth/files/shared/features/components/social-login-buttons.tsx +47 -0
  78. package/modules/auth/better-auth/files/shared/features/components/user-profile-menu.tsx +106 -0
  79. package/modules/auth/better-auth/files/shared/features/components/verify-email-form.tsx +110 -0
  80. package/modules/auth/better-auth/files/shared/features/queries/auth.mutations.tsx +312 -0
  81. package/modules/auth/better-auth/files/shared/features/queries/auth.querie.ts +19 -0
  82. package/modules/auth/better-auth/files/shared/features/services/auth.api.ts +81 -0
  83. package/modules/auth/better-auth/files/shared/features/types/auth.type.ts +47 -0
  84. package/modules/auth/better-auth/files/shared/features/validators/change-password.validator.ts +18 -0
  85. package/modules/auth/better-auth/files/shared/features/validators/forgot.validator.ts +7 -0
  86. package/modules/auth/better-auth/files/shared/features/validators/login.validator.ts +14 -0
  87. package/modules/auth/better-auth/files/shared/features/validators/profile.validator.ts +8 -0
  88. package/modules/auth/better-auth/files/shared/features/validators/register.validator.ts +9 -0
  89. package/modules/auth/better-auth/files/shared/features/validators/reset.validator.ts +9 -0
  90. package/modules/auth/better-auth/files/shared/features/validators/verify.validator.ts +8 -0
  91. package/modules/auth/better-auth/files/shared/lib/auth-client.ts +2 -1
  92. package/modules/auth/better-auth/files/shared/lib/auth.ts +10 -29
  93. package/modules/auth/better-auth/files/shared/lib/constant/dashboard.ts +90 -0
  94. package/modules/auth/better-auth/files/shared/prisma/enums.prisma +0 -1
  95. package/modules/auth/better-auth/files/shared/theme/mode-toggle.tsx +30 -0
  96. package/modules/auth/better-auth/files/shared/ui/shadcn/components/dashboard/dashboard-header.tsx +94 -0
  97. package/modules/auth/better-auth/files/shared/ui/shadcn/components/dashboard/dashboard-sidebar.tsx +255 -0
  98. package/modules/auth/better-auth/files/shared/ui/shadcn/components/footer.tsx +35 -0
  99. package/modules/auth/better-auth/files/shared/ui/shadcn/components/navbar.tsx +145 -0
  100. package/modules/auth/better-auth/files/shared/ui/shadcn/form-field/input-field.tsx +440 -0
  101. package/modules/auth/better-auth/files/shared/utils/email.ts +20 -18
  102. package/modules/auth/better-auth/generator.json +174 -53
  103. package/modules/auth/better-auth/module.json +2 -2
  104. package/modules/components/files/shared/hooks/use-file-upload.ts +412 -0
  105. package/modules/components/files/shared/lib/utils/url-helpers.ts +110 -0
  106. package/modules/components/files/shared/shadcn/dashboard/data-table-column-selector.tsx +52 -0
  107. package/modules/components/files/shared/shadcn/dashboard/data-table-footer.tsx +156 -0
  108. package/modules/components/files/shared/shadcn/dashboard/data-table.tsx +405 -0
  109. package/modules/components/files/shared/shadcn/global/form-field/input-field.tsx +440 -0
  110. package/modules/components/files/shared/shadcn/global/form-field/media-uploader-field.tsx +745 -0
  111. package/modules/components/files/shared/shadcn/global/form-field/multi-select-field.tsx +207 -0
  112. package/modules/components/files/shared/shadcn/global/form-field/select-field.tsx +247 -0
  113. package/modules/components/files/shared/shadcn/global/form-field/textarea-field.tsx +277 -0
  114. package/modules/components/files/shared/shadcn/global/form-field/tiptap-editor-field.tsx +35 -0
  115. package/modules/components/files/shared/shadcn/global/no-results.tsx +41 -0
  116. package/modules/components/files/shared/shadcn/tiptap-editor/editor-menu-bar.tsx +217 -0
  117. package/modules/components/files/shared/shadcn/tiptap-editor/tiptap-editor.tsx +104 -0
  118. package/modules/components/files/shared/url/load-more.tsx +93 -0
  119. package/modules/components/files/shared/url/search-bar.tsx +131 -0
  120. package/modules/components/files/shared/url/sort-select.tsx +118 -0
  121. package/modules/components/files/shared/url/url-tabs.tsx +77 -0
  122. package/modules/components/generator.json +109 -0
  123. package/modules/components/module.json +11 -0
  124. package/modules/database/mongoose/generator.json +3 -14
  125. package/modules/database/mongoose/module.json +2 -2
  126. package/modules/database/prisma/generator.json +6 -12
  127. package/modules/database/prisma/module.json +2 -2
  128. package/modules/storage/cloudinary/files/express/config/env.ts +65 -0
  129. package/modules/storage/cloudinary/files/express/config/media.ts +103 -0
  130. package/modules/storage/cloudinary/files/express/modules/media/media.controller.ts +59 -0
  131. package/modules/storage/cloudinary/files/express/modules/media/media.route.ts +29 -0
  132. package/modules/storage/cloudinary/files/express/modules/media/media.service.ts +113 -0
  133. package/modules/storage/cloudinary/files/express/modules/media/media.type.ts +32 -0
  134. package/modules/storage/cloudinary/generator.json +34 -0
  135. package/modules/storage/cloudinary/module.json +11 -0
  136. package/modules/ui/shadcn/generator.json +21 -0
  137. package/modules/ui/shadcn/module.json +11 -0
  138. package/package.json +24 -26
  139. package/templates/express/README.md +11 -16
  140. package/templates/express/src/config/env.ts +7 -5
  141. package/templates/nextjs/README.md +13 -18
  142. package/templates/nextjs/app/favicon.ico +0 -0
  143. package/templates/nextjs/app/layout.tsx +6 -4
  144. package/templates/nextjs/components/providers/query-provider.tsx +3 -0
  145. package/templates/nextjs/env.example +3 -1
  146. package/templates/nextjs/lib/axios/http.ts +23 -0
  147. package/templates/nextjs/lib/env.ts +7 -5
  148. package/templates/nextjs/package.json +2 -1
  149. package/templates/nextjs/template.json +1 -2
  150. package/templates/react/README.md +9 -14
  151. package/templates/react/index.html +1 -1
  152. package/templates/react/package.json +1 -1
  153. package/templates/react/src/assets/favicon.ico +0 -0
  154. package/templates/react/src/components/providers/query-provider.tsx +38 -0
  155. package/templates/react/src/{shared/components → components}/seo.tsx +4 -8
  156. package/templates/react/src/lib/axios/http.ts +24 -0
  157. package/templates/react/src/main.tsx +8 -11
  158. package/templates/react/src/{features/about/pages → pages}/about.tsx +1 -1
  159. package/templates/react/src/{features/home/pages → pages}/home.tsx +1 -1
  160. package/templates/react/src/router.tsx +6 -6
  161. package/templates/react/src/vite-env.d.ts +2 -1
  162. package/templates/react/template.json +0 -1
  163. package/templates/react/tsconfig.app.json +6 -0
  164. package/templates/react/tsconfig.json +7 -1
  165. package/templates/react/vite.config.ts +12 -0
  166. package/modules/auth/authjs/files/nextjs/api/auth/[...nextauth]/route.ts +0 -3
  167. package/modules/auth/authjs/files/nextjs/proxy.ts +0 -1
  168. package/modules/auth/authjs/files/shared/lib/auth.ts +0 -119
  169. package/modules/auth/authjs/files/shared/prisma/schema.prisma +0 -61
  170. package/modules/auth/authjs/generator.json +0 -64
  171. package/modules/auth/authjs/module.json +0 -13
  172. package/modules/auth/better-auth/files/express/modules/auth/auth.controller.ts +0 -264
  173. package/modules/auth/better-auth/files/express/modules/auth/auth.service.ts +0 -537
  174. package/modules/auth/better-auth/files/express/templates/google-redirect.ejs +0 -24
  175. package/modules/auth/better-auth/files/nextjs/api/auth/[...all]/route.ts +0 -4
  176. package/modules/auth/better-auth/files/nextjs/lib/auth/auth-guards.ts +0 -41
  177. package/modules/auth/better-auth/files/nextjs/templates/email-otp.tsx +0 -74
  178. package/templates/express/node_modules/.bin/acorn +0 -17
  179. package/templates/express/node_modules/.bin/eslint +0 -17
  180. package/templates/express/node_modules/.bin/tsc +0 -17
  181. package/templates/express/node_modules/.bin/tsserver +0 -17
  182. package/templates/express/node_modules/.bin/tsx +0 -17
  183. package/templates/nextjs/lib/api/http.ts +0 -40
  184. package/templates/nextjs/next-env.d.ts +0 -6
  185. package/templates/react/dist/assets/index-D4AHT4dU.js +0 -193
  186. package/templates/react/dist/assets/index-rpwj5ZOX.css +0 -1
  187. package/templates/react/dist/index.html +0 -14
  188. package/templates/react/dist/vite.svg +0 -1
  189. package/templates/react/public/vite.svg +0 -1
  190. package/templates/react/src/app/layouts/dashboard-layout.tsx +0 -8
  191. package/templates/react/src/app/layouts/public-layout.tsx +0 -5
  192. package/templates/react/src/app/providers.tsx +0 -20
  193. package/templates/react/src/app/router.tsx +0 -21
  194. package/templates/react/src/assets/react.svg +0 -1
  195. package/templates/react/src/shared/api/http.ts +0 -39
  196. package/templates/react/src/shared/components/loading.tsx +0 -8
  197. package/templates/react/src/shared/lib/query-client.ts +0 -12
  198. package/templates/react/src/utils/storage.ts +0 -35
  199. package/templates/react/src/utils/utils.ts +0 -3
  200. /package/templates/nextjs/app/{page.tsx → (public)/(root)/page.tsx} +0 -0
  201. /package/templates/react/src/{shared/components → components}/error-boundary.tsx +0 -0
  202. /package/templates/react/src/{shared/components → components}/layout.tsx +0 -0
  203. /package/templates/react/src/{shared/pages → pages}/not-found.tsx +0 -0
@@ -7,8 +7,8 @@ exports.createProject = createProject;
7
7
  const chalk_1 = __importDefault(require("chalk"));
8
8
  const child_process_1 = require("child_process");
9
9
  const fs_extra_1 = __importDefault(require("fs-extra"));
10
- const inquirer_1 = __importDefault(require("inquirer"));
11
10
  const path_1 = __importDefault(require("path"));
11
+ const prompts_1 = __importDefault(require("prompts"));
12
12
  const validate_npm_package_name_1 = __importDefault(require("validate-npm-package-name"));
13
13
  const js_conversion_1 = require("../lib/conversion/js-conversion");
14
14
  const module_discovery_1 = require("../lib/discovery/module-discovery");
@@ -63,6 +63,9 @@ async function getProjectConfig(projectName, options) {
63
63
  auth: defaultAuth,
64
64
  language: "typescript",
65
65
  packageManager: "pnpm",
66
+ ui: "none",
67
+ storageProvider: "none",
68
+ components: false,
66
69
  };
67
70
  }
68
71
  const framework = (options && (options.framework || options.f)) || undefined;
@@ -134,16 +137,42 @@ async function getProjectConfig(projectName, options) {
134
137
  auth,
135
138
  language: (language || "typescript"),
136
139
  packageManager: (pm || "pnpm"),
140
+ components: false,
137
141
  };
138
142
  }
139
143
  const prismaProviders = (0, shared_1.getPrismaProvidersFromGenerator)((0, package_root_1.getPackageRoot)());
140
- const answers = (await inquirer_1.default.prompt([
141
- {
142
- type: "input",
144
+ // Sequential prompts using `prompts` to avoid bundling heavy inquirer code
145
+ const result = {};
146
+ const promptSelect = async (name, message, choices, initial) => {
147
+ const resp = await (0, prompts_1.default)({ type: "select", name, message, choices, initial });
148
+ return resp[name];
149
+ };
150
+ const loadDatabaseChoices = () => {
151
+ if (discoveredModules.databases && discoveredModules.databases.length > 0) {
152
+ return (0, module_discovery_1.getDatabaseChoices)(discoveredModules.databases, result.framework || "").map((c) => ({ title: c.name || String(c.value), value: c.value }));
153
+ }
154
+ try {
155
+ const modulesDir = path_1.default.join((0, package_root_1.getPackageRoot)(), "modules", "database");
156
+ if (fs_extra_1.default.existsSync(modulesDir)) {
157
+ const dbs = fs_extra_1.default.readdirSync(modulesDir).map((d) => ({
158
+ title: d.charAt(0).toUpperCase() + d.slice(1),
159
+ value: d,
160
+ }));
161
+ dbs.push({ title: "None", value: "none" });
162
+ return dbs;
163
+ }
164
+ }
165
+ catch {
166
+ // fall through to default
167
+ }
168
+ return [{ title: "None", value: "none" }];
169
+ };
170
+ if (!projectName) {
171
+ const resp = await (0, prompts_1.default)({
172
+ type: "text",
143
173
  name: "projectName",
144
174
  message: "Project name:",
145
- default: projectName || "my-app",
146
- when: !projectName,
175
+ initial: projectName || "my-app",
147
176
  validate: (input) => {
148
177
  const validation = (0, validate_npm_package_name_1.default)(input);
149
178
  if (!validation.validForNewPackages) {
@@ -154,95 +183,186 @@ async function getProjectConfig(projectName, options) {
154
183
  }
155
184
  return true;
156
185
  },
157
- },
158
- {
159
- type: "list",
160
- name: "framework",
161
- message: "Select framework:",
162
- choices: (() => {
163
- if (discoveredModules.frameworks && discoveredModules.frameworks.length > 0) {
164
- return discoveredModules.frameworks.map((f) => ({ name: f.displayName, value: f.name }));
165
- }
166
- try {
167
- const templatesDir = path_1.default.join((0, package_root_1.getPackageRoot)(), "templates");
168
- if (fs_extra_1.default.existsSync(templatesDir)) {
169
- const dirs = fs_extra_1.default.readdirSync(templatesDir).filter((d) => d !== "node_modules");
170
- return dirs.map((d) => ({ name: d.charAt(0).toUpperCase() + d.slice(1), value: d }));
171
- }
172
- }
173
- catch {
174
- return [];
186
+ });
187
+ result.projectName = resp.projectName || projectName || "my-app";
188
+ }
189
+ else {
190
+ result.projectName = projectName;
191
+ }
192
+ // framework
193
+ const frameworkChoices = discoveredModules.frameworks && discoveredModules.frameworks.length > 0
194
+ ? discoveredModules.frameworks.map((f) => ({ title: f.displayName || f.name, value: f.name }))
195
+ : (() => {
196
+ try {
197
+ const templatesDir = path_1.default.join((0, package_root_1.getPackageRoot)(), "templates");
198
+ if (fs_extra_1.default.existsSync(templatesDir)) {
199
+ const dirs = fs_extra_1.default.readdirSync(templatesDir).filter((d) => d !== "node_modules");
200
+ return dirs.map((d) => ({ title: d.charAt(0).toUpperCase() + d.slice(1), value: d }));
175
201
  }
202
+ }
203
+ catch {
176
204
  return [];
177
- })(),
178
- },
179
- {
180
- type: "list",
181
- name: "database",
182
- message: "Select database/ORM:",
183
- when: (answers) => answers.framework !== "react",
184
- choices: (answers) => {
185
- if (discoveredModules.databases && discoveredModules.databases.length > 0) {
186
- return (0, module_discovery_1.getDatabaseChoices)(discoveredModules.databases, answers.framework);
187
- }
188
- try {
189
- const modulesDir = path_1.default.join((0, package_root_1.getPackageRoot)(), "modules", "database");
190
- if (fs_extra_1.default.existsSync(modulesDir)) {
191
- const dbs = fs_extra_1.default
192
- .readdirSync(modulesDir)
193
- .map((d) => ({ name: d.charAt(0).toUpperCase() + d.slice(1), value: d }));
194
- dbs.push({ name: "None", value: "none" });
195
- return dbs;
196
- }
197
- }
198
- catch {
199
- return [{ name: "None", value: "none" }];
200
- }
201
- return [{ name: "None", value: "none" }];
202
- },
203
- },
204
- {
205
- type: "list",
205
+ }
206
+ return [];
207
+ })();
208
+ const fw = await (0, prompts_1.default)({
209
+ type: "select",
210
+ name: "framework",
211
+ message: "Select framework:",
212
+ choices: frameworkChoices,
213
+ });
214
+ result.framework = fw.framework || (discoveredModules.frameworks?.[0]?.name ?? "");
215
+ // database (skip for React and Next.js)
216
+ if (!["react", "nextjs"].includes(result.framework || "")) {
217
+ const dbChoices = loadDatabaseChoices();
218
+ const dbChoicesNormalized = dbChoices.map((c) => ({
219
+ title: c.name || c.title || String(c.value ?? ""),
220
+ value: c.value ?? String(c.title ?? ""),
221
+ }));
222
+ const selected = await promptSelect("database", "Select database/ORM:", dbChoicesNormalized);
223
+ result.database = selected || "none";
224
+ }
225
+ else {
226
+ result.database = "none";
227
+ }
228
+ // prisma provider
229
+ if (result.database === "prisma" && prismaProviders.length > 0) {
230
+ const pp = await (0, prompts_1.default)({
231
+ type: "select",
206
232
  name: "prismaProvider",
207
233
  message: "Select database provider for Prisma:",
208
- when: (answers) => answers.database === "prisma" && prismaProviders.length > 0,
209
234
  choices: prismaProviders.map((p) => ({
210
- name: p.charAt(0).toUpperCase() + p.slice(1),
235
+ title: p.charAt(0).toUpperCase() + p.slice(1),
211
236
  value: p,
212
237
  })),
213
- },
214
- {
215
- type: "list",
238
+ });
239
+ result.prismaProvider = pp.prismaProvider;
240
+ }
241
+ // UI system (React / Next.js)
242
+ if (result.framework === "react" || result.framework === "nextjs") {
243
+ const uiChoices = (discoveredModules.ui || [])
244
+ .filter((u) => !u.supportedFrameworks || u.supportedFrameworks.includes(result.framework || ""))
245
+ .map((u) => ({ title: u.displayName || u.name, value: u.name }));
246
+ if (uiChoices.length === 0) {
247
+ uiChoices.push({ title: "Shadcn (shadcn/ui)", value: "shadcn" });
248
+ uiChoices.push({ title: "None", value: "none" });
249
+ }
250
+ const uiInitial = uiChoices.findIndex((c) => c.value === "none");
251
+ const uiInitialIndex = uiInitial === -1 ? 0 : uiInitial;
252
+ const uiRespRaw = await (0, prompts_1.default)({
253
+ type: "select",
254
+ name: "ui",
255
+ message: "Select UI system:",
256
+ choices: uiChoices,
257
+ initial: uiInitialIndex,
258
+ });
259
+ const uiAnswer = uiRespRaw["ui"];
260
+ if (typeof uiAnswer === "string") {
261
+ result.ui = uiAnswer;
262
+ }
263
+ else {
264
+ result.ui = "none";
265
+ }
266
+ }
267
+ else {
268
+ result.ui = "none";
269
+ }
270
+ // Storage provider (Express)
271
+ if (result.framework === "express") {
272
+ const storageChoices = (discoveredModules.storage || []).map((s) => ({
273
+ title: s.displayName || s.name,
274
+ value: s.name,
275
+ }));
276
+ if (storageChoices.length === 0) {
277
+ storageChoices.push({ title: "Cloudinary", value: "cloudinary" });
278
+ }
279
+ storageChoices.push({ title: "None", value: "none" });
280
+ const spRaw = await (0, prompts_1.default)({
281
+ type: "select",
282
+ name: "storageProvider",
283
+ message: "Select storage provider:",
284
+ choices: storageChoices,
285
+ initial: Math.max(0, storageChoices.findIndex((c) => c.value === "cloudinary")),
286
+ });
287
+ const storageProviderAnswer = spRaw["storageProvider"];
288
+ if (typeof storageProviderAnswer === "string") {
289
+ result.storageProvider = storageProviderAnswer;
290
+ }
291
+ else {
292
+ result.storageProvider = "none";
293
+ }
294
+ }
295
+ else {
296
+ result.storageProvider = "none";
297
+ }
298
+ // Components — yes/no, default yes (React / Next.js only)
299
+ if (result.framework === "react" || result.framework === "nextjs") {
300
+ const compMeta = (discoveredModules.components || []).find((c) => !c.supportedFrameworks || c.supportedFrameworks.includes(result.framework || ""));
301
+ if (compMeta) {
302
+ const compResp = await (0, prompts_1.default)({
303
+ type: "confirm",
304
+ name: "add",
305
+ message: `Add ${compMeta.displayName || compMeta.name}?${compMeta.description ? ` › ${compMeta.description}` : ""}`,
306
+ initial: true,
307
+ });
308
+ result.components = compResp.add !== false;
309
+ }
310
+ else {
311
+ result.components = false;
312
+ }
313
+ }
314
+ else {
315
+ result.components = false;
316
+ }
317
+ // auth
318
+ if (result.database !== "none" || result.framework === "react" || result.framework === "nextjs") {
319
+ const authChoices = (0, module_discovery_1.getCompatibleAuthOptions)(discoveredModules.auth, result.framework || "", result.database || "none", discoveredModules.frameworks);
320
+ const authChoicesNormalized = (authChoices || []).map((c) => ({
321
+ title: c.name
322
+ ? c.description
323
+ ? `${c.name} — ${c.description}`
324
+ : c.name
325
+ : String(c.value ?? ""),
326
+ value: c.value ?? String(c.name ?? ""),
327
+ }));
328
+ const authResp = await (0, prompts_1.default)({
329
+ type: "select",
216
330
  name: "auth",
217
331
  message: "Select authentication:",
218
- when: (answers) => answers.database !== "none" || answers.framework === "react",
219
- choices: (answers) => (0, module_discovery_1.getCompatibleAuthOptions)(discoveredModules.auth, answers.framework, answers.database || "none", discoveredModules.frameworks),
220
- },
221
- {
222
- type: "list",
223
- name: "language",
224
- message: "Language:",
225
- choices: [
226
- { name: "TypeScript", value: "typescript" },
227
- { name: "JavaScript", value: "javascript" },
228
- ],
229
- default: "typescript",
230
- },
231
- {
232
- type: "list",
233
- name: "packageManager",
234
- message: "Package manager:",
235
- choices: [
236
- { name: "pnpm (recommended)", value: "pnpm" },
237
- { name: "npm", value: "npm" },
238
- { name: "yarn", value: "yarn" },
239
- { name: "bun", value: "bun" },
240
- ],
241
- default: "pnpm",
242
- },
243
- ]));
244
- let databaseAnswer = answers.framework === "react" ? "none" : answers.database;
245
- let prismaProviderAnswer = answers.prismaProvider;
332
+ choices: authChoicesNormalized,
333
+ });
334
+ result.auth = authResp.auth || "none";
335
+ }
336
+ else {
337
+ result.auth = "none";
338
+ }
339
+ const langResp = await (0, prompts_1.default)({
340
+ type: "select",
341
+ name: "language",
342
+ message: "Language:",
343
+ choices: [
344
+ { title: "TypeScript", value: "typescript" },
345
+ { title: "JavaScript", value: "javascript" },
346
+ ],
347
+ initial: 0,
348
+ });
349
+ result.language = langResp.language || "typescript";
350
+ const pmResp = await (0, prompts_1.default)({
351
+ type: "select",
352
+ name: "packageManager",
353
+ message: "Package manager:",
354
+ choices: [
355
+ { title: "pnpm (recommended)", value: "pnpm" },
356
+ { title: "npm", value: "npm" },
357
+ { title: "yarn", value: "yarn" },
358
+ { title: "bun", value: "bun" },
359
+ ],
360
+ initial: 0,
361
+ });
362
+ result.packageManager = pmResp.packageManager || "pnpm";
363
+ // Normalise prisma provider if database string contains prisma-xyz
364
+ let databaseAnswer = result.database;
365
+ let prismaProviderAnswer = result.prismaProvider;
246
366
  if (typeof databaseAnswer === "string" && databaseAnswer.startsWith("prisma-")) {
247
367
  const parts = databaseAnswer.split("-");
248
368
  if (parts.length >= 2) {
@@ -251,13 +371,16 @@ async function getProjectConfig(projectName, options) {
251
371
  }
252
372
  }
253
373
  return {
254
- projectName: (projectName || answers.projectName),
255
- framework: answers.framework,
374
+ projectName: (projectName || result.projectName),
375
+ framework: result.framework,
256
376
  database: databaseAnswer,
257
377
  prismaProvider: prismaProviderAnswer,
258
- auth: answers.auth || "none",
259
- language: answers.language,
260
- packageManager: answers.packageManager,
378
+ auth: result.auth || "none",
379
+ language: result.language,
380
+ packageManager: result.packageManager,
381
+ ui: result.ui || "none",
382
+ storageProvider: result.storageProvider || "none",
383
+ components: result.components ?? false,
261
384
  };
262
385
  }
263
386
  async function generateProject(config, targetDir, options) {
@@ -288,7 +411,7 @@ async function generateProject(config, targetDir, options) {
288
411
  const postInstallSpinner = logger_1.logger.startSpinner("Running post-install commands...");
289
412
  try {
290
413
  for (const command of postInstallCommands) {
291
- (0, child_process_1.execSync)(command, { cwd: targetDir, stdio: "pipe" });
414
+ (0, child_process_1.execSync)(command, { cwd: targetDir, stdio: "inherit" });
292
415
  }
293
416
  postInstallSpinner.succeed("Post-install commands completed");
294
417
  }
@@ -298,13 +421,11 @@ async function generateProject(config, targetDir, options) {
298
421
  }
299
422
  }
300
423
  if (options?.git !== false && !(options?.["no-git"] || options?.noGit)) {
301
- const gitSpinner = logger_1.logger.startSpinner("Initializing git repository...");
302
424
  try {
303
425
  await (0, package_manager_1.initGit)(targetDir);
304
- gitSpinner.succeed("Git repository initialized");
305
426
  }
306
427
  catch (error) {
307
- gitSpinner.warn(`Failed to initialize git repository: ${error.message}`);
428
+ logger_1.logger.warn(`Failed to initialize git repository: ${error.message}`);
308
429
  }
309
430
  }
310
431
  }
@@ -322,6 +443,10 @@ async function composeTemplate(config, targetDir) {
322
443
  database: config.database === "none" ? undefined : config.database,
323
444
  auth: config.auth === "none" ? undefined : config.auth,
324
445
  prismaProvider: config.prismaProvider,
446
+ ui: config.ui,
447
+ storageProvider: config.storageProvider,
448
+ components: config.components === true ? true : undefined,
449
+ packageManager: config.packageManager,
325
450
  }, features, targetDir);
326
451
  const packageJsonPath = path_1.default.join(targetDir, "package.json");
327
452
  if (await fs_extra_1.default.pathExists(packageJsonPath)) {
@@ -388,6 +513,57 @@ async function processGeneratorEnvVars(config, targetDir) {
388
513
  }
389
514
  }
390
515
  }
516
+ // UI module env vars
517
+ if (config.ui && config.ui !== "none") {
518
+ const uiGeneratorPath = path_1.default.join(modulesDir, "ui", config.ui, "generator.json");
519
+ if (await fs_extra_1.default.pathExists(uiGeneratorPath)) {
520
+ const generator = await fs_extra_1.default.readJson(uiGeneratorPath);
521
+ if (generator.operations) {
522
+ for (const operation of generator.operations) {
523
+ if (operation.type === "add-env" &&
524
+ (!operation.condition || checkCondition(operation.condition, config))) {
525
+ for (const [key, value] of Object.entries(operation.envVars)) {
526
+ envVars.push({ key, value: value, required: true });
527
+ }
528
+ }
529
+ }
530
+ }
531
+ }
532
+ }
533
+ // Storage/provider module env vars
534
+ if (config.storageProvider && config.storageProvider !== "none") {
535
+ const spGeneratorPath = path_1.default.join(modulesDir, "storage", config.storageProvider, "generator.json");
536
+ if (await fs_extra_1.default.pathExists(spGeneratorPath)) {
537
+ const generator = await fs_extra_1.default.readJson(spGeneratorPath);
538
+ if (generator.operations) {
539
+ for (const operation of generator.operations) {
540
+ if (operation.type === "add-env" &&
541
+ (!operation.condition || checkCondition(operation.condition, config))) {
542
+ for (const [key, value] of Object.entries(operation.envVars)) {
543
+ envVars.push({ key, value: value, required: true });
544
+ }
545
+ }
546
+ }
547
+ }
548
+ }
549
+ }
550
+ // Components module env vars
551
+ if (config.components === true) {
552
+ const compGeneratorPath = path_1.default.join(modulesDir, "components", "generator.json");
553
+ if (await fs_extra_1.default.pathExists(compGeneratorPath)) {
554
+ const generator = await fs_extra_1.default.readJson(compGeneratorPath);
555
+ if (generator.operations) {
556
+ for (const operation of generator.operations) {
557
+ if (operation.type === "add-env" &&
558
+ (!operation.condition || checkCondition(operation.condition, config))) {
559
+ for (const [key, value] of Object.entries(operation.envVars)) {
560
+ envVars.push({ key, value: value, required: true });
561
+ }
562
+ }
563
+ }
564
+ }
565
+ }
566
+ }
391
567
  if (envVars.length > 0) {
392
568
  await (0, env_editor_1.addEnvVariables)(targetDir, envVars, { force: true });
393
569
  }
@@ -452,6 +452,7 @@ async function checkEslintConfigExists(projectRoot) {
452
452
  ".eslintrc.yml",
453
453
  ".eslintrc.yaml",
454
454
  "eslint.config.js",
455
+ "eslint.config.cjs",
455
456
  "eslint.config.mjs",
456
457
  ];
457
458
  for (const config of possibleConfigs) {
@@ -2,5 +2,5 @@ interface ListOptions {
2
2
  frameworks?: boolean;
3
3
  modules?: boolean;
4
4
  }
5
- export declare function listCommand(options: ListOptions): Promise<void>;
5
+ export declare function listCommand(options?: ListOptions): Promise<void>;
6
6
  export {};
package/dist/cli/list.js CHANGED
@@ -11,7 +11,7 @@ const shared_1 = require("../lib/discovery/shared");
11
11
  const logger_1 = require("../lib/ui/logger");
12
12
  const module_loader_1 = require("../lib/utils/module-loader");
13
13
  const package_root_1 = require("../lib/utils/package-root");
14
- async function listCommand(options) {
14
+ async function listCommand(options = {}) {
15
15
  const showFrameworks = !options.modules || options.frameworks;
16
16
  const showModules = !options.frameworks || options.modules;
17
17
  try {
@@ -19,14 +19,16 @@ async function listCommand(options) {
19
19
  logger_1.logger.newLine();
20
20
  let hasContent = false;
21
21
  if (showFrameworks) {
22
- const frameworks = await getAvailableFrameworks();
22
+ let frameworks = [];
23
+ frameworks = await getAvailableFrameworks();
23
24
  if (frameworks.length > 0) {
24
25
  hasContent = true;
25
26
  printFrameworks(frameworks);
26
27
  }
27
28
  }
28
29
  if (showModules) {
29
- const modules = await getAvailableModules();
30
+ let modules = [];
31
+ modules = await getAvailableModules();
30
32
  if (modules.length > 0) {
31
33
  hasContent = true;
32
34
  printModules(modules);
@@ -40,7 +42,7 @@ async function listCommand(options) {
40
42
  logger_1.logger.newLine();
41
43
  }
42
44
  catch (error) {
43
- logger_1.logger.error(`Failed to list resources: ${error.message}`);
45
+ logger_1.logger.error(`Failed to list resources: ${error.message}`, error);
44
46
  process.exit(1);
45
47
  }
46
48
  }