@donotdev/cli 0.0.14 → 0.0.16

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 (184) hide show
  1. package/dependencies-matrix.json +372 -88
  2. package/dist/bin/commands/agent-setup.js +7 -1
  3. package/dist/bin/commands/build.js +141 -44
  4. package/dist/bin/commands/bump.js +81 -41
  5. package/dist/bin/commands/cacheout.js +37 -9
  6. package/dist/bin/commands/create-app.js +276 -121
  7. package/dist/bin/commands/create-project.js +506 -217
  8. package/dist/bin/commands/deploy.js +1785 -694
  9. package/dist/bin/commands/dev.js +177 -43
  10. package/dist/bin/commands/doctor.d.ts +6 -0
  11. package/dist/bin/commands/doctor.d.ts.map +1 -0
  12. package/dist/bin/commands/{lint.js → doctor.js} +1215 -156
  13. package/dist/bin/commands/doctor.js.map +1 -0
  14. package/dist/bin/commands/emu.js +451 -104
  15. package/dist/bin/commands/format.js +37 -9
  16. package/dist/bin/commands/make-admin.js +77499 -11
  17. package/dist/bin/commands/preview.js +181 -43
  18. package/dist/bin/commands/setup.d.ts +6 -0
  19. package/dist/bin/commands/setup.d.ts.map +1 -0
  20. package/dist/bin/commands/setup.js +11733 -0
  21. package/dist/bin/commands/setup.js.map +1 -0
  22. package/dist/bin/commands/supabase-setup.d.ts +6 -0
  23. package/dist/bin/commands/supabase-setup.d.ts.map +1 -0
  24. package/dist/bin/commands/supabase-setup.js +7 -0
  25. package/dist/bin/commands/supabase-setup.js.map +1 -0
  26. package/dist/bin/commands/sync-secrets.js +211 -34
  27. package/dist/bin/commands/type-check.d.ts +14 -0
  28. package/dist/bin/commands/type-check.d.ts.map +1 -0
  29. package/dist/bin/commands/type-check.js +2049 -0
  30. package/dist/bin/commands/type-check.js.map +1 -0
  31. package/dist/bin/commands/wai.js +3 -1
  32. package/dist/bin/dndev.js +73 -52
  33. package/dist/bin/donotdev.js +54 -45
  34. package/dist/index.js +4212 -3050
  35. package/package.json +3 -3
  36. package/templates/app-demo/src/App.tsx.example +1 -0
  37. package/templates/app-demo/src/pages/FullPage.tsx.example +2 -2
  38. package/templates/app-demo/src/pages/components/DemoLayout.tsx.example +2 -2
  39. package/templates/app-demo/src/themes.css.example +5 -12
  40. package/templates/app-expo/.env.example +44 -0
  41. package/templates/app-expo/.expo/README.md.example +5 -0
  42. package/templates/app-expo/.gitignore.example +36 -0
  43. package/templates/app-expo/README.md.example +58 -0
  44. package/templates/app-expo/app/.gitkeep +2 -0
  45. package/templates/app-expo/app/_layout.tsx.example +41 -0
  46. package/templates/app-expo/app/form.tsx.example +52 -0
  47. package/templates/app-expo/app/index.tsx.example +89 -0
  48. package/templates/app-expo/app/list.tsx.example +32 -0
  49. package/templates/app-expo/app/profile.tsx.example +76 -0
  50. package/templates/app-expo/app/signin.tsx.example +53 -0
  51. package/templates/app-expo/app.json.example +39 -0
  52. package/templates/app-expo/assets/adaptive-icon.png +0 -0
  53. package/templates/app-expo/assets/favicon.png +0 -0
  54. package/templates/app-expo/assets/icon.png +0 -0
  55. package/templates/app-expo/assets/splash.png +0 -0
  56. package/templates/app-expo/babel.config.js.example +10 -0
  57. package/templates/app-expo/eas.json.example +20 -0
  58. package/templates/app-expo/expo-env.d.ts.example +4 -0
  59. package/templates/app-expo/metro.config.js.example +20 -0
  60. package/templates/app-expo/service-account-key.json.example +12 -0
  61. package/templates/app-expo/src/config/app.ts.example +46 -0
  62. package/templates/app-expo/src/config/providers.ts.example +7 -0
  63. package/templates/app-expo/tsconfig.json.example +19 -0
  64. package/templates/app-next/.env.example +4 -33
  65. package/templates/app-next/src/app/ClientLayout.tsx.example +2 -0
  66. package/templates/app-next/src/app/layout.tsx.example +7 -6
  67. package/templates/app-next/src/config/providers.ts.example +7 -0
  68. package/templates/app-next/src/globals.css.example +2 -11
  69. package/templates/app-next/src/pages/HomePage.tsx.example +1 -1
  70. package/templates/app-next/src/themes.css.example +10 -13
  71. package/templates/app-vite/.env.example +3 -32
  72. package/templates/app-vite/index.html.example +2 -24
  73. package/templates/app-vite/src/App.tsx.example +2 -0
  74. package/templates/app-vite/src/config/providers.ts.example +7 -0
  75. package/templates/app-vite/src/globals.css.example +2 -12
  76. package/templates/app-vite/src/pages/FormPageExample.tsx.example +1 -2
  77. package/templates/app-vite/src/pages/HomePage.tsx.example +2 -2
  78. package/templates/app-vite/src/themes.css.example +109 -79
  79. package/templates/app-vite/vercel.json.example +11 -0
  80. package/templates/functions-firebase/README.md.example +1 -1
  81. package/templates/functions-firebase/build.mjs.example +2 -72
  82. package/templates/functions-firebase/functions-firebase/.env.example.example +24 -26
  83. package/templates/functions-firebase/functions-firebase/README.md.example +1 -1
  84. package/templates/functions-firebase/functions-firebase/build.mjs.example +2 -72
  85. package/templates/functions-firebase/functions-firebase/tsconfig.json.example +1 -1
  86. package/templates/functions-firebase/functions.config.js.example +1 -1
  87. package/templates/functions-supabase/supabase/config.toml.example +59 -0
  88. package/templates/functions-supabase/supabase/functions/.env.example +13 -0
  89. package/templates/functions-supabase/supabase/functions/cancel-subscription/index.ts.example +7 -0
  90. package/templates/functions-supabase/supabase/functions/change-plan/index.ts.example +11 -0
  91. package/templates/functions-supabase/supabase/functions/create-checkout-session/index.ts.example +11 -0
  92. package/templates/functions-supabase/supabase/functions/create-customer-portal/index.ts.example +7 -0
  93. package/templates/functions-supabase/supabase/functions/crud/index.ts.example +16 -0
  94. package/templates/functions-supabase/supabase/functions/delete-account/index.ts.example +7 -0
  95. package/templates/functions-supabase/supabase/functions/deno.json.example +8 -0
  96. package/templates/functions-supabase/supabase/functions/get-custom-claims/index.ts.example +7 -0
  97. package/templates/functions-supabase/supabase/functions/get-user-auth-status/index.ts.example +7 -0
  98. package/templates/functions-supabase/supabase/functions/refresh-subscription-status/index.ts.example +7 -0
  99. package/templates/functions-supabase/supabase/functions/remove-custom-claims/index.ts.example +7 -0
  100. package/templates/functions-supabase/supabase/functions/set-custom-claims/index.ts.example +7 -0
  101. package/templates/functions-supabase/supabase/migrations/20250101000000_idempotency.sql +24 -0
  102. package/templates/functions-supabase/supabase/migrations/20250101000001_rate_limits.sql +22 -0
  103. package/templates/functions-supabase/supabase/migrations/20250101000002_cleanup_jobs.sql +28 -0
  104. package/templates/functions-supabase/supabase/migrations/20250101000003_operation_metrics.sql +28 -0
  105. package/templates/functions-vercel/functions-vercel/tsconfig.json.example +1 -1
  106. package/templates/functions-vercel/functions-vercel/vercel.json.example +1 -1
  107. package/templates/functions-vercel/vercel.json.example +1 -1
  108. package/templates/github/github/workflows/firebase-deploy.yml.example +1 -1
  109. package/templates/github/workflows/firebase-deploy.yml.example +1 -1
  110. package/templates/overlay-firebase/env.fragment.example +34 -0
  111. package/templates/overlay-firebase/env.fragment.expo.example +34 -0
  112. package/templates/overlay-firebase/env.fragment.nextjs.example +34 -0
  113. package/templates/overlay-firebase/src/config/providers.expo.ts.example +49 -0
  114. package/templates/overlay-firebase/src/config/providers.ts.example +23 -0
  115. package/templates/overlay-supabase/env.fragment.example +12 -0
  116. package/templates/overlay-supabase/env.fragment.expo.example +12 -0
  117. package/templates/overlay-supabase/env.fragment.nextjs.example +12 -0
  118. package/templates/overlay-supabase/src/config/providers.expo.ts.example +35 -0
  119. package/templates/overlay-supabase/src/config/providers.ts.example +33 -0
  120. package/templates/overlay-supabase/vercel.headers.example +23 -0
  121. package/templates/overlay-supabase/vercel.json.example +22 -0
  122. package/templates/overlay-vercel/env.fragment.example +34 -0
  123. package/templates/overlay-vercel/env.fragment.nextjs.example +34 -0
  124. package/templates/overlay-vercel/src/config/providers.ts.example +24 -0
  125. package/templates/root-consumer/.claude/agents/architect.md.example +2 -310
  126. package/templates/root-consumer/.claude/agents/builder.md.example +2 -326
  127. package/templates/root-consumer/.claude/agents/coder.md.example +2 -83
  128. package/templates/root-consumer/.claude/agents/extractor.md.example +2 -231
  129. package/templates/root-consumer/.claude/agents/polisher.md.example +2 -132
  130. package/templates/root-consumer/.claude/agents/prompt-engineer.md.example +2 -81
  131. package/templates/root-consumer/.claude/commands/grill.md.example +30 -0
  132. package/templates/root-consumer/.claude/commands/techdebt.md.example +28 -0
  133. package/templates/root-consumer/.clinerules.example +1 -0
  134. package/templates/root-consumer/.cursor/rules/no-docs.mdc.example +15 -0
  135. package/templates/root-consumer/.cursorrules.example +1 -0
  136. package/templates/root-consumer/.github/copilot-instructions.md.example +1 -0
  137. package/templates/root-consumer/.windsurfrules.example +1 -0
  138. package/templates/root-consumer/AI.md.example +44 -123
  139. package/templates/root-consumer/CLAUDE.md.example +1 -134
  140. package/templates/root-consumer/CONVENTIONS.md.example +1 -0
  141. package/templates/root-consumer/GEMINI.md.example +1 -0
  142. package/templates/root-consumer/firebase.json.example +1 -1
  143. package/templates/root-consumer/guides/dndev/AGENT_START_HERE.md.example +22 -2
  144. package/templates/root-consumer/guides/dndev/COMPONENTS_ADV.md.example +0 -18
  145. package/templates/root-consumer/guides/dndev/COMPONENTS_UI.md.example +1 -1
  146. package/templates/root-consumer/guides/dndev/ENV_SETUP.md.example +101 -32
  147. package/templates/root-consumer/guides/dndev/INDEX.md.example +4 -2
  148. package/templates/root-consumer/guides/dndev/SETUP_APP_CONFIG.md.example +3 -3
  149. package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +241 -12
  150. package/templates/root-consumer/guides/dndev/SETUP_FIREBASE.md.example +13 -7
  151. package/templates/root-consumer/guides/dndev/SETUP_OAUTH_PROVIDERS.md.example +60 -0
  152. package/templates/root-consumer/guides/dndev/SETUP_SOC2.md.example +234 -0
  153. package/templates/root-consumer/guides/dndev/SETUP_STRIPE.md.example +62 -0
  154. package/templates/root-consumer/guides/dndev/SETUP_SUPABASE.md.example +124 -0
  155. package/templates/root-consumer/guides/dndev/SETUP_THEMES.md.example +6 -2
  156. package/templates/root-consumer/guides/dndev/SETUP_VERCEL.md.example +176 -0
  157. package/templates/root-consumer/guides/dndev/USE_ROUTING.md.example +5 -9
  158. package/templates/root-consumer/guides/dndev/essences_reference.css.example +174 -0
  159. package/templates/root-consumer/guides/wai-way/WAI_WAY_CLI.md.example +7 -8
  160. package/templates/root-consumer/guides/wai-way/agents/builder.md.example +10 -0
  161. package/templates/root-consumer/guides/wai-way/agents/extractor.md.example +25 -5
  162. package/templates/root-consumer/guides/wai-way/agents/polisher.md.example +13 -2
  163. package/templates/root-consumer/guides/wai-way/blueprints/0_brainstorm.md.example +2 -2
  164. package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +55 -15
  165. package/templates/root-consumer/guides/wai-way/blueprints/3_compose.md.example +15 -4
  166. package/templates/root-consumer/guides/wai-way/spec_template.md.example +7 -6
  167. package/dist/bin/commands/lint.d.ts +0 -11
  168. package/dist/bin/commands/lint.d.ts.map +0 -1
  169. package/dist/bin/commands/lint.js.map +0 -1
  170. package/dist/bin/commands/staging.d.ts +0 -11
  171. package/dist/bin/commands/staging.d.ts.map +0 -1
  172. package/dist/bin/commands/staging.js +0 -12
  173. package/dist/bin/commands/staging.js.map +0 -1
  174. package/templates/app-payload/.env.example +0 -28
  175. package/templates/app-payload/README.md.example +0 -233
  176. package/templates/app-payload/collections/Company.ts.example +0 -125
  177. package/templates/app-payload/collections/Hero.ts.example +0 -62
  178. package/templates/app-payload/collections/Media.ts.example +0 -41
  179. package/templates/app-payload/collections/Products.ts.example +0 -115
  180. package/templates/app-payload/collections/Services.ts.example +0 -104
  181. package/templates/app-payload/collections/Testimonials.ts.example +0 -92
  182. package/templates/app-payload/collections/Users.ts.example +0 -35
  183. package/templates/app-payload/src/server.ts.example +0 -79
  184. package/templates/app-payload/tsconfig.json.example +0 -24
