create-stackforge 0.1.0 → 0.1.2

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/dist/cli.js CHANGED
@@ -123,15 +123,58 @@ function defaultConfig() {
123
123
  var supported = {
124
124
  frontend: ["nextjs", "vite"],
125
125
  ui: ["none", "tailwind", "shadcn", "mui", "chakra", "mantine", "antd", "nextui"],
126
- database: ["none", "postgres", "mysql", "sqlite", "neon", "supabase"],
126
+ database: ["none", "postgres", "mysql", "sqlite", "mongodb", "neon", "supabase"],
127
127
  orm: ["drizzle", "prisma", "mongoose", "typeorm"],
128
- auth: ["none", "nextauth", "clerk", "supabase"],
128
+ auth: ["none", "nextauth", "clerk", "better-auth", "supabase"],
129
129
  api: ["none", "rest", "trpc", "graphql"],
130
130
  agents: ["claude", "copilot", "codex", "gemini", "cursor", "codeium", "windsurf", "tabnine"],
131
131
  features: ["email", "storage", "payments", "analytics", "error-tracking"]
132
132
  };
133
133
 
134
134
  // src/cli/prompts/index.ts
135
+ var displayNames = {
136
+ // Frontend
137
+ nextjs: "Next.js",
138
+ vite: "Vite",
139
+ // UI
140
+ none: "None",
141
+ tailwind: "Tailwind CSS",
142
+ shadcn: "shadcn/ui",
143
+ mui: "Material UI",
144
+ chakra: "Chakra UI",
145
+ mantine: "Mantine",
146
+ antd: "Ant Design",
147
+ nextui: "NextUI",
148
+ // Database
149
+ postgres: "PostgreSQL",
150
+ mysql: "MySQL",
151
+ sqlite: "SQLite",
152
+ mongodb: "MongoDB",
153
+ neon: "Neon",
154
+ supabase: "Supabase",
155
+ // ORM
156
+ drizzle: "Drizzle",
157
+ prisma: "Prisma",
158
+ mongoose: "Mongoose",
159
+ typeorm: "TypeORM",
160
+ // Auth
161
+ nextauth: "NextAuth",
162
+ clerk: "Clerk",
163
+ "better-auth": "Better Auth",
164
+ // API
165
+ rest: "REST",
166
+ trpc: "tRPC",
167
+ graphql: "GraphQL",
168
+ // Features
169
+ email: "Email (Resend)",
170
+ storage: "File Storage (Cloudinary)",
171
+ payments: "Payments (Stripe)",
172
+ analytics: "Analytics (PostHog)",
173
+ "error-tracking": "Error Tracking (Sentry)"
174
+ };
175
+ function label(value) {
176
+ return displayNames[value] || value;
177
+ }
135
178
  async function promptForConfig(input) {
136
179
  if (input.skipPrompts) {
137
180
  const base2 = defaultConfig();
@@ -166,7 +209,7 @@ async function promptForConfig(input) {
166
209
  type: "list",
167
210
  name: "frontend",
168
211
  message: "Frontend framework",
169
- choices: supported.frontend.map((v) => ({ name: v, value: v }))
212
+ choices: supported.frontend.map((v) => ({ name: label(v), value: v }))
170
213
  },
171
214
  {
172
215
  type: "list",
@@ -181,38 +224,38 @@ async function promptForConfig(input) {
181
224
  type: "list",
182
225
  name: "uiLibrary",
183
226
  message: "UI library",
184
- choices: supported.ui.map((v) => ({ name: v, value: v }))
227
+ choices: supported.ui.map((v) => ({ name: label(v), value: v }))
185
228
  },
186
229
  {
187
230
  type: "list",
188
231
  name: "databaseProvider",
189
232
  message: "Database provider",
190
- choices: supported.database.map((v) => ({ name: v, value: v }))
233
+ choices: supported.database.map((v) => ({ name: label(v), value: v }))
191
234
  },
192
235
  {
193
236
  type: "list",
194
237
  name: "orm",
195
238
  message: "ORM",
196
239
  when: (ans) => ans.databaseProvider !== "none",
197
- choices: supported.orm.map((v) => ({ name: v, value: v }))
240
+ choices: supported.orm.map((v) => ({ name: label(v), value: v }))
198
241
  },
199
242
  {
200
243
  type: "list",
201
244
  name: "authProvider",
202
245
  message: "Authentication",
203
- choices: supported.auth.map((v) => ({ name: v, value: v }))
246
+ choices: supported.auth.map((v) => ({ name: label(v), value: v }))
204
247
  },
205
248
  {
206
249
  type: "list",
207
250
  name: "apiType",
208
251
  message: "API type",
209
- choices: supported.api.map((v) => ({ name: v, value: v }))
252
+ choices: supported.api.map((v) => ({ name: label(v), value: v }))
210
253
  },
211
254
  {
212
255
  type: "checkbox",
213
256
  name: "features",
214
257
  message: "Additional features",
215
- choices: supported.features.map((v) => ({ name: v, value: v }))
258
+ choices: supported.features.map((v) => ({ name: label(v), value: v }))
216
259
  }
217
260
  ]);
218
261
  const base = {
@@ -358,11 +401,24 @@ var versions = {
358
401
  graphql: "^16.9.0",
359
402
  graphqlRequest: "^6.1.0",
360
403
  graphqlYoga: "^5.7.0",
404
+ mongodb: "^6.8.0",
405
+ betterAuth: "^1.2.0",
361
406
  resend: "^3.5.0",
407
+ sendgrid: "^8.1.0",
408
+ nodemailer: "^6.9.0",
409
+ typesNodemailer: "^6.4.0",
410
+ awsSes: "^3.700.0",
362
411
  cloudinary: "^2.0.0",
412
+ awsS3: "^3.700.0",
413
+ vercelBlob: "^0.24.0",
363
414
  stripe: "^14.0.0",
415
+ paypal: "^1.0.0",
416
+ razorpay: "^2.9.0",
364
417
  posthog: "^1.165.0",
365
- sentryNext: "^8.35.0"
418
+ reactGa4: "^2.1.0",
419
+ vercelAnalytics: "^1.3.0",
420
+ sentryNext: "^8.35.0",
421
+ logrocket: "^8.1.0"
366
422
  };
367
423
 
368
424
  // src/generators/deps/deps-registry.ts
@@ -434,6 +490,9 @@ function collectDependencies(config) {
434
490
  if (config.database.provider === "sqlite") {
435
491
  dependencies["better-sqlite3"] = versions.betterSqlite3;
436
492
  }
493
+ if (config.database.provider === "mongodb") {
494
+ dependencies["mongodb"] = versions.mongodb;
495
+ }
437
496
  if (config.database.provider === "neon") {
438
497
  dependencies["@neondatabase/serverless"] = versions.neonServerless;
439
498
  }
@@ -461,6 +520,9 @@ function collectDependencies(config) {
461
520
  if (config.auth.provider === "clerk") {
462
521
  dependencies["@clerk/nextjs"] = versions.clerkNext;
463
522
  }
523
+ if (config.auth.provider === "better-auth") {
524
+ dependencies["better-auth"] = versions.betterAuth;
525
+ }
464
526
  if (config.auth.provider === "supabase") {
465
527
  dependencies["@supabase/supabase-js"] = versions.supabaseJs;
466
528
  if (config.frontend.type === "nextjs") {
@@ -590,7 +652,7 @@ async function createProjectSkeleton(root, config, ctx) {
590
652
  const envExample = `# Environment Variables
591
653
  `;
592
654
  await writeTextFile(join3(projectRoot, ".env.example"), envExample, ctx);
593
- const gitignore = await readTextFile(join3(templatesRoot, "shared", ".gitignore"));
655
+ const gitignore = await readTextFile(join3(templatesRoot, "shared", "_gitignore"));
594
656
  await writeTextFile(join3(projectRoot, ".gitignore"), gitignore, ctx);
595
657
  const editorconfig = await readTextFile(join3(templatesRoot, "shared", ".editorconfig"));
596
658
  await writeTextFile(join3(projectRoot, ".editorconfig"), editorconfig, ctx);
@@ -684,7 +746,11 @@ async function generateDatabaseFiles(root, config, ctx) {
684
746
  const templatesRoot = fileURLToPath2(new URL("../../../templates", import.meta.url));
685
747
  if (config.database.provider !== "none") {
686
748
  const envPath = join4(projectRoot, ".env.example");
687
- await appendEnvLine(envPath, 'DATABASE_URL=""', ctx);
749
+ if (config.database.provider === "mongodb") {
750
+ await appendEnvLine(envPath, 'MONGODB_URI=""', ctx);
751
+ } else {
752
+ await appendEnvLine(envPath, 'DATABASE_URL=""', ctx);
753
+ }
688
754
  if (config.database.provider === "neon") {
689
755
  await appendEnvLine(envPath, 'NEON_API_KEY=""', ctx);
690
756
  await appendEnvLine(envPath, 'NEON_PROJECT_ID=""', ctx);
@@ -1272,6 +1338,37 @@ export const config = {
1272
1338
  await writeTextFile(join7(authDir, `protected.${ext}x`), protectedPage, ctx);
1273
1339
  }
1274
1340
  }
1341
+ if (config.auth.provider === "better-auth") {
1342
+ await appendEnvLine(join7(projectRoot, ".env.example"), 'BETTER_AUTH_SECRET=""', ctx);
1343
+ await appendEnvLine(join7(projectRoot, ".env.example"), 'BETTER_AUTH_URL=""', ctx);
1344
+ const ext = config.frontend.language === "ts" ? "ts" : "js";
1345
+ const authDir = join7(projectRoot, "auth");
1346
+ await ensureDir(authDir, ctx);
1347
+ const readme = await readTextFile(join7(templatesRoot, "auth", "better-auth.README.md"));
1348
+ await writeTextFile(join7(authDir, "README.md"), readme, ctx);
1349
+ const serverConfig = await readTextFile(join7(templatesRoot, "auth", `better-auth-server.${ext}`));
1350
+ await writeTextFile(join7(authDir, `auth.${ext}`), serverConfig, ctx);
1351
+ const libDir = join7(projectRoot, "src", "lib");
1352
+ await ensureDir(libDir, ctx);
1353
+ const clientConfig = await readTextFile(join7(templatesRoot, "auth", `better-auth-client.${ext}`));
1354
+ await writeTextFile(join7(libDir, `auth-client.${ext}`), clientConfig, ctx);
1355
+ if (config.frontend.type === "nextjs") {
1356
+ const routeDir = join7(projectRoot, "app", "api", "auth", "[...all]");
1357
+ await ensureDir(routeDir, ctx);
1358
+ const route = await readTextFile(join7(templatesRoot, "auth", `better-auth-route.${ext}`));
1359
+ await writeTextFile(join7(routeDir, `route.${ext}`), route, ctx);
1360
+ const protectedDir = join7(projectRoot, "app", "auth", "protected");
1361
+ await ensureDir(protectedDir, ctx);
1362
+ const protectedPage = await readTextFile(
1363
+ join7(templatesRoot, "auth", `better-auth-protected-page.${ext}x`)
1364
+ );
1365
+ await writeTextFile(join7(protectedDir, `page.${ext}x`), protectedPage, ctx);
1366
+ const signInDir = join7(projectRoot, "app", "auth", "signin");
1367
+ await ensureDir(signInDir, ctx);
1368
+ const signInPage = await readTextFile(join7(templatesRoot, "auth", `better-auth-signin.${ext}x`));
1369
+ await writeTextFile(join7(signInDir, `page.${ext}x`), signInPage, ctx);
1370
+ }
1371
+ }
1275
1372
  if (config.auth.provider === "supabase") {
1276
1373
  await appendEnvLine(join7(projectRoot, ".env.example"), 'NEXT_PUBLIC_SUPABASE_URL=""', ctx);
1277
1374
  await appendEnvLine(join7(projectRoot, ".env.example"), 'NEXT_PUBLIC_SUPABASE_ANON_KEY=""', ctx);
@@ -2139,7 +2236,7 @@ function validateCompatibility(config) {
2139
2236
  if (config.api.type === "trpc" && config.frontend.language !== "ts") {
2140
2237
  throw new Error("tRPC requires TypeScript.");
2141
2238
  }
2142
- if (config.database.orm === "mongoose") {
2239
+ if (config.database.orm === "mongoose" && config.database.provider !== "mongodb") {
2143
2240
  throw new Error("Mongoose requires MongoDB. Use drizzle, prisma, or typeorm with SQL databases.");
2144
2241
  }
2145
2242
  if (config.database.orm === "typeorm") {
@@ -3202,7 +3299,7 @@ var require2 = createRequire(import.meta.url);
3202
3299
  var { version } = require2("../package.json");
3203
3300
  var program = new Command17();
3204
3301
  program.name("create-stackforge").description("Universal full-stack boilerplate generator").version(version);
3205
- program.addCommand(createCommand);
3302
+ program.addCommand(createCommand, { isDefault: true });
3206
3303
  program.addCommand(listCommand);
3207
3304
  program.addCommand(addCommand);
3208
3305
  program.addCommand(removeCommand);