@donotdev/cli 0.0.15 → 0.0.17

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 (83) hide show
  1. package/dependencies-matrix.json +67 -147
  2. package/dist/bin/commands/build.js +69 -52
  3. package/dist/bin/commands/bump.js +15 -14
  4. package/dist/bin/commands/create-app.js +258 -55
  5. package/dist/bin/commands/create-project.js +290 -161
  6. package/dist/bin/commands/deploy.js +146 -63
  7. package/dist/bin/commands/dev.js +43 -24
  8. package/dist/bin/commands/doctor.d.ts +6 -0
  9. package/dist/bin/commands/doctor.d.ts.map +1 -0
  10. package/dist/bin/commands/{lint.js → doctor.js} +1370 -146
  11. package/dist/bin/commands/doctor.js.map +1 -0
  12. package/dist/bin/commands/emu.js +295 -107
  13. package/dist/bin/commands/make-admin.js +77519 -11
  14. package/dist/bin/commands/preview.js +44 -25
  15. package/dist/bin/commands/setup.d.ts +6 -0
  16. package/dist/bin/commands/setup.d.ts.map +1 -0
  17. package/dist/bin/commands/setup.js +12123 -0
  18. package/dist/bin/commands/setup.js.map +1 -0
  19. package/dist/bin/commands/type-check.d.ts.map +1 -1
  20. package/dist/bin/commands/type-check.js +2022 -283
  21. package/dist/bin/commands/type-check.js.map +1 -1
  22. package/dist/bin/dndev.js +54 -58
  23. package/dist/bin/donotdev.js +54 -58
  24. package/dist/index.js +860 -459
  25. package/package.json +2 -2
  26. package/templates/app-expo/.env.example +2 -22
  27. package/templates/app-expo/README.md.example +1 -1
  28. package/templates/app-expo/assets/adaptive-icon.png +0 -0
  29. package/templates/app-expo/assets/favicon.png +0 -0
  30. package/templates/app-expo/assets/icon.png +0 -0
  31. package/templates/app-expo/assets/splash.png +0 -0
  32. package/templates/app-expo/src/config/app.ts.example +46 -0
  33. package/templates/app-expo/src/config/providers.ts.example +7 -0
  34. package/templates/app-next/src/config/providers.ts.example +7 -0
  35. package/templates/app-vite/src/config/providers.ts.example +7 -0
  36. package/templates/app-vite/src/pages/HomePage.tsx.example +1 -1
  37. package/templates/functions-firebase/README.md.example +1 -1
  38. package/templates/functions-firebase/functions-firebase/.env.example.example +1 -1
  39. package/templates/functions-firebase/functions-firebase/README.md.example +1 -1
  40. package/templates/functions-firebase/functions-firebase/tsconfig.json.example +1 -1
  41. package/templates/functions-firebase/functions.config.js.example +1 -1
  42. package/templates/functions-supabase/supabase/config.toml.example +59 -0
  43. package/templates/functions-supabase/supabase/functions/.env.example +13 -0
  44. package/templates/functions-supabase/supabase/functions/deno.json.example +8 -0
  45. package/templates/overlay-firebase/env.fragment.example +1 -1
  46. package/templates/overlay-firebase/env.fragment.expo.example +1 -1
  47. package/templates/overlay-firebase/env.fragment.nextjs.example +1 -1
  48. package/templates/overlay-supabase/env.fragment.example +8 -3
  49. package/templates/overlay-supabase/env.fragment.expo.example +8 -3
  50. package/templates/overlay-supabase/env.fragment.nextjs.example +8 -3
  51. package/templates/overlay-vercel/env.fragment.example +1 -1
  52. package/templates/overlay-vercel/env.fragment.nextjs.example +1 -1
  53. package/templates/root-consumer/AI.md.example +15 -0
  54. package/templates/root-consumer/guides/dndev/AGENT_START_HERE.md.example +2 -2
  55. package/templates/root-consumer/guides/dndev/ENV_SETUP.md.example +12 -12
  56. package/templates/root-consumer/guides/dndev/INDEX.md.example +3 -3
  57. package/templates/root-consumer/guides/dndev/SETUP_APP_CONFIG.md.example +3 -3
  58. package/templates/root-consumer/guides/dndev/SETUP_AUTH.md.example +13 -6
  59. package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +149 -988
  60. package/templates/root-consumer/guides/dndev/SETUP_FIREBASE.md.example +72 -20
  61. package/templates/root-consumer/guides/dndev/SETUP_FUNCTIONS.md.example +6 -111
  62. package/templates/root-consumer/guides/dndev/SETUP_OAUTH_PROVIDERS.md.example +60 -0
  63. package/templates/root-consumer/guides/dndev/SETUP_STRIPE.md.example +62 -0
  64. package/templates/root-consumer/guides/dndev/SETUP_SUPABASE.md.example +124 -33
  65. package/templates/root-consumer/guides/dndev/SETUP_VERCEL.md.example +108 -91
  66. package/templates/root-consumer/guides/dndev/advanced/EMULATORS.md.example +2 -2
  67. package/templates/root-consumer/guides/wai-way/WAI_WAY_CLI.md.example +7 -8
  68. package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +9 -5
  69. package/dist/bin/commands/firebase-setup.d.ts +0 -6
  70. package/dist/bin/commands/firebase-setup.d.ts.map +0 -1
  71. package/dist/bin/commands/firebase-setup.js +0 -7
  72. package/dist/bin/commands/firebase-setup.js.map +0 -1
  73. package/dist/bin/commands/lint.d.ts +0 -11
  74. package/dist/bin/commands/lint.d.ts.map +0 -1
  75. package/dist/bin/commands/lint.js.map +0 -1
  76. package/dist/bin/commands/staging.d.ts +0 -11
  77. package/dist/bin/commands/staging.d.ts.map +0 -1
  78. package/dist/bin/commands/staging.js +0 -12
  79. package/dist/bin/commands/staging.js.map +0 -1
  80. package/dist/bin/commands/supabase-setup.d.ts +0 -6
  81. package/dist/bin/commands/supabase-setup.d.ts.map +0 -1
  82. package/dist/bin/commands/supabase-setup.js +0 -7
  83. package/dist/bin/commands/supabase-setup.js.map +0 -1