@@ -7594,11 +7594,39 @@ var init_PathResolver = __esm({
7594
7594
  });
7595
7595
 
7596
7596
  // packages/tooling/src/utils/errors.ts
7597
- var DoNotDevError;
7597
+ var DO_NOT_DEV_ERROR_CODES, DoNotDevError;
7598
7598
  var init_errors = __esm({
7599
7599
  "packages/tooling/src/utils/errors.ts"() {
7600
7600
  "use strict";
7601
7601
  init_utils();
7602
+ DO_NOT_DEV_ERROR_CODES = {
7603
+ CONFIGURATION_ERROR: "configuration-error",
7604
+ CONFIG_NOT_FOUND: "config-not-found",
7605
+ CONFIG_INVALID: "config-invalid",
7606
+ PATH_RESOLUTION_ERROR: "path-resolution-error",
7607
+ FILE_OPERATION_ERROR: "file-operation-error",
7608
+ FILE_NOT_FOUND: "file-not-found",
7609
+ PERMISSION_DENIED: "permission-denied",
7610
+ GENERATION_ERROR: "generation-error",
7611
+ TEMPLATE_ERROR: "template-error",
7612
+ TEMPLATE_NOT_FOUND: "template-not-found",
7613
+ CLI_EXECUTION_ERROR: "cli-execution-error",
7614
+ COMMAND_NOT_FOUND: "command-not-found",
7615
+ COMMAND_FAILED: "command-failed",
7616
+ VALIDATION_ERROR: "validation-error",
7617
+ SCHEMA_ERROR: "schema-error",
7618
+ DEPENDENCY_ERROR: "dependency-error",
7619
+ DEPENDENCY_NOT_FOUND: "dependency-not-found",
7620
+ DEPENDENCY_VERSION_ERROR: "dependency-version-error",
7621
+ INVALID_ARGUMENT: "invalid-argument",
7622
+ MISSING_ARGUMENT: "missing-argument",
7623
+ MISSING_PROJECT_ID: "missing-project-id",
7624
+ FIREBASE_CLI_ERROR: "firebase-cli-error",
7625
+ DEPLOYMENT_FAILED: "deployment-failed",
7626
+ OPERATION_CANCELLED: "operation-cancelled",
7627
+ TIMEOUT_ERROR: "timeout-error",
7628
+ UNKNOWN_ERROR: "unknown-error"
7629
+ };
7602
7630
  DoNotDevError = class _DoNotDevError extends Error {
7603
7631
  /** The error code categorizing this error */
7604
7632
  code;
@@ -7618,7 +7646,7 @@ var init_errors = __esm({
7618
7646
  * @param {Record<string, any>} [options.context] - Additional context data
7619
7647
  * @param {boolean} [options.displayable=true] - Whether this error should be displayed to the user
7620
7648
  */
7621
- constructor(message, code = "unknown-error", options) {
7649
+ constructor(message, code = DO_NOT_DEV_ERROR_CODES.UNKNOWN_ERROR, options) {
7622
7650
  super(message);
7623
7651
  this.name = "DoNotDevError";
7624
7652
  this.code = code;
@@ -7649,7 +7677,7 @@ var init_errors = __esm({
7649
7677
  * @param {boolean} [options.displayable=true] - Whether this error should be displayed to the user
7650
7678
  * @returns {DoNotDevError} New DoNotDev error wrapping the original
7651
7679
  */
7652
- static from(error2, context, code = "unknown-error", options) {
7680
+ static from(error2, context, code = DO_NOT_DEV_ERROR_CODES.UNKNOWN_ERROR, options) {
7653
7681
  if (!(error2 instanceof Error)) {
7654
7682
  return new _DoNotDevError(
7655
7683
  `Unknown error: ${String(error2)}`,
@@ -7686,21 +7714,21 @@ var init_errors = __esm({
7686
7714
  }
7687
7715
  const message = error2.message.toLowerCase();
7688
7716
  if (error2.name === "ValidationError" || message.includes("validation")) {
7689
- return "validation-error";
7717
+ return DO_NOT_DEV_ERROR_CODES.VALIDATION_ERROR;
7690
7718
  }
7691
7719
  if (message.includes("not found") || message.includes("no such file")) {
7692
- return "file-not-found";
7720
+ return DO_NOT_DEV_ERROR_CODES.FILE_NOT_FOUND;
7693
7721
  }
7694
7722
  if (message.includes("permission") || message.includes("access denied")) {
7695
- return "permission-denied";
7723
+ return DO_NOT_DEV_ERROR_CODES.PERMISSION_DENIED;
7696
7724
  }
7697
7725
  if (message.includes("timeout") || message.includes("timed out")) {
7698
- return "timeout-error";
7726
+ return DO_NOT_DEV_ERROR_CODES.TIMEOUT_ERROR;
7699
7727
  }
7700
7728
  if (message.includes("dependency") || message.includes("module not found")) {
7701
- return "dependency-error";
7729
+ return DO_NOT_DEV_ERROR_CODES.DEPENDENCY_ERROR;
7702
7730
  }
7703
- return "unknown-error";
7731
+ return DO_NOT_DEV_ERROR_CODES.UNKNOWN_ERROR;
7704
7732
  }
7705
7733
  };
7706
7734
  }
@@ -7743,6 +7771,52 @@ var init_pathResolver = __esm({
7743
7771
  }
7744
7772
  });
7745
7773
 
7774
+ // packages/tooling/src/utils/typed-file-operations.ts
7775
+ function readFirebaseJson(filePath) {
7776
+ if (!pathExists(filePath)) {
7777
+ throw new DoNotDevError(
7778
+ `firebase.json not found: ${filePath}`,
7779
+ DO_NOT_DEV_ERROR_CODES.FILE_NOT_FOUND,
7780
+ { context: { filePath } }
7781
+ );
7782
+ }
7783
+ const content = readSync(filePath, { format: "json" });
7784
+ if (!content || typeof content !== "object") {
7785
+ throw new DoNotDevError(
7786
+ `Invalid firebase.json: ${filePath}`,
7787
+ DO_NOT_DEV_ERROR_CODES.CONFIG_INVALID,
7788
+ { context: { filePath } }
7789
+ );
7790
+ }
7791
+ return content;
7792
+ }
7793
+ function readPackageJson(filePath) {
7794
+ if (!pathExists(filePath)) {
7795
+ throw new DoNotDevError(
7796
+ `package.json not found: ${filePath}`,
7797
+ DO_NOT_DEV_ERROR_CODES.FILE_NOT_FOUND,
7798
+ { context: { filePath } }
7799
+ );
7800
+ }
7801
+ const content = readSync(filePath, { format: "json" });
7802
+ if (!content || typeof content !== "object" || !("name" in content)) {
7803
+ throw new DoNotDevError(
7804
+ `Invalid package.json: ${filePath}`,
7805
+ DO_NOT_DEV_ERROR_CODES.CONFIG_INVALID,
7806
+ { context: { filePath } }
7807
+ );
7808
+ }
7809
+ return content;
7810
+ }
7811
+ var init_typed_file_operations = __esm({
7812
+ "packages/tooling/src/utils/typed-file-operations.ts"() {
7813
+ "use strict";
7814
+ init_utils();
7815
+ init_pathResolver();
7816
+ init_errors();
7817
+ }
7818
+ });
7819
+
7746
7820
  // packages/tooling/src/bundler/utils.ts
7747
7821
  import { Buffer as Buffer2 } from "node:buffer";
7748
7822
  import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "node:fs";
@@ -7770,22 +7844,7 @@ var init_utils = __esm({
7770
7844
  }
7771
7845
  });
7772
7846
 
7773
- // packages/cli/src/bin/commands/emu.ts
7774
- init_utils();
7775
-
7776
- // packages/tooling/src/index.ts
7777
- init_utils();
7778
-
7779
- // packages/tooling/src/cli/index.ts
7780
- init_utils();
7781
-
7782
- // packages/tooling/src/utils/app-selector.ts
7783
- init_utils();
7784
- init_dist2();
7785
-
7786
7847
  // packages/tooling/src/utils/app-detection.ts
7787
- init_utils();
7788
- init_pathResolver();
7789
7848
  function detectApps(projectRoot) {
7790
7849
  const apps = [];
7791
7850
  const appsDir = joinPath(projectRoot, "apps");
@@ -7806,9 +7865,7 @@ function detectApps(projectRoot) {
7806
7865
  const packageJsonPath = joinPath(projectRoot, "package.json");
7807
7866
  if (pathExists(packageJsonPath)) {
7808
7867
  try {
7809
- const packageJson = readSync(packageJsonPath, {
7810
- format: "json"
7811
- });
7868
+ const packageJson = readPackageJson(packageJsonPath);
7812
7869
  if (packageJson && (packageJson.dependencies?.vite || packageJson.devDependencies?.vite || packageJson.dependencies?.next || packageJson.devDependencies?.next)) {
7813
7870
  const pathParts = projectRoot.split(/[/\\]/);
7814
7871
  const appName = pathParts[pathParts.length - 1] || "app";
@@ -7828,10 +7885,10 @@ function analyzeApp(appPath, appName) {
7828
7885
  if (!pathExists(packageJsonPath)) {
7829
7886
  return null;
7830
7887
  }
7831
- let packageJson;
7888
+ let packageJson = null;
7832
7889
  try {
7833
- packageJson = readSync(packageJsonPath, { format: "json" });
7834
- if (!packageJson) {
7890
+ packageJson = readPackageJson(packageJsonPath);
7891
+ if (!packageJson.name) {
7835
7892
  return null;
7836
7893
  }
7837
7894
  } catch {
@@ -7846,14 +7903,23 @@ function analyzeApp(appPath, appName) {
7846
7903
  const functionsPath = joinPath(appPath, "functions");
7847
7904
  const functionsStat = statSync2(functionsPath);
7848
7905
  const hasFunctions = pathExists(functionsPath) && (functionsStat?.isDirectory() ?? false);
7849
- let platform;
7850
- if (hasFunctions) {
7851
- const firebaseJsonPath = joinPath(functionsPath, "firebase.json");
7906
+ let platform4;
7907
+ const firebaseJsonInFunctions = hasFunctions && pathExists(joinPath(functionsPath, "firebase.json"));
7908
+ const firebaseJsonInApp = pathExists(joinPath(appPath, "firebase.json"));
7909
+ if (firebaseJsonInFunctions || firebaseJsonInApp) {
7910
+ platform4 = "firebase";
7911
+ }
7912
+ if (!platform4) {
7913
+ const supabaseConfigPath = joinPath(appPath, "supabase", "config.toml");
7914
+ const hasSupabaseDep = !!(packageJson.dependencies?.["@donotdev/supabase"] || packageJson.dependencies?.["@supabase/supabase-js"]);
7915
+ if (pathExists(supabaseConfigPath) || hasSupabaseDep) {
7916
+ platform4 = "supabase";
7917
+ }
7918
+ }
7919
+ if (!platform4) {
7852
7920
  const vercelJsonPath = joinPath(appPath, "vercel.json");
7853
- if (pathExists(firebaseJsonPath)) {
7854
- platform = "firebase";
7855
- } else if (pathExists(vercelJsonPath)) {
7856
- platform = "vercel";
7921
+ if (pathExists(vercelJsonPath)) {
7922
+ platform4 = "vercel";
7857
7923
  }
7858
7924
  }
7859
7925
  return {
@@ -7864,12 +7930,19 @@ function analyzeApp(appPath, appName) {
7864
7930
  framework,
7865
7931
  hasFunctions,
7866
7932
  functionsPath: hasFunctions ? functionsPath : void 0,
7867
- platform
7933
+ platform: platform4
7868
7934
  };
7869
7935
  }
7936
+ var init_app_detection = __esm({
7937
+ "packages/tooling/src/utils/app-detection.ts"() {
7938
+ "use strict";
7939
+ init_utils();
7940
+ init_pathResolver();
7941
+ init_typed_file_operations();
7942
+ }
7943
+ });
7870
7944
 
7871
7945
  // packages/tooling/src/utils/app-selector.ts
7872
- init_cli_output();
7873
7946
  async function selectApp(projectRoot, appName) {
7874
7947
  const apps = detectApps(projectRoot);
7875
7948
  if (apps.length === 0) {
@@ -7903,10 +7976,17 @@ async function selectApp(projectRoot, appName) {
7903
7976
  }
7904
7977
  return apps.find((a) => a.name === selected) || null;
7905
7978
  }
7979
+ var init_app_selector = __esm({
7980
+ "packages/tooling/src/utils/app-selector.ts"() {
7981
+ "use strict";
7982
+ init_utils();
7983
+ init_dist2();
7984
+ init_app_detection();
7985
+ init_cli_output();
7986
+ }
7987
+ });
7906
7988
 
7907
7989
  // packages/tooling/src/utils/cli-input.ts
7908
- init_utils();
7909
- init_dist2();
7910
7990
  async function askForMultiSelection(message, choices, defaultIndices = []) {
7911
7991
  const options = choices.map((choice) => ({
7912
7992
  value: choice.value,
@@ -7925,6 +8005,22 @@ async function askForMultiSelection(message, choices, defaultIndices = []) {
7925
8005
  }
7926
8006
  return result;
7927
8007
  }
8008
+ var init_cli_input = __esm({
8009
+ "packages/tooling/src/utils/cli-input.ts"() {
8010
+ "use strict";
8011
+ init_utils();
8012
+ init_dist2();
8013
+ }
8014
+ });
8015
+
8016
+ // packages/cli/src/bin/commands/emu.ts
8017
+ init_utils();
8018
+
8019
+ // packages/tooling/src/index.ts
8020
+ init_utils();
8021
+
8022
+ // packages/tooling/src/cli/index.ts
8023
+ init_utils();
7928
8024
 
7929
8025
  // packages/tooling/src/utils/spawn-utils.ts
7930
8026
  init_utils();
@@ -7970,16 +8066,29 @@ function createEmulatorEnv(appPath, framework = "vite", options) {
7970
8066
 
7971
8067
  // packages/tooling/src/apps/emu.ts
7972
8068
  init_utils();
7973
- import { spawnSync as spawnSync2, execSync as execSync2 } from "node:child_process";
8069
+ init_app_selector();
7974
8070
  init_cli_output();
7975
8071
  init_errors();
7976
8072
  init_pathResolver();
8073
+
8074
+ // packages/tooling/src/apps/emu-firebase.ts
8075
+ init_utils();
8076
+ init_cli_input();
8077
+ init_cli_output();
7977
8078
  init_pathResolver();
8079
+ init_typed_file_operations();
8080
+ import {
8081
+ spawn,
8082
+ spawnSync as spawnSync2,
8083
+ execSync as execSync2
8084
+ } from "node:child_process";
8085
+ import { platform } from "node:os";
7978
8086
  function discoverFirebaseProjectId(appPath) {
7979
8087
  const firebasercPath = joinPath(appPath, ".firebaserc");
7980
8088
  if (pathExists(firebasercPath)) {
7981
8089
  try {
7982
- const firebaserc = readSync(firebasercPath, { format: "json" });
8090
+ const firebasercRaw = readSync(firebasercPath, { format: "json" });
8091
+ const firebaserc = firebasercRaw && typeof firebasercRaw === "object" ? firebasercRaw : null;
7983
8092
  if (firebaserc?.projects?.default) {
7984
8093
  return firebaserc.projects.default;
7985
8094
  }
@@ -8005,7 +8114,7 @@ function killPorts(ports) {
8005
8114
  pids.add(match[1]);
8006
8115
  }
8007
8116
  }
8008
- for (const pid of pids) {
8117
+ for (const pid of Array.from(pids)) {
8009
8118
  try {
8010
8119
  execSync2(`taskkill /F /PID ${pid}`, { stdio: "ignore" });
8011
8120
  log.debug(`Killed process ${pid} on port ${port}`);
@@ -8014,12 +8123,18 @@ function killPorts(ports) {
8014
8123
  }
8015
8124
  } else {
8016
8125
  try {
8017
- const pid = execSync2(`lsof -ti:${port}`, {
8126
+ const output = execSync2(`lsof -ti:${port}`, {
8018
8127
  encoding: "utf-8"
8019
8128
  }).trim();
8020
- if (pid) {
8021
- execSync2(`kill -9 ${pid}`, { stdio: "ignore" });
8022
- log.debug(`Killed process ${pid} on port ${port}`);
8129
+ if (output) {
8130
+ const pids = output.split("\n").filter(Boolean);
8131
+ for (const pid of pids) {
8132
+ try {
8133
+ execSync2(`kill -9 ${pid}`, { stdio: "ignore" });
8134
+ log.debug(`Killed process ${pid} on port ${port}`);
8135
+ } catch {
8136
+ }
8137
+ }
8023
8138
  }
8024
8139
  } catch {
8025
8140
  }
@@ -8061,9 +8176,9 @@ function loadEnvFile(filePath) {
8061
8176
  } catch {
8062
8177
  }
8063
8178
  }
8064
- async function main(options) {
8065
- const args = process.argv.slice(2);
8066
- const debug = options?.debug ?? false;
8179
+ async function startFirebase(app, projectRoot, options = {}) {
8180
+ const debug = options.debug ?? false;
8181
+ let selectedServices = options.selectedServices ?? [];
8067
8182
  const serviceChoices = [
8068
8183
  {
8069
8184
  title: "Auth",
@@ -8086,47 +8201,6 @@ async function main(options) {
8086
8201
  hint: "Stripe webhook forwarding (for payment testing)"
8087
8202
  }
8088
8203
  ];
8089
- let selectedServices = [];
8090
- const appName = args.find(
8091
- (arg) => arg !== "emu" && arg !== "--debug" && !arg.startsWith("--")
8092
- );
8093
- if (options?.services) {
8094
- selectedServices = options.services.split(",").map((s) => s.trim());
8095
- } else {
8096
- const servicesArg = args.find((arg) => arg.startsWith("--services="));
8097
- if (servicesArg) {
8098
- const servicesList = servicesArg.split("=")[1];
8099
- if (servicesList) {
8100
- selectedServices = servicesList.split(",").map((s) => s.trim());
8101
- }
8102
- } else {
8103
- if (options?.auth || args.includes("--auth"))
8104
- selectedServices.push("auth");
8105
- if (args.includes("--functions")) selectedServices.push("functions");
8106
- if (options?.firestore || args.includes("--firestore"))
8107
- selectedServices.push("firestore");
8108
- if (options?.stripe || args.includes("--stripe"))
8109
- selectedServices.push("stripe");
8110
- }
8111
- }
8112
- const validServices = serviceChoices.map((c) => c.value);
8113
- selectedServices = selectedServices.filter((s) => validServices.includes(s));
8114
- const projectRoot = getRepoRoot();
8115
- if (!projectRoot) {
8116
- throw new DoNotDevError(
8117
- "Could not determine repository root",
8118
- "path-resolution-error"
8119
- );
8120
- }
8121
- const app = await selectApp(projectRoot, appName);
8122
- if (!app) {
8123
- return 1;
8124
- }
8125
- if (!app.hasFunctions || app.platform !== "firebase") {
8126
- log.error(`App "${app.name}" does not have Firebase functions.`);
8127
- log.error('Use "dndev dev" for apps without functions.\n');
8128
- return 1;
8129
- }
8130
8204
  log.info(`Starting Firebase emulators + dev server for ${app.name}...
8131
8205
  `);
8132
8206
  if (selectedServices.length === 0) {
@@ -8206,8 +8280,10 @@ FIREBASE_AUTH_EMULATOR_HOST=${authEmulatorHost}
8206
8280
  let emulatorConfig = null;
8207
8281
  if (pathExists(appFirebaseJson)) {
8208
8282
  try {
8209
- const firebaseConfig = readSync(appFirebaseJson, { format: "json" });
8210
- emulatorConfig = firebaseConfig?.emulators;
8283
+ const firebaseConfig = readFirebaseJson(appFirebaseJson);
8284
+ if (firebaseConfig.emulators) {
8285
+ emulatorConfig = firebaseConfig.emulators;
8286
+ }
8211
8287
  } catch {
8212
8288
  }
8213
8289
  }
@@ -8244,7 +8320,7 @@ FIREBASE_AUTH_EMULATOR_HOST=${authEmulatorHost}
8244
8320
  const concurrentlyArgs = [
8245
8321
  "--kill-others-on-fail",
8246
8322
  "--prefix-colors",
8247
- "cyan,green,yellow",
8323
+ useStripe ? "cyan,green,yellow" : "cyan,green",
8248
8324
  "--prefix",
8249
8325
  "[{name}]",
8250
8326
  "--names",
@@ -8256,21 +8332,292 @@ FIREBASE_AUTH_EMULATOR_HOST=${authEmulatorHost}
8256
8332
  const stripeWebhookUrl = `http://localhost:5001/${projectId}/${region}/stripeWebhook`;
8257
8333
  concurrentlyArgs.push(`stripe listen --forward-to ${stripeWebhookUrl}`);
8258
8334
  log.info("");
8259
- log.info("\u2705 Stripe webhook forwarding will start automatically");
8335
+ log.info("Stripe webhook forwarding will start automatically");
8260
8336
  log.info(` Webhook URL: ${stripeWebhookUrl}`);
8261
8337
  log.info(" To trigger test events, run in another terminal:");
8262
8338
  log.info(" stripe trigger checkout.session.completed");
8263
8339
  log.info("");
8264
8340
  }
8265
- const result = spawnSync2("bunx", ["concurrently", ...concurrentlyArgs], {
8266
- stdio: "inherit",
8267
- env: createEmulatorEnv(app.path, app.framework, {
8268
- useEmulatorAuth: useAuth,
8269
- useEmulatorFirestore: useFirestore
8270
- }),
8271
- cwd: app.path
8341
+ const isWindows = platform() === "win32";
8342
+ const childProcess = spawn(
8343
+ "bunx",
8344
+ ["concurrently", ...concurrentlyArgs],
8345
+ {
8346
+ stdio: "inherit",
8347
+ env: createEmulatorEnv(app.path, app.framework, {
8348
+ useEmulatorAuth: useAuth,
8349
+ useEmulatorFirestore: useFirestore
8350
+ }),
8351
+ cwd: app.path,
8352
+ shell: isWindows
8353
+ }
8354
+ );
8355
+ const SIGNAL_EXIT_CODES = {
8356
+ SIGINT: 130,
8357
+ SIGTERM: 143
8358
+ };
8359
+ const cleanup = (signal) => {
8360
+ if (!childProcess.pid) return;
8361
+ log.debug(`Received ${signal}, cleaning up processes...`);
8362
+ if (isWindows) {
8363
+ try {
8364
+ execSync2(`taskkill /F /T /PID ${childProcess.pid}`, {
8365
+ stdio: "ignore",
8366
+ timeout: 2e3
8367
+ });
8368
+ } catch {
8369
+ }
8370
+ } else {
8371
+ try {
8372
+ process.kill(childProcess.pid, signal);
8373
+ } catch {
8374
+ }
8375
+ try {
8376
+ execSync2(`pkill -P ${childProcess.pid}`, {
8377
+ stdio: "ignore",
8378
+ timeout: 1e3
8379
+ });
8380
+ } catch {
8381
+ }
8382
+ }
8383
+ };
8384
+ const signals = ["SIGINT", "SIGTERM"];
8385
+ const handlers = [];
8386
+ for (const signal of signals) {
8387
+ const handler = () => {
8388
+ cleanup(signal);
8389
+ handlers.forEach((h2) => h2());
8390
+ process.exit(SIGNAL_EXIT_CODES[signal] ?? 130);
8391
+ };
8392
+ process.on(signal, handler);
8393
+ handlers.push(() => process.removeListener(signal, handler));
8394
+ }
8395
+ return new Promise((resolve4) => {
8396
+ childProcess.on("exit", (code, signal) => {
8397
+ handlers.forEach((h2) => h2());
8398
+ if (signal) {
8399
+ log.debug(`Process killed by signal: ${signal}`);
8400
+ resolve4(SIGNAL_EXIT_CODES[signal] ?? 130);
8401
+ } else {
8402
+ resolve4(code ?? 0);
8403
+ }
8404
+ });
8405
+ childProcess.on("error", (error2) => {
8406
+ handlers.forEach((h2) => h2());
8407
+ log.error(`Failed to start Firebase emulators: ${error2.message}`);
8408
+ resolve4(1);
8409
+ });
8410
+ });
8411
+ }
8412
+
8413
+ // packages/tooling/src/apps/emu-supabase.ts
8414
+ init_utils();
8415
+ init_cli_output();
8416
+ import {
8417
+ spawn as spawn2,
8418
+ execSync as execSync3
8419
+ } from "node:child_process";
8420
+ import { platform as platform2 } from "node:os";
8421
+ function isDockerRunning() {
8422
+ try {
8423
+ execSync3("docker info", { stdio: "pipe", timeout: 5e3 });
8424
+ return true;
8425
+ } catch {
8426
+ return false;
8427
+ }
8428
+ }
8429
+ async function startSupabase(app, _projectRoot) {
8430
+ log.info(`Starting Supabase local stack + dev server for ${app.name}...
8431
+ `);
8432
+ if (!isDockerRunning()) {
8433
+ log.error("Docker is not running. Supabase local dev requires Docker.");
8434
+ log.error("Start Docker Desktop and try again.\n");
8435
+ return 1;
8436
+ }
8437
+ try {
8438
+ execSync3("supabase --version", { stdio: "pipe" });
8439
+ } catch {
8440
+ log.error("Supabase CLI not found. Install it:");
8441
+ log.error(" npm install -g supabase\n");
8442
+ return 1;
8443
+ }
8444
+ const isWindows = platform2() === "win32";
8445
+ const concurrentlyArgs = [
8446
+ "--kill-others-on-fail",
8447
+ "--prefix-colors",
8448
+ "cyan,green",
8449
+ "--prefix",
8450
+ "[{name}]",
8451
+ "--names",
8452
+ "supabase,dev",
8453
+ "supabase start",
8454
+ `bunx turbo dev --filter=${app.packageName}`
8455
+ ];
8456
+ const childProcess = spawn2(
8457
+ "bunx",
8458
+ ["concurrently", ...concurrentlyArgs],
8459
+ {
8460
+ stdio: "inherit",
8461
+ cwd: app.path,
8462
+ shell: isWindows
8463
+ }
8464
+ );
8465
+ const cleanup = () => {
8466
+ if (!childProcess.pid) return;
8467
+ if (isWindows) {
8468
+ try {
8469
+ execSync3(`taskkill /F /T /PID ${childProcess.pid}`, { stdio: "ignore", timeout: 2e3 });
8470
+ } catch {
8471
+ }
8472
+ } else {
8473
+ try {
8474
+ process.kill(childProcess.pid, "SIGTERM");
8475
+ } catch {
8476
+ }
8477
+ }
8478
+ };
8479
+ process.on("SIGINT", () => {
8480
+ cleanup();
8481
+ process.exit(130);
8482
+ });
8483
+ process.on("SIGTERM", () => {
8484
+ cleanup();
8485
+ process.exit(143);
8272
8486
  });
8273
- return result.status || 0;
8487
+ return new Promise((resolve4) => {
8488
+ childProcess.on("exit", (code) => resolve4(code ?? 0));
8489
+ childProcess.on("error", (error2) => {
8490
+ log.error(`Failed to start Supabase local dev: ${error2.message}`);
8491
+ resolve4(1);
8492
+ });
8493
+ });
8494
+ }
8495
+
8496
+ // packages/tooling/src/apps/emu-vercel.ts
8497
+ init_utils();
8498
+ init_cli_output();
8499
+ import {
8500
+ spawn as spawn3,
8501
+ execSync as execSync4
8502
+ } from "node:child_process";
8503
+ import { platform as platform3 } from "node:os";
8504
+ async function startVercel(app, _projectRoot) {
8505
+ log.info(`Starting Vercel dev server for ${app.name}...
8506
+ `);
8507
+ try {
8508
+ execSync4("vercel --version", { stdio: "pipe" });
8509
+ } catch {
8510
+ log.error("Vercel CLI not found. Install it:");
8511
+ log.error(" npm install -g vercel\n");
8512
+ return 1;
8513
+ }
8514
+ const isWindows = platform3() === "win32";
8515
+ const childProcess = spawn3(
8516
+ "vercel",
8517
+ ["dev"],
8518
+ {
8519
+ stdio: "inherit",
8520
+ cwd: app.path,
8521
+ shell: isWindows
8522
+ }
8523
+ );
8524
+ const cleanup = () => {
8525
+ if (!childProcess.pid) return;
8526
+ if (isWindows) {
8527
+ try {
8528
+ execSync4(`taskkill /F /T /PID ${childProcess.pid}`, { stdio: "ignore", timeout: 2e3 });
8529
+ } catch {
8530
+ }
8531
+ } else {
8532
+ try {
8533
+ process.kill(childProcess.pid, "SIGTERM");
8534
+ } catch {
8535
+ }
8536
+ }
8537
+ };
8538
+ process.on("SIGINT", () => {
8539
+ cleanup();
8540
+ process.exit(130);
8541
+ });
8542
+ process.on("SIGTERM", () => {
8543
+ cleanup();
8544
+ process.exit(143);
8545
+ });
8546
+ return new Promise((resolve4) => {
8547
+ childProcess.on("exit", (code) => resolve4(code ?? 0));
8548
+ childProcess.on("error", (error2) => {
8549
+ log.error(`Failed to start Vercel dev: ${error2.message}`);
8550
+ resolve4(1);
8551
+ });
8552
+ });
8553
+ }
8554
+
8555
+ // packages/tooling/src/apps/emu.ts
8556
+ async function main(options) {
8557
+ const args = process.argv.slice(2);
8558
+ const projectRoot = getRepoRoot();
8559
+ if (!projectRoot) {
8560
+ throw new DoNotDevError(
8561
+ "Could not determine repository root",
8562
+ "path-resolution-error"
8563
+ );
8564
+ }
8565
+ const appName = args.find(
8566
+ (arg) => arg !== "emu" && arg !== "--debug" && !arg.startsWith("--")
8567
+ );
8568
+ const app = await selectApp(projectRoot, appName);
8569
+ if (!app) {
8570
+ return 1;
8571
+ }
8572
+ switch (app.platform) {
8573
+ case "firebase": {
8574
+ if (!app.hasFunctions) {
8575
+ log.error(`App "${app.name}" has Firebase config but no functions directory.`);
8576
+ log.error('Use "dndev dev" for apps without backend functions.\n');
8577
+ return 1;
8578
+ }
8579
+ const selectedServices = parseFirebaseServices(args, options);
8580
+ return startFirebase(app, projectRoot, {
8581
+ debug: options?.debug ?? false,
8582
+ selectedServices
8583
+ });
8584
+ }
8585
+ case "supabase":
8586
+ return startSupabase(app, projectRoot);
8587
+ case "vercel":
8588
+ return startVercel(app, projectRoot);
8589
+ default:
8590
+ log.error(`App "${app.name}" does not have a detected backend platform.`);
8591
+ log.error(
8592
+ "Expected: firebase.json (Firebase), supabase/config.toml or @donotdev/supabase (Supabase), or vercel.json (Vercel)."
8593
+ );
8594
+ log.error('Use "dndev dev" for apps without a backend.\n');
8595
+ return 1;
8596
+ }
8597
+ }
8598
+ function parseFirebaseServices(args, options) {
8599
+ const validServices = ["auth", "functions", "firestore", "stripe"];
8600
+ let selectedServices = [];
8601
+ if (options?.services) {
8602
+ selectedServices = options.services.split(",").map((s) => s.trim());
8603
+ } else {
8604
+ const servicesArg = args.find((arg) => arg.startsWith("--services="));
8605
+ if (servicesArg) {
8606
+ const servicesList = servicesArg.split("=")[1];
8607
+ if (servicesList) {
8608
+ selectedServices = servicesList.split(",").map((s) => s.trim());
8609
+ }
8610
+ } else {
8611
+ if (options?.auth || args.includes("--auth"))
8612
+ selectedServices.push("auth");
8613
+ if (args.includes("--functions")) selectedServices.push("functions");
8614
+ if (options?.firestore || args.includes("--firestore"))
8615
+ selectedServices.push("firestore");
8616
+ if (options?.stripe || args.includes("--stripe"))
8617
+ selectedServices.push("stripe");
8618
+ }
8619
+ }
8620
+ return selectedServices.filter((s) => validServices.includes(s));
8274
8621
  }
8275
8622
  export {
8276
8623
  main