@donotdev/cli 0.0.14 → 0.0.15

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 (151) hide show
  1. package/dependencies-matrix.json +356 -88
  2. package/dist/bin/commands/agent-setup.js +7 -1
  3. package/dist/bin/commands/build.js +118 -38
  4. package/dist/bin/commands/bump.js +74 -28
  5. package/dist/bin/commands/cacheout.js +37 -9
  6. package/dist/bin/commands/create-app.js +222 -115
  7. package/dist/bin/commands/create-project.js +455 -140
  8. package/dist/bin/commands/deploy.js +1736 -697
  9. package/dist/bin/commands/dev.js +138 -23
  10. package/dist/bin/commands/emu.js +215 -58
  11. package/dist/bin/commands/format.js +37 -9
  12. package/dist/bin/commands/lint.js +37 -9
  13. package/dist/bin/commands/preview.js +142 -23
  14. package/dist/bin/commands/supabase-setup.d.ts +6 -0
  15. package/dist/bin/commands/supabase-setup.d.ts.map +1 -0
  16. package/dist/bin/commands/supabase-setup.js +7 -0
  17. package/dist/bin/commands/supabase-setup.js.map +1 -0
  18. package/dist/bin/commands/sync-secrets.js +211 -34
  19. package/dist/bin/commands/type-check.d.ts +14 -0
  20. package/dist/bin/commands/type-check.d.ts.map +1 -0
  21. package/dist/bin/commands/type-check.js +314 -0
  22. package/dist/bin/commands/type-check.js.map +1 -0
  23. package/dist/bin/commands/wai.js +3 -1
  24. package/dist/bin/dndev.js +27 -2
  25. package/dist/bin/donotdev.js +27 -2
  26. package/dist/index.js +3960 -3015
  27. package/package.json +2 -2
  28. package/templates/app-demo/src/App.tsx.example +1 -0
  29. package/templates/app-demo/src/pages/FullPage.tsx.example +2 -2
  30. package/templates/app-demo/src/pages/components/DemoLayout.tsx.example +2 -2
  31. package/templates/app-demo/src/themes.css.example +5 -12
  32. package/templates/app-expo/.env.example +64 -0
  33. package/templates/app-expo/.expo/README.md.example +5 -0
  34. package/templates/app-expo/.gitignore.example +36 -0
  35. package/templates/app-expo/README.md.example +58 -0
  36. package/templates/app-expo/app/.gitkeep +2 -0
  37. package/templates/app-expo/app/_layout.tsx.example +41 -0
  38. package/templates/app-expo/app/form.tsx.example +52 -0
  39. package/templates/app-expo/app/index.tsx.example +89 -0
  40. package/templates/app-expo/app/list.tsx.example +32 -0
  41. package/templates/app-expo/app/profile.tsx.example +76 -0
  42. package/templates/app-expo/app/signin.tsx.example +53 -0
  43. package/templates/app-expo/app.json.example +39 -0
  44. package/templates/app-expo/babel.config.js.example +10 -0
  45. package/templates/app-expo/eas.json.example +20 -0
  46. package/templates/app-expo/expo-env.d.ts.example +4 -0
  47. package/templates/app-expo/metro.config.js.example +20 -0
  48. package/templates/app-expo/service-account-key.json.example +12 -0
  49. package/templates/app-expo/tsconfig.json.example +19 -0
  50. package/templates/app-next/.env.example +4 -33
  51. package/templates/app-next/src/app/ClientLayout.tsx.example +2 -0
  52. package/templates/app-next/src/app/layout.tsx.example +7 -6
  53. package/templates/app-next/src/globals.css.example +2 -11
  54. package/templates/app-next/src/pages/HomePage.tsx.example +1 -1
  55. package/templates/app-next/src/themes.css.example +10 -13
  56. package/templates/app-vite/.env.example +3 -32
  57. package/templates/app-vite/index.html.example +2 -24
  58. package/templates/app-vite/src/App.tsx.example +2 -0
  59. package/templates/app-vite/src/globals.css.example +2 -12
  60. package/templates/app-vite/src/pages/FormPageExample.tsx.example +1 -2
  61. package/templates/app-vite/src/pages/HomePage.tsx.example +1 -1
  62. package/templates/app-vite/src/themes.css.example +109 -79
  63. package/templates/app-vite/vercel.json.example +11 -0
  64. package/templates/functions-firebase/build.mjs.example +2 -72
  65. package/templates/functions-firebase/functions-firebase/.env.example.example +23 -25
  66. package/templates/functions-firebase/functions-firebase/build.mjs.example +2 -72
  67. package/templates/functions-firebase/functions-firebase/tsconfig.json.example +1 -1
  68. package/templates/functions-supabase/supabase/functions/cancel-subscription/index.ts.example +7 -0
  69. package/templates/functions-supabase/supabase/functions/change-plan/index.ts.example +11 -0
  70. package/templates/functions-supabase/supabase/functions/create-checkout-session/index.ts.example +11 -0
  71. package/templates/functions-supabase/supabase/functions/create-customer-portal/index.ts.example +7 -0
  72. package/templates/functions-supabase/supabase/functions/crud/index.ts.example +16 -0
  73. package/templates/functions-supabase/supabase/functions/delete-account/index.ts.example +7 -0
  74. package/templates/functions-supabase/supabase/functions/get-custom-claims/index.ts.example +7 -0
  75. package/templates/functions-supabase/supabase/functions/get-user-auth-status/index.ts.example +7 -0
  76. package/templates/functions-supabase/supabase/functions/refresh-subscription-status/index.ts.example +7 -0
  77. package/templates/functions-supabase/supabase/functions/remove-custom-claims/index.ts.example +7 -0
  78. package/templates/functions-supabase/supabase/functions/set-custom-claims/index.ts.example +7 -0
  79. package/templates/functions-supabase/supabase/migrations/20250101000000_idempotency.sql +24 -0
  80. package/templates/functions-supabase/supabase/migrations/20250101000001_rate_limits.sql +22 -0
  81. package/templates/functions-supabase/supabase/migrations/20250101000002_cleanup_jobs.sql +28 -0
  82. package/templates/functions-supabase/supabase/migrations/20250101000003_operation_metrics.sql +28 -0
  83. package/templates/functions-vercel/functions-vercel/tsconfig.json.example +1 -1
  84. package/templates/functions-vercel/functions-vercel/vercel.json.example +1 -1
  85. package/templates/functions-vercel/vercel.json.example +1 -1
  86. package/templates/github/github/workflows/firebase-deploy.yml.example +1 -1
  87. package/templates/github/workflows/firebase-deploy.yml.example +1 -1
  88. package/templates/overlay-firebase/env.fragment.example +34 -0
  89. package/templates/overlay-firebase/env.fragment.expo.example +34 -0
  90. package/templates/overlay-firebase/env.fragment.nextjs.example +34 -0
  91. package/templates/overlay-firebase/src/config/providers.expo.ts.example +49 -0
  92. package/templates/overlay-firebase/src/config/providers.ts.example +23 -0
  93. package/templates/overlay-supabase/env.fragment.example +7 -0
  94. package/templates/overlay-supabase/env.fragment.expo.example +7 -0
  95. package/templates/overlay-supabase/env.fragment.nextjs.example +7 -0
  96. package/templates/overlay-supabase/src/config/providers.expo.ts.example +35 -0
  97. package/templates/overlay-supabase/src/config/providers.ts.example +33 -0
  98. package/templates/overlay-supabase/vercel.headers.example +23 -0
  99. package/templates/overlay-supabase/vercel.json.example +22 -0
  100. package/templates/overlay-vercel/env.fragment.example +34 -0
  101. package/templates/overlay-vercel/env.fragment.nextjs.example +34 -0
  102. package/templates/overlay-vercel/src/config/providers.ts.example +24 -0
  103. package/templates/root-consumer/.claude/agents/architect.md.example +2 -310
  104. package/templates/root-consumer/.claude/agents/builder.md.example +2 -326
  105. package/templates/root-consumer/.claude/agents/coder.md.example +2 -83
  106. package/templates/root-consumer/.claude/agents/extractor.md.example +2 -231
  107. package/templates/root-consumer/.claude/agents/polisher.md.example +2 -132
  108. package/templates/root-consumer/.claude/agents/prompt-engineer.md.example +2 -81
  109. package/templates/root-consumer/.claude/commands/grill.md.example +30 -0
  110. package/templates/root-consumer/.claude/commands/techdebt.md.example +28 -0
  111. package/templates/root-consumer/.clinerules.example +1 -0
  112. package/templates/root-consumer/.cursor/rules/no-docs.mdc.example +15 -0
  113. package/templates/root-consumer/.cursorrules.example +1 -0
  114. package/templates/root-consumer/.github/copilot-instructions.md.example +1 -0
  115. package/templates/root-consumer/.windsurfrules.example +1 -0
  116. package/templates/root-consumer/AI.md.example +29 -123
  117. package/templates/root-consumer/CLAUDE.md.example +1 -134
  118. package/templates/root-consumer/CONVENTIONS.md.example +1 -0
  119. package/templates/root-consumer/GEMINI.md.example +1 -0
  120. package/templates/root-consumer/firebase.json.example +1 -1
  121. package/templates/root-consumer/guides/dndev/AGENT_START_HERE.md.example +20 -0
  122. package/templates/root-consumer/guides/dndev/COMPONENTS_ADV.md.example +0 -18
  123. package/templates/root-consumer/guides/dndev/COMPONENTS_UI.md.example +1 -1
  124. package/templates/root-consumer/guides/dndev/ENV_SETUP.md.example +99 -30
  125. package/templates/root-consumer/guides/dndev/INDEX.md.example +3 -1
  126. package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +143 -12
  127. package/templates/root-consumer/guides/dndev/SETUP_FIREBASE.md.example +9 -3
  128. package/templates/root-consumer/guides/dndev/SETUP_SOC2.md.example +234 -0
  129. package/templates/root-consumer/guides/dndev/SETUP_SUPABASE.md.example +124 -0
  130. package/templates/root-consumer/guides/dndev/SETUP_THEMES.md.example +6 -2
  131. package/templates/root-consumer/guides/dndev/SETUP_VERCEL.md.example +176 -0
  132. package/templates/root-consumer/guides/dndev/USE_ROUTING.md.example +5 -9
  133. package/templates/root-consumer/guides/dndev/essences_reference.css.example +174 -0
  134. package/templates/root-consumer/guides/wai-way/agents/builder.md.example +10 -0
  135. package/templates/root-consumer/guides/wai-way/agents/extractor.md.example +25 -5
  136. package/templates/root-consumer/guides/wai-way/agents/polisher.md.example +13 -2
  137. package/templates/root-consumer/guides/wai-way/blueprints/0_brainstorm.md.example +2 -2
  138. package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +47 -11
  139. package/templates/root-consumer/guides/wai-way/blueprints/3_compose.md.example +15 -4
  140. package/templates/root-consumer/guides/wai-way/spec_template.md.example +7 -6
  141. package/templates/app-payload/.env.example +0 -28
  142. package/templates/app-payload/README.md.example +0 -233
  143. package/templates/app-payload/collections/Company.ts.example +0 -125
  144. package/templates/app-payload/collections/Hero.ts.example +0 -62
  145. package/templates/app-payload/collections/Media.ts.example +0 -41
  146. package/templates/app-payload/collections/Products.ts.example +0 -115
  147. package/templates/app-payload/collections/Services.ts.example +0 -104
  148. package/templates/app-payload/collections/Testimonials.ts.example +0 -92
  149. package/templates/app-payload/collections/Users.ts.example +0 -35
  150. package/templates/app-payload/src/server.ts.example +0 -79
  151. package/templates/app-payload/tsconfig.json.example +0 -24