@@ -8713,15 +8713,14 @@ function getMatrixPath(mode) {
8713
8713
  }
8714
8714
  const executionMode = mode || detectExecutionMode();
8715
8715
  if (executionMode === "development") {
8716
- const repoRoot = getRepoRoot();
8717
- if (repoRoot) {
8718
- const devPath = normalizePath(
8719
- repoRoot,
8720
- "packages/cli/dependencies-matrix.json"
8721
- );
8722
- if (pathExists(devPath)) {
8723
- return devPath;
8724
- }
8716
+ const templatesRoot = getTemplatesRoot();
8717
+ const devPath = normalizePath(
8718
+ templatesRoot,
8719
+ "..",
8720
+ "dependencies-matrix.json"
8721
+ );
8722
+ if (pathExists(devPath)) {
8723
+ return devPath;
8725
8724
  }
8726
8725
  }
8727
8726
  return null;
@@ -8736,8 +8735,8 @@ function getCliVersion(mode) {
8736
8735
  }
8737
8736
  const executionMode = mode || detectExecutionMode();
8738
8737
  if (executionMode === "development") {
8739
- const repoRoot = getRepoRoot();
8740
- const cliPackageJson = joinPath(repoRoot, "packages/cli/package.json");
8738
+ const templatesRoot = getTemplatesRoot();
8739
+ const cliPackageJson = normalizePath(templatesRoot, "..", "package.json");
8741
8740
  if (pathExists(cliPackageJson)) {
8742
8741
  const pkg = readSync(cliPackageJson, { format: "json" });
8743
8742
  return String(pkg?.version || "0.0.0");
@@ -9026,7 +9025,7 @@ function generatePackageJson(templateName, mode, options = {}) {
9026
9025
  }
9027
9026
  if (templateName.includes("functions")) {
9028
9027
  result.main = "lib/index.js";
9029
- result.engines = { node: "20" };
9028
+ result.engines = { node: "22" };
9030
9029
  if (options.appName) {
9031
9030
  const platform = templateName.includes("vercel") ? "Vercel" : "Firebase";
9032
9031
  result.description = `${options.appName} ${platform} Functions`;
@@ -9071,18 +9070,102 @@ init_pathResolver();
9071
9070
  // packages/tooling/src/scaffolding/scaffold-matrix.ts
9072
9071
  init_utils();
9073
9072
  var MATRIX = [
9074
- { builder: "vite", backend: "none", baseTemplate: "app-vite", overlay: null, deployConfig: null, functionsTemplate: null },
9075
- { builder: "vite", backend: "firebase", baseTemplate: "app-vite", overlay: "overlay-firebase", deployConfig: "firebase", functionsTemplate: "functions-firebase" },
9076
- { builder: "vite", backend: "supabase", baseTemplate: "app-vite", overlay: "overlay-supabase", deployConfig: "vercel-supabase", functionsTemplate: null },
9077
- { builder: "vite", backend: "vercel", baseTemplate: "app-vite", overlay: "overlay-vercel", deployConfig: "vercel-vercel", functionsTemplate: "functions-vercel" },
9078
- { builder: "nextjs", backend: "none", baseTemplate: "app-next", overlay: null, deployConfig: null, functionsTemplate: null },
9079
- { builder: "nextjs", backend: "firebase", baseTemplate: "app-next", overlay: "overlay-firebase", deployConfig: "firebase", functionsTemplate: "functions-firebase" },
9080
- { builder: "nextjs", backend: "supabase", baseTemplate: "app-next", overlay: "overlay-supabase", deployConfig: "vercel-supabase", functionsTemplate: null },
9081
- { builder: "nextjs", backend: "vercel", baseTemplate: "app-next", overlay: "overlay-vercel", deployConfig: "vercel-vercel", functionsTemplate: "functions-vercel" },
9082
- { builder: "expo", backend: "none", baseTemplate: "app-expo", overlay: null, deployConfig: null, functionsTemplate: null },
9083
- { builder: "expo", backend: "firebase", baseTemplate: "app-expo", overlay: "overlay-firebase", deployConfig: null, functionsTemplate: "functions-firebase" },
9084
- { builder: "expo", backend: "supabase", baseTemplate: "app-expo", overlay: "overlay-supabase", deployConfig: null, functionsTemplate: null },
9085
- { builder: "demo", backend: "none", baseTemplate: "app-demo", overlay: null, deployConfig: null, functionsTemplate: null }
9073
+ {
9074
+ builder: "vite",
9075
+ backend: "none",
9076
+ baseTemplate: "app-vite",
9077
+ overlay: null,
9078
+ deployConfig: null,
9079
+ functionsTemplate: null
9080
+ },
9081
+ {
9082
+ builder: "vite",
9083
+ backend: "firebase",
9084
+ baseTemplate: "app-vite",
9085
+ overlay: "overlay-firebase",
9086
+ deployConfig: "firebase",
9087
+ functionsTemplate: "functions-firebase"
9088
+ },
9089
+ {
9090
+ builder: "vite",
9091
+ backend: "supabase",
9092
+ baseTemplate: "app-vite",
9093
+ overlay: "overlay-supabase",
9094
+ deployConfig: "vercel-supabase",
9095
+ functionsTemplate: "functions-supabase"
9096
+ },
9097
+ {
9098
+ builder: "vite",
9099
+ backend: "vercel",
9100
+ baseTemplate: "app-vite",
9101
+ overlay: "overlay-vercel",
9102
+ deployConfig: "vercel-vercel",
9103
+ functionsTemplate: "functions-vercel"
9104
+ },
9105
+ {
9106
+ builder: "nextjs",
9107
+ backend: "none",
9108
+ baseTemplate: "app-next",
9109
+ overlay: null,
9110
+ deployConfig: null,
9111
+ functionsTemplate: null
9112
+ },
9113
+ {
9114
+ builder: "nextjs",
9115
+ backend: "firebase",
9116
+ baseTemplate: "app-next",
9117
+ overlay: "overlay-firebase",
9118
+ deployConfig: "firebase",
9119
+ functionsTemplate: "functions-firebase"
9120
+ },
9121
+ {
9122
+ builder: "nextjs",
9123
+ backend: "supabase",
9124
+ baseTemplate: "app-next",
9125
+ overlay: "overlay-supabase",
9126
+ deployConfig: "vercel-supabase",
9127
+ functionsTemplate: "functions-supabase"
9128
+ },
9129
+ {
9130
+ builder: "nextjs",
9131
+ backend: "vercel",
9132
+ baseTemplate: "app-next",
9133
+ overlay: "overlay-vercel",
9134
+ deployConfig: "vercel-vercel",
9135
+ functionsTemplate: "functions-vercel"
9136
+ },
9137
+ {
9138
+ builder: "expo",
9139
+ backend: "none",
9140
+ baseTemplate: "app-expo",
9141
+ overlay: null,
9142
+ deployConfig: null,
9143
+ functionsTemplate: null
9144
+ },
9145
+ {
9146
+ builder: "expo",
9147
+ backend: "firebase",
9148
+ baseTemplate: "app-expo",
9149
+ overlay: "overlay-firebase",
9150
+ deployConfig: null,
9151
+ functionsTemplate: "functions-firebase"
9152
+ },
9153
+ {
9154
+ builder: "expo",
9155
+ backend: "supabase",
9156
+ baseTemplate: "app-expo",
9157
+ overlay: "overlay-supabase",
9158
+ deployConfig: null,
9159
+ functionsTemplate: "functions-supabase"
9160
+ },
9161
+ {
9162
+ builder: "demo",
9163
+ backend: "none",
9164
+ baseTemplate: "app-demo",
9165
+ overlay: null,
9166
+ deployConfig: null,
9167
+ functionsTemplate: null
9168
+ }
9086
9169
  ];
9087
9170
  function comboKey(builder, backend) {
9088
9171
  return `${builder}-${backend}`;
@@ -9095,7 +9178,9 @@ function getScaffoldRow(builder, backend) {
9095
9178
  const key = comboKey(builder, backend);
9096
9179
  const row = ROWS_BY_KEY.get(key);
9097
9180
  if (!row) {
9098
- throw new Error(`Unsupported scaffold combo: ${key}. Supported: ${[...ROWS_BY_KEY.keys()].join(", ")}`);
9181
+ throw new Error(
9182
+ `Unsupported scaffold combo: ${key}. Supported: ${[...ROWS_BY_KEY.keys()].join(", ")}`
9183
+ );
9099
9184
  }
9100
9185
  return row;
9101
9186
  }
@@ -9251,13 +9336,16 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
9251
9336
  const variantFile = `src/config/providers.${appTemplate}.ts.example`;
9252
9337
  if (overlayFiles.includes(variantFile)) continue;
9253
9338
  }
9254
- const providersVariant = file.match(/^src\/config\/providers\.(\w+)\.ts\.example$/);
9339
+ const providersVariant = file.match(
9340
+ /^src\/config\/providers\.(\w+)\.ts\.example$/
9341
+ );
9255
9342
  if (providersVariant) {
9256
9343
  if (providersVariant[1] !== appTemplate) continue;
9257
9344
  const destPath2 = joinPath(appDir, "src/config/providers.ts");
9258
9345
  await ensureDir(getDirname(destPath2));
9259
- await copy(joinPath(overlayDir, file), destPath2);
9260
- if (await isTextFile(destPath2)) await replacePlaceholders(destPath2, replacements);
9346
+ await copy(joinPath(overlayDir, file), destPath2, { overwrite: true });
9347
+ if (await isTextFile(destPath2))
9348
+ await replacePlaceholders(destPath2, replacements);
9261
9349
  continue;
9262
9350
  }
9263
9351
  const sourcePath = joinPath(overlayDir, file);
@@ -9267,7 +9355,7 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
9267
9355
  }
9268
9356
  const destPath = joinPath(appDir, destFileName);
9269
9357
  await ensureDir(getDirname(destPath));
9270
- await copy(sourcePath, destPath);
9358
+ await copy(sourcePath, destPath, { overwrite: true });
9271
9359
  if (await isTextFile(destPath)) {
9272
9360
  await replacePlaceholders(destPath, replacements);
9273
9361
  }
@@ -9282,16 +9370,28 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
9282
9370
  }
9283
9371
  if (deployConfig === "vercel-supabase") {
9284
9372
  const vercelPath = joinPath(appDir, "vercel.json");
9285
- const headersFragmentPath = joinPath(overlayDir, "vercel.headers.example");
9373
+ const headersFragmentPath = joinPath(
9374
+ overlayDir,
9375
+ "vercel.headers.example"
9376
+ );
9286
9377
  const fullVercelPath = joinPath(overlayDir, "vercel.json.example");
9287
9378
  if (pathExists(vercelPath) && pathExists(headersFragmentPath)) {
9288
9379
  const vercelJson = readSync(vercelPath, { format: "json" });
9289
- const headersFragment = readSync(headersFragmentPath, { format: "json" });
9290
- vercelJson.headers = [...vercelJson.headers ?? [], ...headersFragment];
9291
- await write(vercelPath, vercelJson, { format: "json", overwrite: true });
9380
+ const headersFragment = readSync(headersFragmentPath, {
9381
+ format: "json"
9382
+ });
9383
+ vercelJson.headers = [
9384
+ ...vercelJson.headers ?? [],
9385
+ ...headersFragment
9386
+ ];
9387
+ await write(vercelPath, vercelJson, {
9388
+ format: "json",
9389
+ overwrite: true
9390
+ });
9292
9391
  } else if (pathExists(fullVercelPath)) {
9293
9392
  await copy(fullVercelPath, vercelPath);
9294
- if (await isTextFile(vercelPath)) await replacePlaceholders(vercelPath, replacements);
9393
+ if (await isTextFile(vercelPath))
9394
+ await replacePlaceholders(vercelPath, replacements);
9295
9395
  }
9296
9396
  }
9297
9397
  }
@@ -9310,23 +9410,33 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
9310
9410
  overwrite: true
9311
9411
  });
