create-efc-app 0.2.5 → 0.3.0

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/index.js CHANGED
@@ -2606,14 +2606,16 @@ export const GET = async (_req: Request, res: Response) => {
2606
2606
  ${roleGuard} // TODO: generate CSV of all users and stream response
2607
2607
  res.setHeader('Content-Type', 'text/csv');
2608
2608
  res.setHeader('Content-Disposition', 'attachment; filename="users.csv"');
2609
- res.send('id,name,email,role,createdAt\\n');
2609
+ res.send('id,name,email,role,createdAt
2610
+ ');
2610
2611
  };
2611
2612
  ` : `${RA}${rr3}${exportMeta}${mwAdmin3}
2612
2613
  export const GET = async (_req, res) => {
2613
2614
  ${roleGuard} // TODO: generate CSV of all users and stream response
2614
2615
  res.setHeader('Content-Type', 'text/csv');
2615
2616
  res.setHeader('Content-Disposition', 'attachment; filename="users.csv"');
2616
- res.send('id,name,email,role,createdAt\\n');
2617
+ res.send('id,name,email,role,createdAt
2618
+ ');
2617
2619
  };
2618
2620
  `;
2619
2621
  await fs.outputFile(path.join(dest, "src", "api", "admin", "users", `export.${ext}`), exportContent);
@@ -3014,10 +3016,6 @@ ${roleGuard} const { status, page = 1, limit = 20 } = req.query;
3014
3016
  }
3015
3017
 
3016
3018
  // src/index.ts
3017
- function cancel2(msg = "Cancelled") {
3018
- p.cancel(msg);
3019
- process.exit(0);
3020
- }
3021
3019
  async function main() {
3022
3020
  console.log();
3023
3021
  p.intro(pc.bgCyan(pc.black(" create-efc-app ")));
@@ -3027,7 +3025,10 @@ async function main() {
3027
3025
  defaultValue: "my-api",
3028
3026
  validate: (v) => !v.trim() ? "Project name is required" : void 0
3029
3027
  });
3030
- if (p.isCancel(projectName)) cancel2();
3028
+ if (p.isCancel(projectName)) {
3029
+ p.cancel("Cancelled");
3030
+ process.exit(0);
3031
+ }
3031
3032
  const language = await p.select({
3032
3033
  message: "Language:",
3033
3034
  options: [
@@ -3035,7 +3036,10 @@ async function main() {
3035
3036
  { value: "javascript", label: "JavaScript" }
3036
3037
  ]
3037
3038
  });
3038
- if (p.isCancel(language)) cancel2();
3039
+ if (p.isCancel(language)) {
3040
+ p.cancel("Cancelled");
3041
+ process.exit(0);
3042
+ }
3039
3043
  const database = await p.select({
3040
3044
  message: "Database:",
3041
3045
  options: [
@@ -3043,7 +3047,10 @@ async function main() {
3043
3047
  { value: "postgresql", label: "PostgreSQL", hint: "Drizzle ORM" }
3044
3048
  ]
3045
3049
  });
3046
- if (p.isCancel(database)) cancel2();
3050
+ if (p.isCancel(database)) {
3051
+ p.cancel("Cancelled");
3052
+ process.exit(0);
3053
+ }
3047
3054
  const authStrategy = await p.select({
3048
3055
  message: "Authentication strategy:",
3049
3056
  options: [
@@ -3051,25 +3058,28 @@ async function main() {
3051
3058
  { value: "localStorage", label: "localStorage", hint: "bearer token \u2014 for SPAs" }
3052
3059
  ]
3053
3060
  });
3054
- if (p.isCancel(authStrategy)) cancel2();
3055
- const features = await p.multiselect({
3056
- message: "Features: (space to toggle, enter to confirm)",
3057
- options: [
3058
- { value: "cluster", label: "Multi-core clustering", hint: "Node cluster module" },
3059
- { value: "tasks", label: "Background tasks", hint: "BullMQ / pg-boss" },
3060
- { value: "routeDocs", label: "API route documentation", hint: "meta exports + dashboard" },
3061
- { value: "userPortal", label: "User portal", hint: "auth, profile, billing routes" },
3062
- { value: "adminPortal", label: "Admin portal", hint: "dashboard, user mgmt, analytics" },
3063
- { value: "rbac", label: "Role-based access control", hint: "requireRole middleware" },
3064
- { value: "mailer", label: "Mailer", hint: "nodemailer + SMTP" }
3065
- ],
3066
- initialValues: ["cluster", "tasks", "routeDocs", "userPortal", "adminPortal", "rbac"],
3067
- required: false
3061
+ if (p.isCancel(authStrategy)) {
3062
+ p.cancel("Cancelled");
3063
+ process.exit(0);
3064
+ }
3065
+ const cluster = await p.confirm({
3066
+ message: "Enable multi-core clustering?",
3067
+ initialValue: true
3068
3068
  });
3069
- if (p.isCancel(features)) cancel2();
3070
- const selected = new Set(features);
3069
+ if (p.isCancel(cluster)) {
3070
+ p.cancel("Cancelled");
3071
+ process.exit(0);
3072
+ }
3073
+ const tasks = await p.confirm({
3074
+ message: "Enable background tasks?",
3075
+ initialValue: true
3076
+ });
3077
+ if (p.isCancel(tasks)) {
3078
+ p.cancel("Cancelled");
3079
+ process.exit(0);
3080
+ }
3071
3081
  let taskBackend;
3072
- if (selected.has("tasks")) {
3082
+ if (tasks) {
3073
3083
  const backend = await p.select({
3074
3084
  message: "Task queue backend:",
3075
3085
  options: [
@@ -3077,25 +3087,79 @@ async function main() {
3077
3087
  { value: "pg-boss", label: "pg-boss", hint: "PostgreSQL" }
3078
3088
  ]
3079
3089
  });
3080
- if (p.isCancel(backend)) cancel2();
3090
+ if (p.isCancel(backend)) {
3091
+ p.cancel("Cancelled");
3092
+ process.exit(0);
3093
+ }
3081
3094
  taskBackend = backend;
3082
3095
  }
3096
+ const routeDocs = await p.confirm({
3097
+ message: "Include route documentation (meta exports for the API dashboard)?",
3098
+ initialValue: true
3099
+ });
3100
+ if (p.isCancel(routeDocs)) {
3101
+ p.cancel("Cancelled");
3102
+ process.exit(0);
3103
+ }
3104
+ const userPortal = await p.confirm({
3105
+ message: "Build user portal?",
3106
+ initialValue: true
3107
+ });
3108
+ if (p.isCancel(userPortal)) {
3109
+ p.cancel("Cancelled");
3110
+ process.exit(0);
3111
+ }
3112
+ const adminPortal = await p.confirm({
3113
+ message: "Build admin portal?",
3114
+ initialValue: true
3115
+ });
3116
+ if (p.isCancel(adminPortal)) {
3117
+ p.cancel("Cancelled");
3118
+ process.exit(0);
3119
+ }
3120
+ let rbac = false;
3121
+ if (userPortal || adminPortal) {
3122
+ const rbacAnswer = await p.confirm({
3123
+ message: "Enable role-based access control (RBAC)?",
3124
+ initialValue: true
3125
+ });
3126
+ if (p.isCancel(rbacAnswer)) {
3127
+ p.cancel("Cancelled");
3128
+ process.exit(0);
3129
+ }
3130
+ rbac = rbacAnswer;
3131
+ }
3132
+ const mailerAnswer = await p.confirm({
3133
+ message: "Enable mailer (nodemailer)?",
3134
+ initialValue: false
3135
+ });
3136
+ if (p.isCancel(mailerAnswer)) {
3137
+ p.cancel("Cancelled");
3138
+ process.exit(0);
3139
+ }
3140
+ const mailer = mailerAnswer;
3083
3141
  let smtpHost;
3084
3142
  let smtpPort;
3085
- if (selected.has("mailer")) {
3143
+ if (mailer) {
3086
3144
  const host = await p.text({
3087
3145
  message: "SMTP host:",
3088
3146
  placeholder: "smtp.gmail.com",
3089
3147
  defaultValue: "smtp.gmail.com"
3090
3148
  });
3091
- if (p.isCancel(host)) cancel2();
3149
+ if (p.isCancel(host)) {
3150
+ p.cancel("Cancelled");
3151
+ process.exit(0);
3152
+ }
3092
3153
  smtpHost = host;
3093
3154
  const port = await p.text({
3094
3155
  message: "SMTP port:",
3095
3156
  placeholder: "587",
3096
3157
  defaultValue: "587"
3097
3158
  });
3098
- if (p.isCancel(port)) cancel2();
3159
+ if (p.isCancel(port)) {
3160
+ p.cancel("Cancelled");
3161
+ process.exit(0);
3162
+ }
3099
3163
  smtpPort = port;
3100
3164
  }
3101
3165
  const opts = {
@@ -3103,13 +3167,13 @@ async function main() {
3103
3167
  language,
3104
3168
  database,
3105
3169
  authStrategy,
3106
- cluster: selected.has("cluster"),
3107
- tasks: selected.has("tasks"),
3108
- routeDocs: selected.has("routeDocs"),
3109
- userPortal: selected.has("userPortal"),
3110
- adminPortal: selected.has("adminPortal"),
3111
- rbac: selected.has("rbac"),
3112
- mailer: selected.has("mailer"),
3170
+ cluster,
3171
+ tasks,
3172
+ routeDocs,
3173
+ userPortal,
3174
+ adminPortal,
3175
+ rbac,
3176
+ mailer,
3113
3177
  ...taskBackend !== void 0 && { taskBackend },
3114
3178
  ...smtpHost !== void 0 && { smtpHost },
3115
3179
  ...smtpPort !== void 0 && { smtpPort }
@@ -3144,14 +3208,22 @@ Your project is ready!
3144
3208
  }
3145
3209
  function npmInstall(projectDir) {
3146
3210
  return new Promise((resolve, reject) => {
3147
- const child = spawn("npm", ["install"], { cwd: projectDir, stdio: "ignore" });
3148
- child.on("exit", (code) => code === 0 ? resolve() : reject(new Error("npm install failed")));
3211
+ const child = spawn("npm", ["install"], {
3212
+ cwd: projectDir,
3213
+ stdio: "ignore"
3214
+ });
3215
+ child.on("exit", (code) => code === 0 ? resolve() : reject(new Error(`npm install failed`)));
3149
3216
  });
3150
3217
  }
3151
3218
  function npmInstallGlobal() {
3152
3219
  return new Promise((resolve, reject) => {
3153
- const child = spawn("npm", ["install", "-g", "express-file-cluster"], { stdio: "ignore" });
3154
- child.on("exit", (code) => code === 0 ? resolve() : reject(new Error("global install failed")));
3220
+ const child = spawn("npm", ["install", "-g", "express-file-cluster"], {
3221
+ stdio: "ignore"
3222
+ });
3223
+ child.on(
3224
+ "exit",
3225
+ (code) => code === 0 ? resolve() : reject(new Error("global install failed"))
3226
+ );
3155
3227
  });
3156
3228
  }
3157
3229
  main().catch((err) => {