@@ -7884,16 +7884,19 @@ function getBinPath(binaryName) {
7884
7884
  return binaryName;
7885
7885
  }
7886
7886
  function detectExecutionMode() {
7887
- const fileUrlPath = new URL(import.meta.url).pathname;
7888
- if (!fileUrlPath.includes("node_modules")) {
7889
- return "development";
7887
+ const fileUrlPath = fileURLToPath2(import.meta.url);
7888
+ if (fileUrlPath.includes("node_modules")) {
7889
+ return "published";
7890
7890
  }
7891
- return "published";
7891
+ if (fileUrlPath.includes("/dist/")) {
7892
+ return "published";
7893
+ }
7894
+ return "development";
7892
7895
  }
7893
7896
  function getTemplatesRoot() {
7894
7897
  const mode = detectExecutionMode();
7895
7898
  if (mode === "development") {
7896
- const fileUrlPath = new URL(import.meta.url).pathname;
7899
+ const fileUrlPath = fileURLToPath2(import.meta.url);
7897
7900
  const frameworkRoot = normalizePath(dirname2(fileUrlPath), "../../../..");
7898
7901
  return normalizePath(frameworkRoot, PACKAGE_PATHS.CLI, "templates");
7899
7902
  } else {
@@ -8173,18 +8176,7 @@ var init_utils = __esm({
8173
8176
  }
8174
8177
  });
8175
8178
 
8176
- // packages/cli/src/bin/commands/create-app.ts
8177
- init_utils();
8178
-
8179
- // packages/tooling/src/index.ts
8180
- init_utils();
8181
-
8182
- // packages/tooling/src/cli/index.ts
8183
- init_utils();
8184
-
8185
8179
  // packages/tooling/src/utils/cli-input.ts
8186
- init_utils();
8187
- init_dist2();
8188
8180
  async function askForInput(message, defaultValue = "") {
8189
8181
  const result = await he({
8190
8182
  message,
@@ -8225,6 +8217,22 @@ async function askForSelection(message, choices, defaultValue = 0) {
8225
8217
  }
8226
8218
  return result;
8227
8219
  }
8220
+ var init_cli_input = __esm({
8221
+ "packages/tooling/src/utils/cli-input.ts"() {
8222
+ "use strict";
8223
+ init_utils();
8224
+ init_dist2();
8225
+ }
8226
+ });
8227
+
8228
+ // packages/cli/src/bin/commands/create-app.ts
8229
+ init_utils();
8230
+
8231
+ // packages/tooling/src/index.ts
8232
+ init_utils();
8233
+
8234
+ // packages/tooling/src/cli/index.ts
8235
+ init_utils();
8228
8236
 
8229
8237
  // packages/tooling/src/utils/create-utils.ts
8230
8238
  init_utils();
@@ -8460,6 +8468,10 @@ var APP_QUESTIONNAIRE = [
8460
8468
  {
8461
8469
  title: "Next.js \u2014 Static content/SEO (SSR, SSG) \u2014 BETA",
8462
8470
  value: "nextjs"
8471
+ },
8472
+ {
8473
+ title: "Expo \u2014 Mobile app (iOS + Android)",
8474
+ value: "expo"
8463
8475
  }
8464
8476
  ]
8465
8477
  },
@@ -8486,6 +8498,10 @@ var APP_QUESTIONNAIRE = [
8486
8498
  {
8487
8499
  title: "Vercel \u2014 Serverless functions (edge + node.js)",
8488
8500
  value: "vercel"
8501
+ },
8502
+ {
8503
+ title: "Supabase \u2014 Postgres + Auth + Storage",
8504
+ value: "supabase"
8489
8505
  }
8490
8506
  ]
8491
8507
  }
@@ -8552,6 +8568,7 @@ async function runQuestionnaire(questions, initialAnswers, showWIP, askFor) {
8552
8568
 
8553
8569
  // packages/tooling/src/scaffolding/create-app.ts
8554
8570
  init_utils();
8571
+ init_cli_input();
8555
8572
  init_cli_output();
8556
8573
 
8557
8574
  // packages/tooling/src/utils/dependency-resolver.ts
@@ -8585,6 +8602,15 @@ function generateScripts(templateName, options) {
8585
8602
  scripts.preview = "next start";
8586
8603
  scripts.lint = "eslint src/";
8587
8604
  scripts["type-check"] = "tsc --noEmit";
8605
+ } else if (templateName.includes("expo")) {
8606
+ scripts.dev = "expo start";
8607
+ scripts.start = "expo start";
8608
+ scripts.android = "expo start --android";
8609
+ scripts.ios = "expo start --ios";
8610
+ scripts.web = "expo start --web";
8611
+ scripts.build = "expo export";
8612
+ scripts.lint = "eslint .";
8613
+ scripts["type-check"] = "tsc --noEmit";
8588
8614
  } else if (templateName === "consumer-root") {
8589
8615
  scripts.dev = "turbo run dev";
8590
8616
  scripts.build = "turbo run build";
@@ -8673,7 +8699,7 @@ function generatePackageJson(templateName, mode, options = {}) {
8673
8699
  result.main = "./index.ts";
8674
8700
  result.types = "./index.ts";
8675
8701
  }
8676
- if (templateName.includes("vite") || templateName.includes("nextjs") || templateName.includes("functions")) {
8702
+ if (templateName.includes("vite") || templateName.includes("nextjs") || templateName.includes("expo") || templateName.includes("functions")) {
8677
8703
  if (!dependencies.entities) {
8678
8704
  dependencies.entities = "workspace:*";
8679
8705
  }
@@ -8721,6 +8747,40 @@ function generatePackageJson(templateName, mode, options = {}) {
8721
8747
  // packages/tooling/src/scaffolding/create-app.ts
8722
8748
  init_pathResolver();
8723
8749
  init_pathResolver();
8750
+
8751
+ // packages/tooling/src/scaffolding/scaffold-matrix.ts
8752
+ init_utils();
8753
+ var MATRIX = [
8754
+ { builder: "vite", backend: "none", baseTemplate: "app-vite", overlay: null, deployConfig: null, functionsTemplate: null },
8755
+ { builder: "vite", backend: "firebase", baseTemplate: "app-vite", overlay: "overlay-firebase", deployConfig: "firebase", functionsTemplate: "functions-firebase" },
8756
+ { builder: "vite", backend: "supabase", baseTemplate: "app-vite", overlay: "overlay-supabase", deployConfig: "vercel-supabase", functionsTemplate: null },
8757
+ { builder: "vite", backend: "vercel", baseTemplate: "app-vite", overlay: "overlay-vercel", deployConfig: "vercel-vercel", functionsTemplate: "functions-vercel" },
8758
+ { builder: "nextjs", backend: "none", baseTemplate: "app-next", overlay: null, deployConfig: null, functionsTemplate: null },
8759
+ { builder: "nextjs", backend: "firebase", baseTemplate: "app-next", overlay: "overlay-firebase", deployConfig: "firebase", functionsTemplate: "functions-firebase" },
8760
+ { builder: "nextjs", backend: "supabase", baseTemplate: "app-next", overlay: "overlay-supabase", deployConfig: "vercel-supabase", functionsTemplate: null },
8761
+ { builder: "nextjs", backend: "vercel", baseTemplate: "app-next", overlay: "overlay-vercel", deployConfig: "vercel-vercel", functionsTemplate: "functions-vercel" },
8762
+ { builder: "expo", backend: "none", baseTemplate: "app-expo", overlay: null, deployConfig: null, functionsTemplate: null },
8763
+ { builder: "expo", backend: "firebase", baseTemplate: "app-expo", overlay: "overlay-firebase", deployConfig: null, functionsTemplate: "functions-firebase" },
8764
+ { builder: "expo", backend: "supabase", baseTemplate: "app-expo", overlay: "overlay-supabase", deployConfig: null, functionsTemplate: null },
8765
+ { builder: "demo", backend: "none", baseTemplate: "app-demo", overlay: null, deployConfig: null, functionsTemplate: null }
8766
+ ];
8767
+ function comboKey(builder, backend) {
8768
+ return `${builder}-${backend}`;
8769
+ }
8770
+ var ROWS_BY_KEY = /* @__PURE__ */ new Map();
8771
+ for (const row of MATRIX) {
8772
+ ROWS_BY_KEY.set(comboKey(row.builder, row.backend), row);
8773
+ }
8774
+ function getScaffoldRow(builder, backend) {
8775
+ const key = comboKey(builder, backend);
8776
+ const row = ROWS_BY_KEY.get(key);
8777
+ if (!row) {
8778
+ throw new Error(`Unsupported scaffold combo: ${key}. Supported: ${[...ROWS_BY_KEY.keys()].join(", ")}`);
8779
+ }
8780
+ return row;
8781
+ }
8782
+
8783
+ // packages/tooling/src/scaffolding/create-app.ts
8724
8784
  var SHOW_WIP = process.env.SHOW_WIP === "true" || process.argv.includes("--wip");
8725
8785
  async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
8726
8786
  const isInteractive = !appName || !appConfig;
@@ -8806,14 +8866,19 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
8806
8866
  const s = Y2();
8807
8867
  s.start(`Creating app: ${appName}`);
8808
8868
  await ensureDir(appDir);
8809
- const templateDir = appTemplate === "demo" ? "app-demo" : appTemplate === "nextjs" ? "app-next" : "app-vite";
8869
+ const builder = appTemplate;
8870
+ const backend = appConfig.needsBackend && appConfig.backendPlatform ? appConfig.backendPlatform : "none";
8871
+ const row = getScaffoldRow(builder, backend);
8872
+ const templateDir = row.baseTemplate;
8810
8873
  const firebaseProjectId = (appConfig?.firebaseProjectId ?? "").trim() || appName.toLowerCase().replace(/\s+/g, "-");
8811
8874
  const firebaseRegion = appConfig?.firebaseRegion ?? "europe-west1";
8875
+ const backendPlatform = appConfig.backendPlatform ?? "firebase";
8876
+ const deployConfig = row.deployConfig;
8812
8877
  const replacements = {
8813
8878
  projectName: appName,
8814
8879
  appName,
8815
8880
  appShortName: appName.toUpperCase().replace(/-/g, " "),
8816
- includeFunctions: Boolean(appConfig.needsBackend),
8881
+ includeFunctions: Boolean(row.functionsTemplate),
8817
8882
  needsCRUD: Boolean(appConfig.needsCRUD),
8818
8883
  setupGithubActions: false,
8819
8884
  appNames: [appName],
@@ -8823,8 +8888,13 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
8823
8888
  monorepoRelativePath: "../../packages/tooling",
8824
8889
  appTemplate,
8825
8890
  isNextjs: appTemplate === "nextjs",
8891
+ isExpo: appTemplate === "expo",
8826
8892
  YOUR_FIREBASE_PROJECT_ID: firebaseProjectId,
8827
- YOUR_REGION: firebaseRegion
8893
+ YOUR_REGION: firebaseRegion,
8894
+ backendPlatform,
8895
+ isFirebase: backendPlatform === "firebase",
8896
+ isSupabase: backendPlatform === "supabase",
8897
+ isVercel: backendPlatform === "vercel"
8828
8898
  };
8829
8899
  const templateSourceDir = joinPath(templatesRoot, templateDir);
8830
8900
  const templateFiles = await glob("**/*", {
@@ -8845,118 +8915,155 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
8845
8915
  await replacePlaceholders(destPath, replacements);
8846
8916
  }
8847
8917
  }
8918
+ if (row.overlay) {
8919
+ const overlayDir = joinPath(templatesRoot, row.overlay);
8920
+ if (pathExists(overlayDir)) {
8921
+ const overlayFiles = await glob("**/*", {
8922
+ cwd: overlayDir,
8923
+ dot: true,
8924
+ onlyFiles: true
8925
+ });
8926
+ for (const file of overlayFiles) {
8927
+ if (file.startsWith("env.fragment")) continue;
8928
+ if (file === "vercel.headers.example") continue;
8929
+ if (file === "vercel.json.example") continue;
8930
+ if (file === "src/config/providers.ts.example") {
8931
+ const variantFile = `src/config/providers.${appTemplate}.ts.example`;
8932
+ if (overlayFiles.includes(variantFile)) continue;
8933
+ }
8934
+ const providersVariant = file.match(/^src\/config\/providers\.(\w+)\.ts\.example$/);
8935
+ if (providersVariant) {
8936
+ if (providersVariant[1] !== appTemplate) continue;
8937
+ const destPath2 = joinPath(appDir, "src/config/providers.ts");
8938
+ await ensureDir(getDirname(destPath2));
8939
+ await copy(joinPath(overlayDir, file), destPath2);
8940
+ if (await isTextFile(destPath2)) await replacePlaceholders(destPath2, replacements);
8941
+ continue;
8942
+ }
8943
+ const sourcePath = joinPath(overlayDir, file);
8944
+ let destFileName = file;
8945
+ if (destFileName.endsWith(".example")) {
8946
+ destFileName = destFileName.slice(0, -8);
8947
+ }
8948
+ const destPath = joinPath(appDir, destFileName);
8949
+ await ensureDir(getDirname(destPath));
8950
+ await copy(sourcePath, destPath);
8951
+ if (await isTextFile(destPath)) {
8952
+ await replacePlaceholders(destPath, replacements);
8953
+ }
8954
+ }
8955
+ const fragmentName = appTemplate === "nextjs" ? "env.fragment.nextjs.example" : appTemplate === "expo" ? "env.fragment.expo.example" : "env.fragment.example";
8956
+ const fragmentPath = joinPath(overlayDir, fragmentName);
8957
+ const envPath = joinPath(appDir, ".env");
8958
+ if (pathExists(fragmentPath) && pathExists(envPath)) {
8959
+ const baseEnv = readSync(envPath);
8960
+ const fragment = readSync(fragmentPath);
8961
+ await write(envPath, baseEnv + "\n" + fragment, { overwrite: true });
8962
+ }
8963
+ if (deployConfig === "vercel-supabase") {
8964
+ const vercelPath = joinPath(appDir, "vercel.json");
8965
+ const headersFragmentPath = joinPath(overlayDir, "vercel.headers.example");
8966
+ const fullVercelPath = joinPath(overlayDir, "vercel.json.example");
8967
+ if (pathExists(vercelPath) && pathExists(headersFragmentPath)) {
8968
+ const vercelJson = readSync(vercelPath, { format: "json" });
8969
+ const headersFragment = readSync(headersFragmentPath, { format: "json" });
8970
+ vercelJson.headers = [...vercelJson.headers ?? [], ...headersFragment];
8971
+ await write(vercelPath, vercelJson, { format: "json", overwrite: true });
8972
+ } else if (pathExists(fullVercelPath)) {
8973
+ await copy(fullVercelPath, vercelPath);
8974
+ if (await isTextFile(vercelPath)) await replacePlaceholders(vercelPath, replacements);
8975
+ }
8976
+ }
8977
+ }
8978
+ }
8848
8979
  const executionMode = detectExecutionMode();
8849
8980
  const templateName = appTemplate === "demo" ? "demo" : executionMode === "development" ? `dev-${appTemplate}` : `consumer-${appTemplate}`;
8850
8981
  const packageJson = generatePackageJson(templateName, executionMode, {
8851
8982
  appName,
8852
8983
  template: appTemplate === "demo" ? "vite" : appTemplate,
8853
- includeFunctions: Boolean(appConfig.needsBackend)
8984
+ includeFunctions: Boolean(row.functionsTemplate),
8985
+ platform: appTemplate === "demo" ? void 0 : backendPlatform
8854
8986
  });
8855
8987
  const packageJsonPath = joinPath(appDir, "package.json");
8856
8988
  await write(packageJsonPath, packageJson, {
8857
8989
  format: "json",
8858
8990
  overwrite: true
8859
8991
  });
8860
- if (appConfig.needsBackend && appConfig.backendPlatform) {
8861
- const platform = appConfig.backendPlatform;
8992
+ if (row.functionsTemplate) {
8862
8993
  const functionsRootDir = joinPath(appDir, "functions");
8863
- const functionsTemplateName = `functions-${platform}`;
8864
- const functionsPackageJson = generatePackageJson(
8865
- functionsTemplateName,
8866
- executionMode,
8867
- {
8868
- appName,
8869
- platform
8870
- }
8871
- );
8872
- const packageJsonPath2 = joinPath(functionsRootDir, "package.json");
8873
- await ensureDir(functionsRootDir);
8874
- await write(packageJsonPath2, functionsPackageJson, {
8875
- format: "json",
8876
- overwrite: true
8877
- });
8878
- const templateSourceDir2 = joinPath(
8879
- templatesRoot,
8880
- functionsTemplateName,
8881
- functionsTemplateName
8882
- );
8883
- const fallbackTemplateDir = joinPath(templatesRoot, functionsTemplateName);
8884
- const templateDir2 = pathExists(templateSourceDir2) ? templateSourceDir2 : fallbackTemplateDir;
8885
- const templateFiles2 = await glob("**/*", {
8886
- cwd: templateDir2,
8887
- dot: true,
8888
- onlyFiles: true
8889
- });
8890
- for (const file of templateFiles2) {
8891
- if (file === "package.json.example") continue;
8892
- const sourcePath = joinPath(templateDir2, file);
8893
- let destFileName = file;
8894
- if (destFileName.endsWith(".example")) {
8895
- destFileName = destFileName.slice(0, -8);
8896
- }
8897
- const destPath = joinPath(functionsRootDir, destFileName);
8898
- await ensureDir(getDirname(destPath));
8899
- await copy(sourcePath, destPath);
8900
- if (await isTextFile(destPath)) {
8901
- await replacePlaceholders(destPath, {
8902
- ...replacements,
8903
- APP_NAME: appName
8904
- });
8994
+ const functionsTemplateName = row.functionsTemplate;
8995
+ const functionsTemplateExists = pathExists(joinPath(templatesRoot, functionsTemplateName));
8996
+ if (!functionsTemplateExists) {
8997
+ log.warn(`Functions template "${functionsTemplateName}" not found \u2014 skipping functions scaffolding.`);
8998
+ } else {
8999
+ const functionsPackageJson = generatePackageJson(
9000
+ functionsTemplateName,
9001
+ executionMode,
9002
+ { appName, platform: row.functionsTemplate.replace("functions-", "") }
9003
+ );
9004
+ const packageJsonPath2 = joinPath(functionsRootDir, "package.json");
9005
+ await ensureDir(functionsRootDir);
9006
+ await write(packageJsonPath2, functionsPackageJson, {
9007
+ format: "json",
9008
+ overwrite: true
9009
+ });
9010
+ const templateDir2 = joinPath(templatesRoot, functionsTemplateName);
9011
+ const templateFiles2 = await glob("**/*", {
9012
+ cwd: templateDir2,
9013
+ dot: true,
9014
+ onlyFiles: true
9015
+ });
9016
+ for (const file of templateFiles2) {
9017
+ if (file === "package.json.example") continue;
9018
+ const sourcePath = joinPath(templateDir2, file);
9019
+ let destFileName = file;
9020
+ if (destFileName.endsWith(".example")) {
9021
+ destFileName = destFileName.slice(0, -8);
9022
+ }
9023
+ const destPath = joinPath(functionsRootDir, destFileName);
9024
+ await ensureDir(getDirname(destPath));
9025
+ await copy(sourcePath, destPath);
9026
+ if (await isTextFile(destPath)) {
9027
+ await replacePlaceholders(destPath, {
9028
+ ...replacements,
9029
+ APP_NAME: appName
9030
+ });
9031
+ }
8905
9032
  }
8906
9033
  }
8907
9034
  }
8908
9035
  const deploymentTemplateDir = joinPath(templatesRoot, "root-consumer");
8909
- const firebaseJsonSource = joinPath(
8910
- deploymentTemplateDir,
8911
- "firebase.json.example"
8912
- );
8913
- if (pathExists(firebaseJsonSource)) {
8914
- const firebaseJsonDest = joinPath(appDir, "firebase.json");
8915
- await copy(firebaseJsonSource, firebaseJsonDest);
8916
- if (await isTextFile(firebaseJsonDest)) {
8917
- await replacePlaceholders(firebaseJsonDest, replacements);
9036
+ if (deployConfig === "firebase") {
9037
+ const firebaseJsonSource = joinPath(deploymentTemplateDir, "firebase.json.example");
9038
+ if (pathExists(firebaseJsonSource)) {
9039
+ await copy(firebaseJsonSource, joinPath(appDir, "firebase.json"));
9040
+ const firebaseJsonDest = joinPath(appDir, "firebase.json");
9041
+ if (await isTextFile(firebaseJsonDest)) await replacePlaceholders(firebaseJsonDest, replacements);
9042
+ }
9043
+ const firebasercSource = joinPath(deploymentTemplateDir, ".firebaserc.example");
9044
+ if (pathExists(firebasercSource)) {
9045
+ await copy(firebasercSource, joinPath(appDir, ".firebaserc"));
9046
+ const firebasercDest = joinPath(appDir, ".firebaserc");
9047
+ if (await isTextFile(firebasercDest)) await replacePlaceholders(firebasercDest, replacements);
9048
+ }
9049
+ if (row.functionsTemplate === "functions-firebase") {
9050
+ for (const example of ["firestore.rules.example", "firestore.indexes.json.example", "storage.rules.example"]) {
9051
+ const src = joinPath(deploymentTemplateDir, example);
9052
+ if (pathExists(src)) {
9053
+ await copy(src, joinPath(appDir, example.replace(".example", "")));
9054
+ }
9055
+ }
8918
9056
  }
8919
9057
  }
8920
- const firebasercSource = joinPath(
8921
- deploymentTemplateDir,
8922
- ".firebaserc.example"
8923
- );
8924
- if (pathExists(firebasercSource)) {
8925
- const firebasercDest = joinPath(appDir, ".firebaserc");
8926
- await copy(firebasercSource, firebasercDest);
8927
- if (await isTextFile(firebasercDest)) {
8928
- await replacePlaceholders(firebasercDest, replacements);
8929
- }
8930
- }
8931
- if (appConfig.needsBackend && appConfig.backendPlatform === "firebase") {
8932
- const rulesFiles = [
8933
- "firestore.rules.example",
8934
- "firestore.indexes.json.example",
8935
- "storage.rules.example"
8936
- ];
8937
- for (const example of rulesFiles) {
8938
- const src = joinPath(deploymentTemplateDir, example);
8939
- if (pathExists(src)) {
8940
- const destName = example.replace(".example", "");
8941
- const dest = joinPath(appDir, destName);
8942
- await copy(src, dest);
8943
- }
8944
- }
8945
- }
8946
- if (appTemplate === "nextjs" || appConfig.needsBackend && appConfig.backendPlatform === "vercel") {
8947
- const vercelJsonSource = joinPath(
8948
- deploymentTemplateDir,
8949
- "vercel.json.example"
8950
- );
9058
+ if (deployConfig === "vercel-vercel") {
9059
+ const vercelJsonSource = joinPath(deploymentTemplateDir, "vercel.json.example");
8951
9060
  if (pathExists(vercelJsonSource)) {
9061
+ await copy(vercelJsonSource, joinPath(appDir, "vercel.json"));
8952
9062
  const vercelJsonDest = joinPath(appDir, "vercel.json");
8953
- await copy(vercelJsonSource, vercelJsonDest);
8954
- if (await isTextFile(vercelJsonDest)) {
8955
- await replacePlaceholders(vercelJsonDest, replacements);
8956
- }
9063
+ if (await isTextFile(vercelJsonDest)) await replacePlaceholders(vercelJsonDest, replacements);
8957
9064
  }
8958
9065
  }
8959
- const backendInfo = appConfig.needsBackend && appConfig.backendPlatform ? ` with ${appConfig.backendPlatform} functions` : "";
9066
+ const backendInfo = row.functionsTemplate ? ` with ${row.functionsTemplate.replace("functions-", "")} functions` : "";
8960
9067
  s.stop(`Created ${appName}${backendInfo}`);
8961
9068
  const rootPackageJsonPath = joinPath(workspaceRoot, "package.json");
8962
9069
  if (pathExists(rootPackageJsonPath)) {
@@ -8968,7 +9075,7 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
8968
9075
  }
8969
9076
  if (isInteractive) {
8970
9077
  Se("\u{1F389} App created successfully!");
8971
- const firebaseStep = appConfig.needsBackend && appConfig.backendPlatform === "firebase" ? `2. Set Firebase project: cd apps/${appName} && firebase use --add (or edit .firebase rc)
9078
+ const firebaseStep = row.functionsTemplate === "functions-firebase" ? `2. Set Firebase project: cd apps/${appName} && firebase use --add (or edit .firebaserc)
8972
9079
  3. bun install
8973
9080
  4. bun run dev` : `2. bun install
8974
9081
  3. bun run dev`;
@@ -8985,8 +9092,8 @@ Happy coding!`,
8985
9092
  }
8986
9093
  async function main(options) {
8987
9094
  try {
8988
- const hasCliOptions = options?.name || options?.builder !== void 0;
8989
- if (hasCliOptions && options?.name) {
9095
+ const hasExplicitFlags = options?.builder !== void 0 || options?.functions !== void 0;
9096
+ if (hasExplicitFlags && options?.name) {
8990
9097
  const appName = options.name;
8991
9098
  const builder = options.builder || "vite";
8992
9099
  const includeFunctions = options.functions ?? false;
@@ -9001,7 +9108,7 @@ async function main(options) {
9001
9108
  );
9002
9109
  }
9003
9110
  const appConfig = {
9004
- template: builder === "next" ? "nextjs" : "vite",
9111
+ template: builder === "next" ? "nextjs" : builder === "expo" ? "expo" : "vite",
9005
9112
  needsBackend: includeFunctions,
9006
9113
  backendPlatform: includeFunctions ? "firebase" : void 0,
9007
9114
  needsCRUD: true,
@@ -9014,7 +9121,7 @@ async function main(options) {
9014
9121
  };
9015
9122
  await createApp(appName, appConfig);
9016
9123
  } else {
9017
- await createApp();
9124
+ await createApp(options?.name);
9018
9125
  }
9019
9126
  } catch (error2) {
9020
9127
  log.error("\n\u274C Error creating app:", error2);