stackkit 0.3.5 → 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.
- package/README.md +50 -42
- package/dist/cli/add.js +122 -56
- package/dist/cli/create.d.ts +2 -0
- package/dist/cli/create.js +271 -95
- package/dist/cli/doctor.js +1 -0
- package/dist/cli/list.d.ts +1 -1
- package/dist/cli/list.js +6 -4
- package/dist/index.js +234 -191
- package/dist/lib/constants.d.ts +4 -0
- package/dist/lib/constants.js +4 -0
- package/dist/lib/discovery/module-discovery.d.ts +4 -0
- package/dist/lib/discovery/module-discovery.js +56 -0
- package/dist/lib/generation/code-generator.d.ts +11 -2
- package/dist/lib/generation/code-generator.js +42 -3
- package/dist/lib/generation/generator-utils.js +3 -1
- package/dist/lib/pm/package-manager.js +16 -13
- package/dist/lib/ui/logger.js +3 -2
- package/dist/lib/utils/path-resolver.d.ts +2 -0
- package/dist/lib/utils/path-resolver.js +8 -0
- package/dist/meta.json +8312 -0
- package/modules/auth/better-auth/files/{shared → express}/config/env.ts +48 -50
- package/modules/auth/better-auth/files/express/middlewares/authorize.ts +20 -1
- package/modules/auth/better-auth/files/express/modules/auth.controller.ts +349 -0
- package/modules/auth/better-auth/files/express/modules/{auth/auth.route.ts → auth.route.ts} +9 -4
- package/modules/auth/better-auth/files/express/modules/auth.service.ts +664 -0
- package/modules/auth/better-auth/files/express/modules/{auth/auth.type.ts → auth.type.ts} +22 -9
- package/modules/auth/better-auth/files/{shared/mongoose/auth/helper.ts → express/mongo-modules/auth.helper.ts} +11 -1
- package/modules/auth/better-auth/files/express/types/express.d.ts +11 -0
- package/modules/auth/better-auth/files/nextjs/api-route.ts +74 -0
- package/modules/auth/better-auth/files/nextjs/dashboard/pages/(user)/page.tsx +6 -0
- package/modules/auth/better-auth/files/nextjs/dashboard/pages/admin/page.tsx +6 -0
- package/modules/auth/better-auth/files/nextjs/dashboard/pages/layout.tsx +48 -0
- package/modules/auth/better-auth/files/nextjs/dashboard/pages/my-profile/page.tsx +5 -0
- package/modules/auth/better-auth/files/nextjs/features/services/auth.service.ts +102 -0
- package/modules/auth/better-auth/files/nextjs/layout/layout.tsx +13 -0
- package/modules/auth/better-auth/files/nextjs/lib/axios/http.ts +158 -0
- package/modules/auth/better-auth/files/nextjs/lib/env.ts +35 -0
- package/modules/auth/better-auth/files/nextjs/lib/utils/auth.ts +75 -0
- package/modules/auth/better-auth/files/nextjs/lib/utils/cookie.ts +29 -0
- package/modules/auth/better-auth/files/nextjs/lib/utils/jwt.ts +28 -0
- package/modules/auth/better-auth/files/nextjs/lib/utils/token.ts +49 -0
- package/modules/auth/better-auth/files/nextjs/pages/forgot-password/page.tsx +5 -0
- package/modules/auth/better-auth/files/nextjs/pages/layout.tsx +11 -0
- package/modules/auth/better-auth/files/nextjs/pages/login/page.tsx +9 -0
- package/modules/auth/better-auth/files/nextjs/pages/register/page.tsx +5 -0
- package/modules/auth/better-auth/files/nextjs/pages/reset-password/page.tsx +10 -0
- package/modules/auth/better-auth/files/nextjs/pages/verify-email/page.tsx +10 -0
- package/modules/auth/better-auth/files/nextjs/proxy.ts +154 -42
- package/modules/auth/better-auth/files/nextjs/theme/providers/theme-provider.tsx +11 -0
- package/modules/auth/better-auth/files/nextjs/types/api.types.ts +18 -0
- package/modules/auth/better-auth/files/react/components/protected-route.tsx +39 -0
- package/modules/auth/better-auth/files/react/components/route-guards.tsx +13 -0
- package/modules/auth/better-auth/files/react/dashboard/admin/pages/overview.tsx +3 -0
- package/modules/auth/better-auth/files/react/dashboard/pages/overview.tsx +3 -0
- package/modules/auth/better-auth/files/react/features/pages/forgot-password.tsx +5 -0
- package/modules/auth/better-auth/files/react/features/pages/login.tsx +5 -0
- package/modules/auth/better-auth/files/react/features/pages/my-profile.tsx +5 -0
- package/modules/auth/better-auth/files/react/features/pages/oauth-callback.tsx +59 -0
- package/modules/auth/better-auth/files/react/features/pages/register.tsx +5 -0
- package/modules/auth/better-auth/files/react/features/pages/reset-password.tsx +10 -0
- package/modules/auth/better-auth/files/react/features/pages/verify-email.tsx +10 -0
- package/modules/auth/better-auth/files/react/layout/dashboard-layout.tsx +54 -0
- package/modules/auth/better-auth/files/react/lib/axios/http.ts +68 -0
- package/modules/auth/better-auth/files/react/lib/env.ts +25 -0
- package/modules/auth/better-auth/files/react/router.tsx +73 -0
- package/modules/auth/better-auth/files/react/theme/components/providers/theme-provider-context.ts +13 -0
- package/modules/auth/better-auth/files/react/theme/components/providers/theme-provider.tsx +51 -0
- package/modules/auth/better-auth/files/react/theme/hooks/use-theme.ts +8 -0
- package/modules/auth/better-auth/files/shared/features/components/change-password-dialog.tsx +113 -0
- package/modules/auth/better-auth/files/shared/features/components/forgot-password-form.tsx +84 -0
- package/modules/auth/better-auth/files/shared/features/components/login-form.tsx +134 -0
- package/modules/auth/better-auth/files/shared/features/components/my-profile.tsx +147 -0
- package/modules/auth/better-auth/files/shared/features/components/profile-form.tsx +205 -0
- package/modules/auth/better-auth/files/shared/features/components/register-form.tsx +100 -0
- package/modules/auth/better-auth/files/shared/features/components/reset-password-form.tsx +111 -0
- package/modules/auth/better-auth/files/shared/features/components/social-login-buttons.tsx +47 -0
- package/modules/auth/better-auth/files/shared/features/components/user-profile-menu.tsx +106 -0
- package/modules/auth/better-auth/files/shared/features/components/verify-email-form.tsx +110 -0
- package/modules/auth/better-auth/files/shared/features/queries/auth.mutations.tsx +312 -0
- package/modules/auth/better-auth/files/shared/features/queries/auth.querie.ts +19 -0
- package/modules/auth/better-auth/files/shared/features/services/auth.api.ts +81 -0
- package/modules/auth/better-auth/files/shared/features/types/auth.type.ts +47 -0
- package/modules/auth/better-auth/files/shared/features/validators/change-password.validator.ts +18 -0
- package/modules/auth/better-auth/files/shared/features/validators/forgot.validator.ts +7 -0
- package/modules/auth/better-auth/files/shared/features/validators/login.validator.ts +14 -0
- package/modules/auth/better-auth/files/shared/features/validators/profile.validator.ts +8 -0
- package/modules/auth/better-auth/files/shared/features/validators/register.validator.ts +9 -0
- package/modules/auth/better-auth/files/shared/features/validators/reset.validator.ts +9 -0
- package/modules/auth/better-auth/files/shared/features/validators/verify.validator.ts +8 -0
- package/modules/auth/better-auth/files/shared/lib/auth-client.ts +2 -1
- package/modules/auth/better-auth/files/shared/lib/auth.ts +5 -19
- package/modules/auth/better-auth/files/shared/lib/constant/dashboard.ts +90 -0
- package/modules/auth/better-auth/files/shared/theme/mode-toggle.tsx +30 -0
- package/modules/auth/better-auth/files/shared/ui/shadcn/components/dashboard/dashboard-header.tsx +94 -0
- package/modules/auth/better-auth/files/shared/ui/shadcn/components/dashboard/dashboard-sidebar.tsx +255 -0
- package/modules/auth/better-auth/files/shared/ui/shadcn/components/footer.tsx +35 -0
- package/modules/auth/better-auth/files/shared/ui/shadcn/components/navbar.tsx +145 -0
- package/modules/auth/better-auth/files/shared/ui/shadcn/form-field/input-field.tsx +440 -0
- package/modules/auth/better-auth/files/shared/utils/email.ts +2 -17
- package/modules/auth/better-auth/generator.json +172 -51
- package/modules/auth/better-auth/module.json +2 -2
- package/modules/components/files/shared/hooks/use-file-upload.ts +412 -0
- package/modules/components/files/shared/lib/utils/url-helpers.ts +110 -0
- package/modules/components/files/shared/shadcn/dashboard/data-table-column-selector.tsx +52 -0
- package/modules/components/files/shared/shadcn/dashboard/data-table-footer.tsx +156 -0
- package/modules/components/files/shared/shadcn/dashboard/data-table.tsx +405 -0
- package/modules/components/files/shared/shadcn/global/form-field/input-field.tsx +440 -0
- package/modules/components/files/shared/shadcn/global/form-field/media-uploader-field.tsx +745 -0
- package/modules/components/files/shared/shadcn/global/form-field/multi-select-field.tsx +207 -0
- package/modules/components/files/shared/shadcn/global/form-field/select-field.tsx +247 -0
- package/modules/components/files/shared/shadcn/global/form-field/textarea-field.tsx +277 -0
- package/modules/components/files/shared/shadcn/global/form-field/tiptap-editor-field.tsx +35 -0
- package/modules/components/files/shared/shadcn/global/no-results.tsx +41 -0
- package/modules/components/files/shared/shadcn/tiptap-editor/editor-menu-bar.tsx +217 -0
- package/modules/components/files/shared/shadcn/tiptap-editor/tiptap-editor.tsx +104 -0
- package/modules/components/files/shared/url/load-more.tsx +93 -0
- package/modules/components/files/shared/url/search-bar.tsx +131 -0
- package/modules/components/files/shared/url/sort-select.tsx +118 -0
- package/modules/components/files/shared/url/url-tabs.tsx +77 -0
- package/modules/components/generator.json +109 -0
- package/modules/components/module.json +11 -0
- package/modules/database/mongoose/generator.json +3 -14
- package/modules/database/mongoose/module.json +2 -2
- package/modules/database/prisma/generator.json +6 -12
- package/modules/database/prisma/module.json +2 -2
- package/modules/storage/cloudinary/files/express/config/env.ts +65 -0
- package/modules/storage/cloudinary/files/express/config/media.ts +103 -0
- package/modules/storage/cloudinary/files/express/modules/media/media.controller.ts +59 -0
- package/modules/storage/cloudinary/files/express/modules/media/media.route.ts +29 -0
- package/modules/storage/cloudinary/files/express/modules/media/media.service.ts +113 -0
- package/modules/storage/cloudinary/files/express/modules/media/media.type.ts +32 -0
- package/modules/storage/cloudinary/generator.json +34 -0
- package/modules/storage/cloudinary/module.json +11 -0
- package/modules/ui/shadcn/generator.json +21 -0
- package/modules/ui/shadcn/module.json +11 -0
- package/package.json +24 -26
- package/templates/express/README.md +11 -16
- package/templates/express/src/config/env.ts +7 -5
- package/templates/nextjs/README.md +13 -18
- package/templates/nextjs/app/favicon.ico +0 -0
- package/templates/nextjs/app/layout.tsx +6 -4
- package/templates/nextjs/components/providers/query-provider.tsx +3 -0
- package/templates/nextjs/env.example +3 -1
- package/templates/nextjs/lib/axios/http.ts +23 -0
- package/templates/nextjs/lib/env.ts +7 -5
- package/templates/nextjs/package.json +2 -1
- package/templates/nextjs/template.json +1 -2
- package/templates/react/README.md +9 -14
- package/templates/react/index.html +1 -1
- package/templates/react/package.json +1 -1
- package/templates/react/src/assets/favicon.ico +0 -0
- package/templates/react/src/components/providers/query-provider.tsx +38 -0
- package/templates/react/src/{shared/components → components}/seo.tsx +4 -8
- package/templates/react/src/lib/axios/http.ts +24 -0
- package/templates/react/src/main.tsx +8 -11
- package/templates/react/src/{features/about/pages → pages}/about.tsx +1 -1
- package/templates/react/src/{features/home/pages → pages}/home.tsx +1 -1
- package/templates/react/src/router.tsx +6 -6
- package/templates/react/src/vite-env.d.ts +2 -1
- package/templates/react/template.json +0 -1
- package/templates/react/tsconfig.app.json +6 -0
- package/templates/react/tsconfig.json +7 -1
- package/templates/react/vite.config.ts +12 -0
- package/modules/auth/authjs/files/nextjs/api/auth/[...nextauth]/route.ts +0 -3
- package/modules/auth/authjs/files/nextjs/proxy.ts +0 -1
- package/modules/auth/authjs/files/shared/lib/auth.ts +0 -119
- package/modules/auth/authjs/files/shared/prisma/schema.prisma +0 -61
- package/modules/auth/authjs/generator.json +0 -64
- package/modules/auth/authjs/module.json +0 -13
- package/modules/auth/better-auth/files/express/modules/auth/auth.controller.ts +0 -264
- package/modules/auth/better-auth/files/express/modules/auth/auth.service.ts +0 -549
- package/modules/auth/better-auth/files/express/templates/google-redirect.ejs +0 -24
- package/modules/auth/better-auth/files/nextjs/api/auth/[...all]/route.ts +0 -4
- package/modules/auth/better-auth/files/nextjs/lib/auth/auth-guards.ts +0 -31
- package/modules/auth/better-auth/files/nextjs/templates/email-otp.tsx +0 -74
- package/templates/nextjs/lib/api/http.ts +0 -40
- package/templates/react/public/vite.svg +0 -1
- package/templates/react/src/app/layouts/dashboard-layout.tsx +0 -8
- package/templates/react/src/app/layouts/public-layout.tsx +0 -5
- package/templates/react/src/app/providers.tsx +0 -20
- package/templates/react/src/app/router.tsx +0 -21
- package/templates/react/src/assets/react.svg +0 -1
- package/templates/react/src/shared/api/http.ts +0 -39
- package/templates/react/src/shared/components/loading.tsx +0 -8
- package/templates/react/src/shared/lib/query-client.ts +0 -12
- package/templates/react/src/utils/storage.ts +0 -35
- package/templates/react/src/utils/utils.ts +0 -3
- /package/modules/auth/better-auth/files/{shared/mongoose/auth/constants.ts → express/mongo-modules/auth.constants.ts} +0 -0
- /package/templates/nextjs/app/{page.tsx → (public)/(root)/page.tsx} +0 -0
- /package/templates/react/src/{shared/components → components}/error-boundary.tsx +0 -0
- /package/templates/react/src/{shared/components → components}/layout.tsx +0 -0
- /package/templates/react/src/{shared/pages → pages}/not-found.tsx +0 -0
package/dist/cli/create.js
CHANGED
|
@@ -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
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
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
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
-
|
|
235
|
+
title: p.charAt(0).toUpperCase() + p.slice(1),
|
|
211
236
|
value: p,
|
|
212
237
|
})),
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
|
|
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
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
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 ||
|
|
255
|
-
framework:
|
|
374
|
+
projectName: (projectName || result.projectName),
|
|
375
|
+
framework: result.framework,
|
|
256
376
|
database: databaseAnswer,
|
|
257
377
|
prismaProvider: prismaProviderAnswer,
|
|
258
|
-
auth:
|
|
259
|
-
language:
|
|
260
|
-
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: "
|
|
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
|
-
|
|
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
|
}
|
package/dist/cli/doctor.js
CHANGED
package/dist/cli/list.d.ts
CHANGED
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
|
-
|
|
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
|
-
|
|
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
|
}
|