create-stackforge 0.1.1 → 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 +110 -13
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/templates/auth/better-auth-client.js +7 -0
- package/templates/auth/better-auth-client.ts +7 -0
- package/templates/auth/better-auth-protected-page.jsx +12 -0
- package/templates/auth/better-auth-protected-page.tsx +12 -0
- package/templates/auth/better-auth-route.js +4 -0
- package/templates/auth/better-auth-route.ts +4 -0
- package/templates/auth/better-auth-server.js +9 -0
- package/templates/auth/better-auth-server.ts +9 -0
- package/templates/auth/better-auth-signin.jsx +25 -0
- package/templates/auth/better-auth-signin.tsx +25 -0
- package/templates/auth/better-auth.README.md +10 -0
- package/templates/shared/_gitignore +7 -0
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
|
-
|
|
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", "
|
|
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
|
-
|
|
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") {
|