9312
9412
  if (row.functionsTemplate) {
9313
- const functionsRootDir = joinPath(appDir, "functions");
9314
9413
  const functionsTemplateName = row.functionsTemplate;
9315
- const functionsTemplateExists = pathExists(joinPath(templatesRoot, functionsTemplateName));
9414
+ const functionsTemplateExists = pathExists(
9415
+ joinPath(templatesRoot, functionsTemplateName)
9416
+ );
9316
9417
  if (!functionsTemplateExists) {
9317
- log.warn(`Functions template "${functionsTemplateName}" not found \u2014 skipping functions scaffolding.`);
9318
- } else {
9319
- const functionsPackageJson = generatePackageJson(
9320
- functionsTemplateName,
9321
- executionMode,
9322
- { appName, platform: row.functionsTemplate.replace("functions-", "") }
9418
+ log.warn(
9419
+ `Functions template "${functionsTemplateName}" not found \u2014 skipping functions scaffolding.`
9323
9420
  );
9324
- const packageJsonPath2 = joinPath(functionsRootDir, "package.json");
9325
- await ensureDir(functionsRootDir);
9326
- await write(packageJsonPath2, functionsPackageJson, {
9327
- format: "json",
9328
- overwrite: true
9329
- });
9421
+ } else {
9422
+ const isSupabaseFunctions = functionsTemplateName === "functions-supabase";
9423
+ const functionsRootDir = isSupabaseFunctions ? appDir : joinPath(appDir, "functions");
9424
+ if (!isSupabaseFunctions) {
9425
+ const functionsPackageJson = generatePackageJson(
9426
+ functionsTemplateName,
9427
+ executionMode,
9428
+ {
9429
+ appName,
9430
+ platform: row.functionsTemplate.replace("functions-", "")
9431
+ }
9432
+ );
9433
+ const packageJsonPath2 = joinPath(functionsRootDir, "package.json");
9434
+ await ensureDir(functionsRootDir);
9435
+ await write(packageJsonPath2, functionsPackageJson, {
9436
+ format: "json",
9437
+ overwrite: true
9438
+ });
9439
+ }
9330
9440
  const templateDir2 = joinPath(templatesRoot, functionsTemplateName);
9331
9441
  const templateFiles2 = await glob("**/*", {
9332
9442
  cwd: templateDir2,
@@ -9354,20 +9464,49 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
9354
9464
  }
9355
9465
  const deploymentTemplateDir = joinPath(templatesRoot, "root-consumer");
9356
9466
  if (deployConfig === "firebase") {
9357
- const firebaseJsonSource = joinPath(deploymentTemplateDir, "firebase.json.example");
9467
+ const firebaseJsonSource = joinPath(
9468
+ deploymentTemplateDir,
9469
+ "firebase.json.example"
9470
+ );
9358
9471
  if (pathExists(firebaseJsonSource)) {
9359
9472
  await copy(firebaseJsonSource, joinPath(appDir, "firebase.json"));
9360
9473
  const firebaseJsonDest = joinPath(appDir, "firebase.json");
9361
- if (await isTextFile(firebaseJsonDest)) await replacePlaceholders(firebaseJsonDest, replacements);
9474
+ if (await isTextFile(firebaseJsonDest))
9475
+ await replacePlaceholders(firebaseJsonDest, replacements);
9476
+ if (appTemplate === "nextjs") {
9477
+ const firebaseJson = readSync(firebaseJsonDest, {
9478
+ format: "json"
9479
+ });
9480
+ if (firebaseJson.hosting?.rewrites) {
9481
+ firebaseJson.hosting.rewrites = firebaseJson.hosting.rewrites.filter(
9482
+ (r2) => r2.destination !== "/index.html"
9483
+ );
9484
+ }
9485
+ if (firebaseJson.hosting) {
9486
+ firebaseJson.hosting.public = "out";
9487
+ }
9488
+ await write(firebaseJsonDest, firebaseJson, {
9489
+ format: "json",
9490
+ overwrite: true
9491
+ });
9492
+ }
9362
9493
  }
9363
- const firebasercSource = joinPath(deploymentTemplateDir, ".firebaserc.example");
9494
+ const firebasercSource = joinPath(
9495
+ deploymentTemplateDir,
9496
+ ".firebaserc.example"
9497
+ );
9364
9498
  if (pathExists(firebasercSource)) {
9365
9499
  await copy(firebasercSource, joinPath(appDir, ".firebaserc"));
9366
9500
  const firebasercDest = joinPath(appDir, ".firebaserc");
9367
- if (await isTextFile(firebasercDest)) await replacePlaceholders(firebasercDest, replacements);
9501
+ if (await isTextFile(firebasercDest))
9502
+ await replacePlaceholders(firebasercDest, replacements);
9368
9503
  }
9369
9504
  if (row.functionsTemplate === "functions-firebase") {
9370
- for (const example of ["firestore.rules.example", "firestore.indexes.json.example", "storage.rules.example"]) {
9505
+ for (const example of [
9506
+ "firestore.rules.example",
9507
+ "firestore.indexes.json.example",
9508
+ "storage.rules.example"
9509
+ ]) {
9371
9510
  const src = joinPath(deploymentTemplateDir, example);
9372
9511
  if (pathExists(src)) {
9373
9512
  await copy(src, joinPath(appDir, example.replace(".example", "")));
@@ -9375,12 +9514,76 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
9375
9514
  }
9376
9515
  }
9377
9516
  }
9517
+ if (!deployConfig && backend === "firebase" && row.functionsTemplate) {
9518
+ const firebaseJsonPath = joinPath(appDir, "firebase.json");
9519
+ if (!pathExists(firebaseJsonPath)) {
9520
+ const expoFirebaseJson = {
9521
+ functions: [
9522
+ {
9523
+ source: "functions",
9524
+ codebase: "default",
9525
+ ignore: [
9526
+ "node_modules",
9527
+ ".git",
9528
+ "firebase-debug.log",
9529
+ "firebase-debug.*.log",
9530
+ "**/.*",
9531
+ "**/*.test.ts",
9532
+ "**/__tests__/**"
9533
+ ],
9534
+ runtime: "nodejs22"
9535
+ }
9536
+ ],
9537
+ firestore: {
9538
+ rules: "firestore.rules",
9539
+ indexes: "firestore.indexes.json"
9540
+ },
9541
+ storage: { rules: "storage.rules" },
9542
+ emulators: {
9543
+ auth: { port: 9099 },
9544
+ functions: { port: 5001 },
9545
+ firestore: { port: 8080 },
9546
+ storage: { port: 9199 },
9547
+ ui: { enabled: true, port: 4e3 }
9548
+ }
9549
+ };
9550
+ await write(firebaseJsonPath, expoFirebaseJson, {
9551
+ format: "json",
9552
+ overwrite: true
9553
+ });
9554
+ }
9555
+ const firebasercSource = joinPath(
9556
+ deploymentTemplateDir,
9557
+ ".firebaserc.example"
9558
+ );
9559
+ const firebasercDest = joinPath(appDir, ".firebaserc");
9560
+ if (pathExists(firebasercSource) && !pathExists(firebasercDest)) {
9561
+ await copy(firebasercSource, firebasercDest);
9562
+ if (await isTextFile(firebasercDest))
9563
+ await replacePlaceholders(firebasercDest, replacements);
9564
+ }
9565
+ for (const example of [
9566
+ "firestore.rules.example",
9567
+ "firestore.indexes.json.example",
9568
+ "storage.rules.example"
9569
+ ]) {
9570
+ const src = joinPath(deploymentTemplateDir, example);
9571
+ const dest = joinPath(appDir, example.replace(".example", ""));
9572
+ if (pathExists(src) && !pathExists(dest)) {
9573
+ await copy(src, dest);
9574
+ }
9575
+ }
9576
+ }
9378
9577
  if (deployConfig === "vercel-vercel") {
9379
- const vercelJsonSource = joinPath(deploymentTemplateDir, "vercel.json.example");
9578
+ const vercelJsonSource = joinPath(
9579
+ deploymentTemplateDir,
9580
+ "vercel.json.example"
9581
+ );
9380
9582
  if (pathExists(vercelJsonSource)) {
9381
9583
  await copy(vercelJsonSource, joinPath(appDir, "vercel.json"));
9382
9584
  const vercelJsonDest = joinPath(appDir, "vercel.json");
9383
- if (await isTextFile(vercelJsonDest)) await replacePlaceholders(vercelJsonDest, replacements);
9585
+ if (await isTextFile(vercelJsonDest))
9586
+ await replacePlaceholders(vercelJsonDest, replacements);
9384
9587
  }
9385
9588
  }
9386
9589
  const backendInfo = row.functionsTemplate ? ` with ${row.functionsTemplate.replace("functions-", "")} functions` : "";
@@ -9417,23 +9620,25 @@ init_cli_input();
9417
9620
  init_cli_output();
9418
9621
  init_pathResolver();
9419
9622
  var SHOW_WIP2 = process.env.SHOW_WIP === "true" || process.argv.includes("--wip");
9420
- var BACKEND_CHOICES = [
9421
- { title: "None", value: "none" },
9422
- {
9423
- title: "Firebase \u2014 Full platform (Auth, Firestore, Storage, Functions, Hosting)",
9424
- value: "firebase"
9425
- },
9426
- {
9427
- title: "Supabase \u2014 Auth, Postgres, Storage, Functions",
9428
- value: "supabase"
9429
- },
9430
- {
9431
- title: "Vercel \u2014 Serverless functions + Hosting (e.g. Next.js API routes)",
9432
- value: "vercel"
9433
- }
9434
- ];
9435
- function getDefaultBackendIndex(framework) {
9436
- return framework === "nextjs" ? 3 : 1;
9623
+ async function collectAppConfig(appName) {
9624
+ const answers = await runQuestionnaire(APP_QUESTIONNAIRE, {}, SHOW_WIP2, {
9625
+ selection: askForSelection,
9626
+ confirmation: askForConfirmation,
9627
+ input: askForInput
9628
+ });
9629
+ const framework = answers.framework || "vite";
9630
+ const needsBackend = answers.needsBackend || false;
9631
+ const defaultPlatform = framework === "nextjs" ? "vercel" : "firebase";
9632
+ return {
9633
+ template: framework,
9634
+ needsBackend,
9635
+ backendPlatform: needsBackend ? answers.backendPlatform || defaultPlatform : void 0,
9636
+ needsCRUD: false,
9637
+ selectedEntities: [],
9638
+ userAuth: "none",
9639
+ billing: false,
9640
+ features: []
9641
+ };
9437
9642
  }
9438
9643
  function calculateRelativePath(from, to) {
9439
9644
  try {
@@ -9546,71 +9751,22 @@ async function main(options) {
9546
9751
  let appNames = [];
9547
9752
  const appConfigs = {};
9548
9753
  let anyAppNeedsBackend = false;
9549
- const firstAppName = await askForInput(
9550
- "What's your first app name? (press Enter to skip)",
9551
- ""
9552
- );
9553
- if (firstAppName && firstAppName.trim() !== "") {
9554
- const trimmedName = firstAppName.trim();
9555
- if (isReservedAppName(trimmedName)) {
9556
- log.warn(`'${trimmedName}' is reserved for framework demos.`);
9557
- } else if (!isValidFileName(trimmedName)) {
9558
- log.warn(
9559
- `Invalid app name. Use only letters, numbers, dashes (-), and underscores (_).`
9560
- );
9561
- } else {
9562
- appNames.push(trimmedName);
9563
- const framework = await askForSelection(
9564
- `Builder for "${trimmedName}"?`,
9565
- [
9566
- {
9567
- title: "Vite \u2014 SPA/SaaS (client-side rendering, fast dev)",
9568
- value: "vite"
9569
- },
9570
- {
9571
- title: "Next.js \u2014 Static content/SEO (SSR, SSG) \u2014 DoNotDev support: BETA",
9572
- value: "nextjs"
9573
- },
9574
- {
9575
- title: "Expo \u2014 Mobile app (iOS + Android, single codebase)",
9576
- value: "expo"
9577
- }
9578
- ],
9579
- 0
9580
- );
9581
- const backendValue = await askForSelection(
9582
- `Backend for "${trimmedName}"?`,
9583
- [...BACKEND_CHOICES],
9584
- getDefaultBackendIndex(framework)
9585
- );
9586
- const needsBackend = backendValue !== "none";
9587
- if (needsBackend) anyAppNeedsBackend = true;
9588
- appConfigs[trimmedName] = {
9589
- template: framework,
9590
- needsBackend,
9591
- backendPlatform: needsBackend ? backendValue : void 0,
9592
- needsCRUD: false,
9593
- selectedEntities: [],
9594
- userAuth: "none",
9595
- billing: false,
9596
- features: []
9597
- };
9598
- }
9599
- }
9600
- while (appNames.length > 0) {
9601
- const appName = await askForInput("App name (press Enter to finish)", "");
9602
- if (!appName || appName.trim() === "") {
9754
+ let isFirstApp = true;
9755
+ while (true) {
9756
+ const prompt = isFirstApp ? "What's your first app name? (press Enter to skip)" : "App name (press Enter to finish)";
9757
+ const appNameInput = await askForInput(prompt, "");
9758
+ if (!appNameInput || appNameInput.trim() === "") {
9759
+ if (isFirstApp) break;
9603
9760
  break;
9604
9761
  }
9605
- const trimmedName = appName.trim();
9762
+ const trimmedName = appNameInput.trim();
9763
+ isFirstApp = false;
9606
9764
  if (appNames.includes(trimmedName)) {
9607
9765
  log.warn(`'${trimmedName}' already exists. Choose a different name.`);
9608
9766
  continue;
9609
9767
  }
9610
9768
  if (isReservedAppName(trimmedName)) {
9611
- log.warn(
9612
- `'${trimmedName}' is reserved for framework demos. Choose a different name.`
9613
- );
9769
+ log.warn(`'${trimmedName}' is reserved for framework demos.`);
9614
9770
  continue;
9615
9771
  }
9616
9772
  if (!isValidFileName(trimmedName)) {
@@ -9620,37 +9776,10 @@ async function main(options) {
9620
9776
  continue;
9621
9777
  }
9622
9778
  appNames.push(trimmedName);
9623
- const framework = await askForSelection(
9624
- `Builder for "${trimmedName}"?`,
9625
- [
9626
- {
9627
- title: "Vite \u2014 SPA/SaaS (client-side rendering, fast dev)",
9628
- value: "vite"
9629
- },
9630
- {
9631
- title: "Next.js \u2014 Static content/SEO (SSR, SSG) \u2014 DoNotDev support: BETA",
9632
- value: "nextjs"
9633
- }
9634
- ],
9635
- 0
9636
- );
9637
- const backendValue = await askForSelection(
9638
- `Backend for "${trimmedName}"?`,
9639
- [...BACKEND_CHOICES],
9640
- getDefaultBackendIndex(framework)
9641
- );
9642
- const needsBackend = backendValue !== "none";
9643
- if (needsBackend) anyAppNeedsBackend = true;
9644
- appConfigs[trimmedName] = {
9645
- template: framework,
9646
- needsBackend,
9647
- backendPlatform: needsBackend ? backendValue : void 0,
9648
- needsCRUD: false,
9649
- selectedEntities: [],
9650
- userAuth: "none",
9651
- billing: false,
9652
- features: []
9653
- };
9779
+ Me(`Configuring "${trimmedName}"...`, "\u2699\uFE0F");
9780
+ const config = await collectAppConfig(trimmedName);
9781
+ appConfigs[trimmedName] = config;
9782
+ if (config.needsBackend) anyAppNeedsBackend = true;
9654
9783
  }
9655
9784
  let installDemoApp = await askForConfirmation(
9656
9785
  "Would you like to install the demo app? (component showcase)",