@donotdev/cli 0.0.15 → 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.
- package/dependencies-matrix.json +36 -20
- package/dist/bin/commands/build.js +69 -52
- package/dist/bin/commands/bump.js +7 -13
- package/dist/bin/commands/create-app.js +77 -29
- package/dist/bin/commands/create-project.js +109 -135
- package/dist/bin/commands/deploy.js +97 -45
- package/dist/bin/commands/dev.js +43 -24
- package/dist/bin/commands/doctor.d.ts +6 -0
- package/dist/bin/commands/doctor.d.ts.map +1 -0
- package/dist/bin/commands/{lint.js → doctor.js} +1178 -147
- package/dist/bin/commands/doctor.js.map +1 -0
- package/dist/bin/commands/emu.js +297 -107
- package/dist/bin/commands/make-admin.js +77499 -11
- package/dist/bin/commands/preview.js +44 -25
- package/dist/bin/commands/setup.d.ts +6 -0
- package/dist/bin/commands/setup.d.ts.map +1 -0
- package/dist/bin/commands/setup.js +11733 -0
- package/dist/bin/commands/setup.js.map +1 -0
- package/dist/bin/commands/type-check.js +2018 -283
- package/dist/bin/dndev.js +54 -58
- package/dist/bin/donotdev.js +28 -44
- package/dist/index.js +633 -416
- package/package.json +2 -2
- package/templates/app-expo/.env.example +2 -22
- package/templates/app-expo/README.md.example +1 -1
- package/templates/app-expo/assets/adaptive-icon.png +0 -0
- package/templates/app-expo/assets/favicon.png +0 -0
- package/templates/app-expo/assets/icon.png +0 -0
- package/templates/app-expo/assets/splash.png +0 -0
- package/templates/app-expo/src/config/app.ts.example +46 -0
- package/templates/app-expo/src/config/providers.ts.example +7 -0
- package/templates/app-next/src/config/providers.ts.example +7 -0
- package/templates/app-vite/src/config/providers.ts.example +7 -0
- package/templates/app-vite/src/pages/HomePage.tsx.example +1 -1
- package/templates/functions-firebase/README.md.example +1 -1
- package/templates/functions-firebase/functions-firebase/.env.example.example +1 -1
- package/templates/functions-firebase/functions-firebase/README.md.example +1 -1
- package/templates/functions-firebase/functions-firebase/tsconfig.json.example +1 -1
- package/templates/functions-firebase/functions.config.js.example +1 -1
- package/templates/functions-supabase/supabase/config.toml.example +59 -0
- package/templates/functions-supabase/supabase/functions/.env.example +13 -0
- package/templates/functions-supabase/supabase/functions/deno.json.example +8 -0
- package/templates/overlay-firebase/env.fragment.example +1 -1
- package/templates/overlay-firebase/env.fragment.expo.example +1 -1
- package/templates/overlay-firebase/env.fragment.nextjs.example +1 -1
- package/templates/overlay-supabase/env.fragment.example +8 -3
- package/templates/overlay-supabase/env.fragment.expo.example +8 -3
- package/templates/overlay-supabase/env.fragment.nextjs.example +8 -3
- package/templates/overlay-vercel/env.fragment.example +1 -1
- package/templates/overlay-vercel/env.fragment.nextjs.example +1 -1
- package/templates/root-consumer/AI.md.example +15 -0
- package/templates/root-consumer/guides/dndev/AGENT_START_HERE.md.example +2 -2
- package/templates/root-consumer/guides/dndev/ENV_SETUP.md.example +6 -6
- package/templates/root-consumer/guides/dndev/INDEX.md.example +2 -2
- package/templates/root-consumer/guides/dndev/SETUP_APP_CONFIG.md.example +3 -3
- package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +98 -0
- package/templates/root-consumer/guides/dndev/SETUP_FIREBASE.md.example +4 -4
- package/templates/root-consumer/guides/dndev/SETUP_OAUTH_PROVIDERS.md.example +60 -0
- package/templates/root-consumer/guides/dndev/SETUP_STRIPE.md.example +62 -0
- package/templates/root-consumer/guides/dndev/SETUP_SUPABASE.md.example +3 -3
- package/templates/root-consumer/guides/dndev/SETUP_VERCEL.md.example +2 -2
- package/templates/root-consumer/guides/wai-way/WAI_WAY_CLI.md.example +7 -8
- package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +9 -5
- package/dist/bin/commands/lint.d.ts +0 -11
- package/dist/bin/commands/lint.d.ts.map +0 -1
- package/dist/bin/commands/lint.js.map +0 -1
- package/dist/bin/commands/staging.d.ts +0 -11
- package/dist/bin/commands/staging.d.ts.map +0 -1
- package/dist/bin/commands/staging.js +0 -12
- package/dist/bin/commands/staging.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -8510,6 +8510,148 @@ var init_utils = __esm({
|
|
|
8510
8510
|
}
|
|
8511
8511
|
});
|
|
8512
8512
|
|
|
8513
|
+
// packages/tooling/src/utils/app-detection.ts
|
|
8514
|
+
function detectApps(projectRoot) {
|
|
8515
|
+
const apps = [];
|
|
8516
|
+
const appsDir = joinPath(projectRoot, "apps");
|
|
8517
|
+
const appsDirStat = statSync2(appsDir);
|
|
8518
|
+
if (pathExists(appsDir) && appsDirStat?.isDirectory()) {
|
|
8519
|
+
const appDirs = readdirSync2(appsDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name).sort();
|
|
8520
|
+
for (const appDir of appDirs) {
|
|
8521
|
+
const appPath = joinPath(appsDir, appDir);
|
|
8522
|
+
const packageJsonPath = joinPath(appPath, "package.json");
|
|
8523
|
+
if (pathExists(packageJsonPath)) {
|
|
8524
|
+
const appInfo = analyzeApp(appPath, appDir);
|
|
8525
|
+
if (appInfo) {
|
|
8526
|
+
apps.push(appInfo);
|
|
8527
|
+
}
|
|
8528
|
+
}
|
|
8529
|
+
}
|
|
8530
|
+
} else {
|
|
8531
|
+
const packageJsonPath = joinPath(projectRoot, "package.json");
|
|
8532
|
+
if (pathExists(packageJsonPath)) {
|
|
8533
|
+
try {
|
|
8534
|
+
const packageJson = readPackageJson(packageJsonPath);
|
|
8535
|
+
if (packageJson && (packageJson.dependencies?.vite || packageJson.devDependencies?.vite || packageJson.dependencies?.next || packageJson.devDependencies?.next)) {
|
|
8536
|
+
const pathParts = projectRoot.split(/[/\\]/);
|
|
8537
|
+
const appName = pathParts[pathParts.length - 1] || "app";
|
|
8538
|
+
const appInfo = analyzeApp(projectRoot, appName);
|
|
8539
|
+
if (appInfo) {
|
|
8540
|
+
apps.push(appInfo);
|
|
8541
|
+
}
|
|
8542
|
+
}
|
|
8543
|
+
} catch {
|
|
8544
|
+
}
|
|
8545
|
+
}
|
|
8546
|
+
}
|
|
8547
|
+
return apps;
|
|
8548
|
+
}
|
|
8549
|
+
function analyzeApp(appPath, appName) {
|
|
8550
|
+
const packageJsonPath = joinPath(appPath, "package.json");
|
|
8551
|
+
if (!pathExists(packageJsonPath)) {
|
|
8552
|
+
return null;
|
|
8553
|
+
}
|
|
8554
|
+
let packageJson = null;
|
|
8555
|
+
try {
|
|
8556
|
+
packageJson = readPackageJson(packageJsonPath);
|
|
8557
|
+
if (!packageJson.name) {
|
|
8558
|
+
return null;
|
|
8559
|
+
}
|
|
8560
|
+
} catch {
|
|
8561
|
+
return null;
|
|
8562
|
+
}
|
|
8563
|
+
let framework = "unknown";
|
|
8564
|
+
if (pathExists(joinPath(appPath, "next.config.js")) || pathExists(joinPath(appPath, "next.config.ts")) || pathExists(joinPath(appPath, "next.config.mjs")) || packageJson.dependencies?.next || packageJson.devDependencies?.next) {
|
|
8565
|
+
framework = "nextjs";
|
|
8566
|
+
} else if (pathExists(joinPath(appPath, "vite.config.ts")) || pathExists(joinPath(appPath, "vite.config.js")) || pathExists(joinPath(appPath, "vite.config.mjs")) || packageJson.dependencies?.vite || packageJson.devDependencies?.vite) {
|
|
8567
|
+
framework = "vite";
|
|
8568
|
+
}
|
|
8569
|
+
const functionsPath = joinPath(appPath, "functions");
|
|
8570
|
+
const functionsStat = statSync2(functionsPath);
|
|
8571
|
+
const hasFunctions = pathExists(functionsPath) && (functionsStat?.isDirectory() ?? false);
|
|
8572
|
+
let platform6;
|
|
8573
|
+
const firebaseJsonInFunctions = hasFunctions && pathExists(joinPath(functionsPath, "firebase.json"));
|
|
8574
|
+
const firebaseJsonInApp = pathExists(joinPath(appPath, "firebase.json"));
|
|
8575
|
+
if (firebaseJsonInFunctions || firebaseJsonInApp) {
|
|
8576
|
+
platform6 = "firebase";
|
|
8577
|
+
}
|
|
8578
|
+
if (!platform6) {
|
|
8579
|
+
const supabaseConfigPath = joinPath(appPath, "supabase", "config.toml");
|
|
8580
|
+
const hasSupabaseDep = !!(packageJson.dependencies?.["@donotdev/supabase"] || packageJson.dependencies?.["@supabase/supabase-js"]);
|
|
8581
|
+
if (pathExists(supabaseConfigPath) || hasSupabaseDep) {
|
|
8582
|
+
platform6 = "supabase";
|
|
8583
|
+
}
|
|
8584
|
+
}
|
|
8585
|
+
if (!platform6) {
|
|
8586
|
+
const vercelJsonPath = joinPath(appPath, "vercel.json");
|
|
8587
|
+
if (pathExists(vercelJsonPath)) {
|
|
8588
|
+
platform6 = "vercel";
|
|
8589
|
+
}
|
|
8590
|
+
}
|
|
8591
|
+
return {
|
|
8592
|
+
name: appName,
|
|
8593
|
+
packageName: packageJson.name || appName,
|
|
8594
|
+
path: appPath,
|
|
8595
|
+
packageJsonPath,
|
|
8596
|
+
framework,
|
|
8597
|
+
hasFunctions,
|
|
8598
|
+
functionsPath: hasFunctions ? functionsPath : void 0,
|
|
8599
|
+
platform: platform6
|
|
8600
|
+
};
|
|
8601
|
+
}
|
|
8602
|
+
var init_app_detection = __esm({
|
|
8603
|
+
"packages/tooling/src/utils/app-detection.ts"() {
|
|
8604
|
+
"use strict";
|
|
8605
|
+
init_utils();
|
|
8606
|
+
init_pathResolver();
|
|
8607
|
+
init_typed_file_operations();
|
|
8608
|
+
}
|
|
8609
|
+
});
|
|
8610
|
+
|
|
8611
|
+
// packages/tooling/src/utils/app-selector.ts
|
|
8612
|
+
async function selectApp(projectRoot, appName) {
|
|
8613
|
+
const apps = detectApps(projectRoot);
|
|
8614
|
+
if (apps.length === 0) {
|
|
8615
|
+
log.error("No apps found in this project.");
|
|
8616
|
+
log.info('Run "dndev init" to create a new project.');
|
|
8617
|
+
return null;
|
|
8618
|
+
}
|
|
8619
|
+
if (appName) {
|
|
8620
|
+
const app = apps.find((a) => a.name === appName);
|
|
8621
|
+
if (!app) {
|
|
8622
|
+
log.warn(`App "${appName}" not found.`);
|
|
8623
|
+
log.info("Available apps:");
|
|
8624
|
+
apps.forEach((a) => log.info(` - ${a.name}`));
|
|
8625
|
+
log.info("Please select from the list:");
|
|
8626
|
+
} else {
|
|
8627
|
+
return app;
|
|
8628
|
+
}
|
|
8629
|
+
}
|
|
8630
|
+
if (apps.length === 1) {
|
|
8631
|
+
return apps[0] || null;
|
|
8632
|
+
}
|
|
8633
|
+
const selected = await ve({
|
|
8634
|
+
message: "Select app:",
|
|
8635
|
+
options: apps.map((app) => ({
|
|
8636
|
+
value: app.name,
|
|
8637
|
+
label: `${app.name} (${app.framework === "nextjs" ? "Next.js" : "Vite"}${app.hasFunctions ? ` + ${app.platform || "functions"}` : ""})`
|
|
8638
|
+
}))
|
|
8639
|
+
});
|
|
8640
|
+
if (typeof selected !== "string") {
|
|
8641
|
+
return null;
|
|
8642
|
+
}
|
|
8643
|
+
return apps.find((a) => a.name === selected) || null;
|
|
8644
|
+
}
|
|
8645
|
+
var init_app_selector = __esm({
|
|
8646
|
+
"packages/tooling/src/utils/app-selector.ts"() {
|
|
8647
|
+
"use strict";
|
|
8648
|
+
init_utils();
|
|
8649
|
+
init_dist2();
|
|
8650
|
+
init_app_detection();
|
|
8651
|
+
init_cli_output();
|
|
8652
|
+
}
|
|
8653
|
+
});
|
|
8654
|
+
|
|
8513
8655
|
// packages/tooling/src/utils/cli-input.ts
|
|
8514
8656
|
async function askForInput(message, defaultValue = "") {
|
|
8515
8657
|
const result = await he({
|
|
@@ -8677,7 +8819,7 @@ function checkTsx() {
|
|
|
8677
8819
|
return checkCLI("tsx");
|
|
8678
8820
|
}
|
|
8679
8821
|
function getCLIInstallInstructions(tool) {
|
|
8680
|
-
const
|
|
8822
|
+
const platform6 = process.platform;
|
|
8681
8823
|
const instructions = {
|
|
8682
8824
|
[CLI_TOOLS.BUN]: {
|
|
8683
8825
|
win32: [
|
|
@@ -8730,15 +8872,15 @@ function getCLIInstallInstructions(tool) {
|
|
|
8730
8872
|
},
|
|
8731
8873
|
[CLI_TOOLS.SUPABASE]: {
|
|
8732
8874
|
win32: [
|
|
8733
|
-
"
|
|
8875
|
+
"scoop install supabase",
|
|
8876
|
+
"Or: winget install Supabase.CLI",
|
|
8734
8877
|
"Or download from: https://github.com/supabase/cli/releases"
|
|
8735
8878
|
],
|
|
8736
8879
|
darwin: [
|
|
8737
|
-
"brew install supabase/tap/supabase"
|
|
8738
|
-
"Or: npm install -g supabase"
|
|
8880
|
+
"brew install supabase/tap/supabase"
|
|
8739
8881
|
],
|
|
8740
8882
|
linux: [
|
|
8741
|
-
"
|
|
8883
|
+
"brew install supabase/tap/supabase",
|
|
8742
8884
|
"Or see: https://supabase.com/docs/guides/cli"
|
|
8743
8885
|
]
|
|
8744
8886
|
},
|
|
@@ -8791,7 +8933,7 @@ function getCLIInstallInstructions(tool) {
|
|
|
8791
8933
|
linux: ["npm install -g tsx"]
|
|
8792
8934
|
}
|
|
8793
8935
|
};
|
|
8794
|
-
const platformInstructions = instructions[tool]?.[
|
|
8936
|
+
const platformInstructions = instructions[tool]?.[platform6] || instructions[tool]?.linux || [];
|
|
8795
8937
|
return platformInstructions.join("\n \u2022 ");
|
|
8796
8938
|
}
|
|
8797
8939
|
function formatCLIMissingError(tool, additionalContext) {
|
|
@@ -8806,9 +8948,9 @@ function formatCLIMissingError(tool, additionalContext) {
|
|
|
8806
8948
|
M2.info(`
|
|
8807
8949
|
${additionalContext}`);
|
|
8808
8950
|
}
|
|
8809
|
-
const
|
|
8951
|
+
const platform6 = process.platform;
|
|
8810
8952
|
M2.info("\nIf already installed, ensure it's in your PATH:");
|
|
8811
|
-
if (
|
|
8953
|
+
if (platform6 === "win32") {
|
|
8812
8954
|
M2.message(" \u2022 Check with: where " + tool);
|
|
8813
8955
|
M2.message(
|
|
8814
8956
|
" \u2022 Common location: C:\\Users\\<username>\\AppData\\Roaming\\npm\\"
|
|
@@ -8865,6 +9007,40 @@ var init_cli_tools = __esm({
|
|
|
8865
9007
|
}
|
|
8866
9008
|
});
|
|
8867
9009
|
|
|
9010
|
+
// packages/tooling/src/cli/setup/vercel-token.ts
|
|
9011
|
+
function readEnvVar(filePath, varName) {
|
|
9012
|
+
if (!pathExists(filePath)) return null;
|
|
9013
|
+
const content = readSync(filePath, { format: "text" });
|
|
9014
|
+
if (typeof content !== "string") return null;
|
|
9015
|
+
for (const line of content.split(/\r?\n/)) {
|
|
9016
|
+
const trimmed = line.trim();
|
|
9017
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
9018
|
+
if (trimmed.startsWith(`${varName}=`)) {
|
|
9019
|
+
const val = trimmed.substring(`${varName}=`.length).trim();
|
|
9020
|
+
if (val.startsWith('"') && val.endsWith('"') || val.startsWith("'") && val.endsWith("'")) {
|
|
9021
|
+
return val.slice(1, -1);
|
|
9022
|
+
}
|
|
9023
|
+
return val || null;
|
|
9024
|
+
}
|
|
9025
|
+
}
|
|
9026
|
+
return null;
|
|
9027
|
+
}
|
|
9028
|
+
function resolveVercelToken(appDir) {
|
|
9029
|
+
if (process.env.VERCEL_TOKEN) return process.env.VERCEL_TOKEN;
|
|
9030
|
+
const fromEnv = readEnvVar(joinPath(appDir, ".env"), "VERCEL_TOKEN");
|
|
9031
|
+
if (fromEnv) return fromEnv;
|
|
9032
|
+
const fromLocal = readEnvVar(joinPath(appDir, ".env.local"), "VERCEL_TOKEN");
|
|
9033
|
+
if (fromLocal) return fromLocal;
|
|
9034
|
+
return null;
|
|
9035
|
+
}
|
|
9036
|
+
var init_vercel_token = __esm({
|
|
9037
|
+
"packages/tooling/src/cli/setup/vercel-token.ts"() {
|
|
9038
|
+
"use strict";
|
|
9039
|
+
init_utils();
|
|
9040
|
+
init_pathResolver();
|
|
9041
|
+
}
|
|
9042
|
+
});
|
|
9043
|
+
|
|
8868
9044
|
// node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/nodes/identity.js
|
|
8869
9045
|
var require_identity = __commonJS({
|
|
8870
9046
|
"node_modules/.bun/yaml@2.8.2/node_modules/yaml/dist/nodes/identity.js"(exports) {
|
|
@@ -16226,13 +16402,36 @@ var require_dist = __commonJS({
|
|
|
16226
16402
|
}
|
|
16227
16403
|
});
|
|
16228
16404
|
|
|
16405
|
+
// packages/tooling/src/utils/error-handling.ts
|
|
16406
|
+
function isError(error2) {
|
|
16407
|
+
return error2 instanceof Error;
|
|
16408
|
+
}
|
|
16409
|
+
function getErrorMessage(error2) {
|
|
16410
|
+
if (isError(error2)) {
|
|
16411
|
+
return error2.message;
|
|
16412
|
+
}
|
|
16413
|
+
if (typeof error2 === "string") {
|
|
16414
|
+
return error2;
|
|
16415
|
+
}
|
|
16416
|
+
if (error2 && typeof error2 === "object" && "message" in error2) {
|
|
16417
|
+
return String(error2.message);
|
|
16418
|
+
}
|
|
16419
|
+
return String(error2);
|
|
16420
|
+
}
|
|
16421
|
+
var init_error_handling = __esm({
|
|
16422
|
+
"packages/tooling/src/utils/error-handling.ts"() {
|
|
16423
|
+
"use strict";
|
|
16424
|
+
init_utils();
|
|
16425
|
+
}
|
|
16426
|
+
});
|
|
16427
|
+
|
|
16229
16428
|
// packages/tooling/src/apps/sync-secrets.ts
|
|
16230
16429
|
var sync_secrets_exports = {};
|
|
16231
16430
|
__export(sync_secrets_exports, {
|
|
16232
16431
|
default: () => sync_secrets_default,
|
|
16233
16432
|
main: () => main5
|
|
16234
16433
|
});
|
|
16235
|
-
import { spawnSync as
|
|
16434
|
+
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
16236
16435
|
function parseEnvFile(filePath) {
|
|
16237
16436
|
if (!pathExists(filePath)) {
|
|
16238
16437
|
throw new DoNotDevError(
|
|
@@ -16425,7 +16624,7 @@ async function setFirebaseSecret(key, value, projectId, dryRun = false, cwd) {
|
|
|
16425
16624
|
NODE_OPTIONS: ""
|
|
16426
16625
|
// Clear to avoid conflicts
|
|
16427
16626
|
};
|
|
16428
|
-
const result =
|
|
16627
|
+
const result = spawnSync9(firebaseCmd, args, {
|
|
16429
16628
|
input: value,
|
|
16430
16629
|
encoding: "utf8",
|
|
16431
16630
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -16521,7 +16720,7 @@ function setVercelSecret(key, value, projectId, dryRun = false) {
|
|
|
16521
16720
|
if (projectId) {
|
|
16522
16721
|
args.push("--project", projectId);
|
|
16523
16722
|
}
|
|
16524
|
-
const result =
|
|
16723
|
+
const result = spawnSync9("vercel", args, {
|
|
16525
16724
|
input: value,
|
|
16526
16725
|
encoding: "utf8",
|
|
16527
16726
|
stdio: ["pipe", "inherit", "inherit"]
|
|
@@ -16550,7 +16749,7 @@ function setVercelSecret(key, value, projectId, dryRun = false) {
|
|
|
16550
16749
|
}
|
|
16551
16750
|
function detectGitHubRepo() {
|
|
16552
16751
|
try {
|
|
16553
|
-
const result =
|
|
16752
|
+
const result = spawnSync9("git", ["remote", "get-url", "origin"], {
|
|
16554
16753
|
encoding: "utf8",
|
|
16555
16754
|
stdio: ["pipe", "pipe", "pipe"]
|
|
16556
16755
|
});
|
|
@@ -16578,7 +16777,7 @@ function setGitHubSecret(key, value, repo, dryRun = false) {
|
|
|
16578
16777
|
if (repo) {
|
|
16579
16778
|
args.push("--repo", repo);
|
|
16580
16779
|
}
|
|
16581
|
-
const result =
|
|
16780
|
+
const result = spawnSync9("gh", args, {
|
|
16582
16781
|
input: value,
|
|
16583
16782
|
encoding: "utf8",
|
|
16584
16783
|
stdio: ["pipe", "pipe", "pipe"]
|
|
@@ -16752,12 +16951,12 @@ Examples:
|
|
|
16752
16951
|
}
|
|
16753
16952
|
return 0;
|
|
16754
16953
|
}
|
|
16755
|
-
const
|
|
16954
|
+
const platform6 = config.platform || detectPlatform();
|
|
16756
16955
|
log.info(`Reading secrets from: ${envFilePath}`);
|
|
16757
16956
|
if (config.verbose) {
|
|
16758
16957
|
log.debug(`Working directory: ${currentDir}`);
|
|
16759
16958
|
log.debug(`Environment file: ${envFilePath}`);
|
|
16760
|
-
log.debug(`Platform: ${
|
|
16959
|
+
log.debug(`Platform: ${platform6}`);
|
|
16761
16960
|
log.debug(`Dry run mode: ${config.dryRun}`);
|
|
16762
16961
|
}
|
|
16763
16962
|
const secrets = parseEnvFile(envFilePath);
|
|
@@ -16766,7 +16965,7 @@ Examples:
|
|
|
16766
16965
|
log.info("No secrets found in .env file");
|
|
16767
16966
|
return 0;
|
|
16768
16967
|
}
|
|
16769
|
-
log.info(`Found ${secretKeys.length} secrets to sync to ${
|
|
16968
|
+
log.info(`Found ${secretKeys.length} secrets to sync to ${platform6}:`);
|
|
16770
16969
|
secretKeys.forEach((key) => {
|
|
16771
16970
|
if (config.verbose) {
|
|
16772
16971
|
const value = secrets[key];
|
|
@@ -16777,12 +16976,12 @@ Examples:
|
|
|
16777
16976
|
log.info(` ${key}`);
|
|
16778
16977
|
}
|
|
16779
16978
|
});
|
|
16780
|
-
const finalFirebaseProjectDir =
|
|
16979
|
+
const finalFirebaseProjectDir = platform6 === "firebase" ? firebaseProjectDir || findFirebaseProjectDir(config.envFile) : void 0;
|
|
16781
16980
|
if (config.verbose && finalFirebaseProjectDir) {
|
|
16782
16981
|
log.debug(`Firebase project directory: ${finalFirebaseProjectDir}`);
|
|
16783
16982
|
}
|
|
16784
16983
|
for (const [key, value] of Object.entries(secrets)) {
|
|
16785
|
-
if (
|
|
16984
|
+
if (platform6 === "firebase") {
|
|
16786
16985
|
await setFirebaseSecret(
|
|
16787
16986
|
key,
|
|
16788
16987
|
value,
|
|
@@ -16790,18 +16989,18 @@ Examples:
|
|
|
16790
16989
|
config.dryRun,
|
|
16791
16990
|
finalFirebaseProjectDir
|
|
16792
16991
|
);
|
|
16793
|
-
} else if (
|
|
16992
|
+
} else if (platform6 === "vercel") {
|
|
16794
16993
|
setVercelSecret(key, value, config.vercelProjectId, config.dryRun);
|
|
16795
16994
|
}
|
|
16796
16995
|
}
|
|
16797
16996
|
if (config.dryRun) {
|
|
16798
16997
|
log.success(
|
|
16799
16998
|
`
|
|
16800
|
-
Dry run completed. No secrets were actually set to ${
|
|
16999
|
+
Dry run completed. No secrets were actually set to ${platform6}.`
|
|
16801
17000
|
);
|
|
16802
17001
|
} else {
|
|
16803
17002
|
log.success(`
|
|
16804
|
-
All secrets synced successfully to ${
|
|
17003
|
+
All secrets synced successfully to ${platform6}!`);
|
|
16805
17004
|
}
|
|
16806
17005
|
return 0;
|
|
16807
17006
|
} catch (err) {
|
|
@@ -16830,7 +17029,7 @@ var deploy_supabase_functions_exports = {};
|
|
|
16830
17029
|
__export(deploy_supabase_functions_exports, {
|
|
16831
17030
|
deploySupabaseFunctions: () => deploySupabaseFunctions
|
|
16832
17031
|
});
|
|
16833
|
-
import { execSync as
|
|
17032
|
+
import { execSync as execSync9 } from "node:child_process";
|
|
16834
17033
|
async function deploySupabaseFunctions(appDir, config) {
|
|
16835
17034
|
const supabaseDir = joinPath(appDir, "supabase");
|
|
16836
17035
|
const functionsDir = joinPath(supabaseDir, "functions");
|
|
@@ -16859,7 +17058,7 @@ async function deploySupabaseFunctions(appDir, config) {
|
|
|
16859
17058
|
for (const functionName of functionDirs) {
|
|
16860
17059
|
s.start(`Deploying Edge Function: ${functionName}...`);
|
|
16861
17060
|
try {
|
|
16862
|
-
|
|
17061
|
+
execSync9(`supabase functions deploy ${functionName}`, {
|
|
16863
17062
|
cwd: supabaseDir,
|
|
16864
17063
|
stdio: config.verbose ? "inherit" : "pipe",
|
|
16865
17064
|
env: {
|
|
@@ -16898,167 +17097,42 @@ init_utils();
|
|
|
16898
17097
|
|
|
16899
17098
|
// packages/tooling/src/apps/build.ts
|
|
16900
17099
|
init_utils();
|
|
16901
|
-
|
|
16902
|
-
|
|
16903
|
-
|
|
16904
|
-
|
|
16905
|
-
init_dist2();
|
|
16906
|
-
|
|
16907
|
-
// packages/tooling/src/utils/app-detection.ts
|
|
16908
|
-
init_utils();
|
|
17100
|
+
init_app_selector();
|
|
17101
|
+
init_cli_input();
|
|
17102
|
+
init_cli_output();
|
|
17103
|
+
init_errors();
|
|
16909
17104
|
init_pathResolver();
|
|
16910
17105
|
init_typed_file_operations();
|
|
16911
|
-
|
|
16912
|
-
|
|
16913
|
-
const
|
|
16914
|
-
|
|
16915
|
-
|
|
16916
|
-
|
|
16917
|
-
|
|
16918
|
-
|
|
16919
|
-
|
|
16920
|
-
if (pathExists(packageJsonPath)) {
|
|
16921
|
-
const appInfo = analyzeApp(appPath, appDir);
|
|
16922
|
-
if (appInfo) {
|
|
16923
|
-
apps.push(appInfo);
|
|
16924
|
-
}
|
|
16925
|
-
}
|
|
16926
|
-
}
|
|
16927
|
-
} else {
|
|
16928
|
-
const packageJsonPath = joinPath(projectRoot, "package.json");
|
|
16929
|
-
if (pathExists(packageJsonPath)) {
|
|
16930
|
-
try {
|
|
16931
|
-
const packageJson = readPackageJson(packageJsonPath);
|
|
16932
|
-
if (packageJson && (packageJson.dependencies?.vite || packageJson.devDependencies?.vite || packageJson.dependencies?.next || packageJson.devDependencies?.next)) {
|
|
16933
|
-
const pathParts = projectRoot.split(/[/\\]/);
|
|
16934
|
-
const appName = pathParts[pathParts.length - 1] || "app";
|
|
16935
|
-
const appInfo = analyzeApp(projectRoot, appName);
|
|
16936
|
-
if (appInfo) {
|
|
16937
|
-
apps.push(appInfo);
|
|
16938
|
-
}
|
|
16939
|
-
}
|
|
16940
|
-
} catch {
|
|
16941
|
-
}
|
|
16942
|
-
}
|
|
16943
|
-
}
|
|
16944
|
-
return apps;
|
|
16945
|
-
}
|
|
16946
|
-
function analyzeApp(appPath, appName) {
|
|
16947
|
-
const packageJsonPath = joinPath(appPath, "package.json");
|
|
16948
|
-
if (!pathExists(packageJsonPath)) {
|
|
16949
|
-
return null;
|
|
17106
|
+
import { spawnSync, execSync } from "node:child_process";
|
|
17107
|
+
function validateFirebaseJson(appDir) {
|
|
17108
|
+
const firebaseJsonPath = joinPath(appDir, "firebase.json");
|
|
17109
|
+
if (!pathExists(firebaseJsonPath)) {
|
|
17110
|
+
return {
|
|
17111
|
+
valid: false,
|
|
17112
|
+
hasHosting: false,
|
|
17113
|
+
hasFunctions: false
|
|
17114
|
+
};
|
|
16950
17115
|
}
|
|
16951
|
-
let packageJson = null;
|
|
16952
17116
|
try {
|
|
16953
|
-
|
|
16954
|
-
if (!
|
|
16955
|
-
return
|
|
17117
|
+
const config = readFirebaseJson(firebaseJsonPath);
|
|
17118
|
+
if (!config.projectId) {
|
|
17119
|
+
return {
|
|
17120
|
+
valid: false,
|
|
17121
|
+
hasHosting: false,
|
|
17122
|
+
hasFunctions: false
|
|
17123
|
+
};
|
|
16956
17124
|
}
|
|
17125
|
+
return {
|
|
17126
|
+
valid: true,
|
|
17127
|
+
hasHosting: !!config.hosting,
|
|
17128
|
+
hasFunctions: !!config.functions && Array.isArray(config.functions)
|
|
17129
|
+
};
|
|
16957
17130
|
} catch {
|
|
16958
|
-
return
|
|
16959
|
-
|
|
16960
|
-
|
|
16961
|
-
|
|
16962
|
-
|
|
16963
|
-
} else if (pathExists(joinPath(appPath, "vite.config.ts")) || pathExists(joinPath(appPath, "vite.config.js")) || pathExists(joinPath(appPath, "vite.config.mjs")) || packageJson.dependencies?.vite || packageJson.devDependencies?.vite) {
|
|
16964
|
-
framework = "vite";
|
|
16965
|
-
}
|
|
16966
|
-
const functionsPath = joinPath(appPath, "functions");
|
|
16967
|
-
const functionsStat = statSync2(functionsPath);
|
|
16968
|
-
const hasFunctions = pathExists(functionsPath) && (functionsStat?.isDirectory() ?? false);
|
|
16969
|
-
let platform4;
|
|
16970
|
-
if (hasFunctions) {
|
|
16971
|
-
const firebaseJsonPath = joinPath(functionsPath, "firebase.json");
|
|
16972
|
-
const vercelJsonPath = joinPath(appPath, "vercel.json");
|
|
16973
|
-
if (pathExists(firebaseJsonPath)) {
|
|
16974
|
-
platform4 = "firebase";
|
|
16975
|
-
} else if (pathExists(vercelJsonPath)) {
|
|
16976
|
-
platform4 = "vercel";
|
|
16977
|
-
}
|
|
16978
|
-
}
|
|
16979
|
-
return {
|
|
16980
|
-
name: appName,
|
|
16981
|
-
packageName: packageJson.name || appName,
|
|
16982
|
-
path: appPath,
|
|
16983
|
-
packageJsonPath,
|
|
16984
|
-
framework,
|
|
16985
|
-
hasFunctions,
|
|
16986
|
-
functionsPath: hasFunctions ? functionsPath : void 0,
|
|
16987
|
-
platform: platform4
|
|
16988
|
-
};
|
|
16989
|
-
}
|
|
16990
|
-
|
|
16991
|
-
// packages/tooling/src/utils/app-selector.ts
|
|
16992
|
-
init_cli_output();
|
|
16993
|
-
async function selectApp(projectRoot, appName) {
|
|
16994
|
-
const apps = detectApps(projectRoot);
|
|
16995
|
-
if (apps.length === 0) {
|
|
16996
|
-
log.error("No apps found in this project.");
|
|
16997
|
-
log.info('Run "dndev init" to create a new project.');
|
|
16998
|
-
return null;
|
|
16999
|
-
}
|
|
17000
|
-
if (appName) {
|
|
17001
|
-
const app = apps.find((a) => a.name === appName);
|
|
17002
|
-
if (!app) {
|
|
17003
|
-
log.warn(`App "${appName}" not found.`);
|
|
17004
|
-
log.info("Available apps:");
|
|
17005
|
-
apps.forEach((a) => log.info(` - ${a.name}`));
|
|
17006
|
-
log.info("Please select from the list:");
|
|
17007
|
-
} else {
|
|
17008
|
-
return app;
|
|
17009
|
-
}
|
|
17010
|
-
}
|
|
17011
|
-
if (apps.length === 1) {
|
|
17012
|
-
return apps[0] || null;
|
|
17013
|
-
}
|
|
17014
|
-
const selected = await ve({
|
|
17015
|
-
message: "Select app:",
|
|
17016
|
-
options: apps.map((app) => ({
|
|
17017
|
-
value: app.name,
|
|
17018
|
-
label: `${app.name} (${app.framework === "nextjs" ? "Next.js" : "Vite"}${app.hasFunctions ? ` + ${app.platform || "functions"}` : ""})`
|
|
17019
|
-
}))
|
|
17020
|
-
});
|
|
17021
|
-
if (typeof selected !== "string") {
|
|
17022
|
-
return null;
|
|
17023
|
-
}
|
|
17024
|
-
return apps.find((a) => a.name === selected) || null;
|
|
17025
|
-
}
|
|
17026
|
-
|
|
17027
|
-
// packages/tooling/src/apps/build.ts
|
|
17028
|
-
init_cli_input();
|
|
17029
|
-
init_cli_output();
|
|
17030
|
-
init_errors();
|
|
17031
|
-
init_pathResolver();
|
|
17032
|
-
init_typed_file_operations();
|
|
17033
|
-
function validateFirebaseJson(appDir) {
|
|
17034
|
-
const firebaseJsonPath = joinPath(appDir, "firebase.json");
|
|
17035
|
-
if (!pathExists(firebaseJsonPath)) {
|
|
17036
|
-
return {
|
|
17037
|
-
valid: false,
|
|
17038
|
-
hasHosting: false,
|
|
17039
|
-
hasFunctions: false
|
|
17040
|
-
};
|
|
17041
|
-
}
|
|
17042
|
-
try {
|
|
17043
|
-
const config = readFirebaseJson(firebaseJsonPath);
|
|
17044
|
-
if (!config.projectId) {
|
|
17045
|
-
return {
|
|
17046
|
-
valid: false,
|
|
17047
|
-
hasHosting: false,
|
|
17048
|
-
hasFunctions: false
|
|
17049
|
-
};
|
|
17050
|
-
}
|
|
17051
|
-
return {
|
|
17052
|
-
valid: true,
|
|
17053
|
-
hasHosting: !!config.hosting,
|
|
17054
|
-
hasFunctions: !!config.functions && Array.isArray(config.functions)
|
|
17055
|
-
};
|
|
17056
|
-
} catch {
|
|
17057
|
-
return {
|
|
17058
|
-
valid: false,
|
|
17059
|
-
hasHosting: false,
|
|
17060
|
-
hasFunctions: false
|
|
17061
|
-
};
|
|
17131
|
+
return {
|
|
17132
|
+
valid: false,
|
|
17133
|
+
hasHosting: false,
|
|
17134
|
+
hasFunctions: false
|
|
17135
|
+
};
|
|
17062
17136
|
}
|
|
17063
17137
|
}
|
|
17064
17138
|
function parseBuildArgs(args) {
|
|
@@ -17220,11 +17294,12 @@ async function main() {
|
|
|
17220
17294
|
|
|
17221
17295
|
// packages/tooling/src/apps/dev.ts
|
|
17222
17296
|
init_utils();
|
|
17223
|
-
|
|
17224
|
-
import { platform } from "node:os";
|
|
17297
|
+
init_app_selector();
|
|
17225
17298
|
init_cli_output();
|
|
17226
17299
|
init_errors();
|
|
17227
17300
|
init_pathResolver();
|
|
17301
|
+
import { spawn, execSync as execSync3 } from "node:child_process";
|
|
17302
|
+
import { platform } from "node:os";
|
|
17228
17303
|
|
|
17229
17304
|
// packages/tooling/src/utils/spawn-utils.ts
|
|
17230
17305
|
init_utils();
|
|
@@ -17470,18 +17545,23 @@ async function main2() {
|
|
|
17470
17545
|
|
|
17471
17546
|
// packages/tooling/src/apps/emu.ts
|
|
17472
17547
|
init_utils();
|
|
17548
|
+
init_app_selector();
|
|
17549
|
+
init_cli_output();
|
|
17550
|
+
init_errors();
|
|
17551
|
+
init_pathResolver();
|
|
17552
|
+
|
|
17553
|
+
// packages/tooling/src/apps/emu-firebase.ts
|
|
17554
|
+
init_utils();
|
|
17555
|
+
init_cli_input();
|
|
17556
|
+
init_cli_output();
|
|
17557
|
+
init_pathResolver();
|
|
17558
|
+
init_typed_file_operations();
|
|
17473
17559
|
import {
|
|
17474
17560
|
spawn as spawn2,
|
|
17475
17561
|
spawnSync as spawnSync3,
|
|
17476
17562
|
execSync as execSync4
|
|
17477
17563
|
} from "node:child_process";
|
|
17478
17564
|
import { platform as platform2 } from "node:os";
|
|
17479
|
-
init_cli_input();
|
|
17480
|
-
init_cli_output();
|
|
17481
|
-
init_errors();
|
|
17482
|
-
init_pathResolver();
|
|
17483
|
-
init_pathResolver();
|
|
17484
|
-
init_typed_file_operations();
|
|
17485
17565
|
function discoverFirebaseProjectId(appPath) {
|
|
17486
17566
|
const firebasercPath = joinPath(appPath, ".firebaserc");
|
|
17487
17567
|
if (pathExists(firebasercPath)) {
|
|
@@ -17513,7 +17593,7 @@ function killPorts(ports) {
|
|
|
17513
17593
|
pids.add(match[1]);
|
|
17514
17594
|
}
|
|
17515
17595
|
}
|
|
17516
|
-
for (const pid of pids) {
|
|
17596
|
+
for (const pid of Array.from(pids)) {
|
|
17517
17597
|
try {
|
|
17518
17598
|
execSync4(`taskkill /F /PID ${pid}`, { stdio: "ignore" });
|
|
17519
17599
|
log.debug(`Killed process ${pid} on port ${port}`);
|
|
@@ -17575,9 +17655,9 @@ function loadEnvFile(filePath) {
|
|
|
17575
17655
|
} catch {
|
|
17576
17656
|
}
|
|
17577
17657
|
}
|
|
17578
|
-
async function
|
|
17579
|
-
const
|
|
17580
|
-
|
|
17658
|
+
async function startFirebase(app, projectRoot, options = {}) {
|
|
17659
|
+
const debug = options.debug ?? false;
|
|
17660
|
+
let selectedServices = options.selectedServices ?? [];
|
|
17581
17661
|
const serviceChoices = [
|
|
17582
17662
|
{
|
|
17583
17663
|
title: "Auth",
|
|
@@ -17600,47 +17680,6 @@ async function main3(options) {
|
|
|
17600
17680
|
hint: "Stripe webhook forwarding (for payment testing)"
|
|
17601
17681
|
}
|
|
17602
17682
|
];
|
|
17603
|
-
let selectedServices = [];
|
|
17604
|
-
const appName = args.find(
|
|
17605
|
-
(arg) => arg !== "emu" && arg !== "--debug" && !arg.startsWith("--")
|
|
17606
|
-
);
|
|
17607
|
-
if (options?.services) {
|
|
17608
|
-
selectedServices = options.services.split(",").map((s) => s.trim());
|
|
17609
|
-
} else {
|
|
17610
|
-
const servicesArg = args.find((arg) => arg.startsWith("--services="));
|
|
17611
|
-
if (servicesArg) {
|
|
17612
|
-
const servicesList = servicesArg.split("=")[1];
|
|
17613
|
-
if (servicesList) {
|
|
17614
|
-
selectedServices = servicesList.split(",").map((s) => s.trim());
|
|
17615
|
-
}
|
|
17616
|
-
} else {
|
|
17617
|
-
if (options?.auth || args.includes("--auth"))
|
|
17618
|
-
selectedServices.push("auth");
|
|
17619
|
-
if (args.includes("--functions")) selectedServices.push("functions");
|
|
17620
|
-
if (options?.firestore || args.includes("--firestore"))
|
|
17621
|
-
selectedServices.push("firestore");
|
|
17622
|
-
if (options?.stripe || args.includes("--stripe"))
|
|
17623
|
-
selectedServices.push("stripe");
|
|
17624
|
-
}
|
|
17625
|
-
}
|
|
17626
|
-
const validServices = serviceChoices.map((c) => c.value);
|
|
17627
|
-
selectedServices = selectedServices.filter((s) => validServices.includes(s));
|
|
17628
|
-
const projectRoot = getRepoRoot();
|
|
17629
|
-
if (!projectRoot) {
|
|
17630
|
-
throw new DoNotDevError(
|
|
17631
|
-
"Could not determine repository root",
|
|
17632
|
-
"path-resolution-error"
|
|
17633
|
-
);
|
|
17634
|
-
}
|
|
17635
|
-
const app = await selectApp(projectRoot, appName);
|
|
17636
|
-
if (!app) {
|
|
17637
|
-
return 1;
|
|
17638
|
-
}
|
|
17639
|
-
if (!app.hasFunctions || app.platform !== "firebase") {
|
|
17640
|
-
log.error(`App "${app.name}" does not have Firebase functions.`);
|
|
17641
|
-
log.error('Use "dndev dev" for apps without functions.\n');
|
|
17642
|
-
return 1;
|
|
17643
|
-
}
|
|
17644
17683
|
log.info(`Starting Firebase emulators + dev server for ${app.name}...
|
|
17645
17684
|
`);
|
|
17646
17685
|
if (selectedServices.length === 0) {
|
|
@@ -17772,7 +17811,7 @@ FIREBASE_AUTH_EMULATOR_HOST=${authEmulatorHost}
|
|
|
17772
17811
|
const stripeWebhookUrl = `http://localhost:5001/${projectId}/${region}/stripeWebhook`;
|
|
17773
17812
|
concurrentlyArgs.push(`stripe listen --forward-to ${stripeWebhookUrl}`);
|
|
17774
17813
|
log.info("");
|
|
17775
|
-
log.info("
|
|
17814
|
+
log.info("Stripe webhook forwarding will start automatically");
|
|
17776
17815
|
log.info(` Webhook URL: ${stripeWebhookUrl}`);
|
|
17777
17816
|
log.info(" To trigger test events, run in another terminal:");
|
|
17778
17817
|
log.info(" stripe trigger checkout.session.completed");
|
|
@@ -17794,9 +17833,7 @@ FIREBASE_AUTH_EMULATOR_HOST=${authEmulatorHost}
|
|
|
17794
17833
|
);
|
|
17795
17834
|
const SIGNAL_EXIT_CODES3 = {
|
|
17796
17835
|
SIGINT: 130,
|
|
17797
|
-
// 128 + 2
|
|
17798
17836
|
SIGTERM: 143
|
|
17799
|
-
// 128 + 15
|
|
17800
17837
|
};
|
|
17801
17838
|
const cleanup = (signal) => {
|
|
17802
17839
|
if (!childProcess.pid) return;
|
|
@@ -17846,23 +17883,234 @@ FIREBASE_AUTH_EMULATOR_HOST=${authEmulatorHost}
|
|
|
17846
17883
|
});
|
|
17847
17884
|
childProcess.on("error", (error2) => {
|
|
17848
17885
|
handlers.forEach((h2) => h2());
|
|
17849
|
-
log.error(`Failed to start emulators: ${error2.message}`);
|
|
17886
|
+
log.error(`Failed to start Firebase emulators: ${error2.message}`);
|
|
17850
17887
|
resolve4(1);
|
|
17851
17888
|
});
|
|
17852
17889
|
});
|
|
17853
17890
|
}
|
|
17854
17891
|
|
|
17855
|
-
// packages/tooling/src/apps/
|
|
17892
|
+
// packages/tooling/src/apps/emu-supabase.ts
|
|
17856
17893
|
init_utils();
|
|
17894
|
+
init_cli_output();
|
|
17857
17895
|
import {
|
|
17858
17896
|
spawn as spawn3,
|
|
17859
|
-
spawnSync as spawnSync4,
|
|
17860
17897
|
execSync as execSync5
|
|
17861
17898
|
} from "node:child_process";
|
|
17862
17899
|
import { platform as platform3 } from "node:os";
|
|
17900
|
+
function isDockerRunning() {
|
|
17901
|
+
try {
|
|
17902
|
+
execSync5("docker info", { stdio: "pipe", timeout: 5e3 });
|
|
17903
|
+
return true;
|
|
17904
|
+
} catch {
|
|
17905
|
+
return false;
|
|
17906
|
+
}
|
|
17907
|
+
}
|
|
17908
|
+
async function startSupabase(app, _projectRoot) {
|
|
17909
|
+
log.info(`Starting Supabase local stack + dev server for ${app.name}...
|
|
17910
|
+
`);
|
|
17911
|
+
if (!isDockerRunning()) {
|
|
17912
|
+
log.error("Docker is not running. Supabase local dev requires Docker.");
|
|
17913
|
+
log.error("Start Docker Desktop and try again.\n");
|
|
17914
|
+
return 1;
|
|
17915
|
+
}
|
|
17916
|
+
try {
|
|
17917
|
+
execSync5("supabase --version", { stdio: "pipe" });
|
|
17918
|
+
} catch {
|
|
17919
|
+
log.error("Supabase CLI not found. Install it:");
|
|
17920
|
+
log.error(" npm install -g supabase\n");
|
|
17921
|
+
return 1;
|
|
17922
|
+
}
|
|
17923
|
+
const isWindows = platform3() === "win32";
|
|
17924
|
+
const concurrentlyArgs = [
|
|
17925
|
+
"--kill-others-on-fail",
|
|
17926
|
+
"--prefix-colors",
|
|
17927
|
+
"cyan,green",
|
|
17928
|
+
"--prefix",
|
|
17929
|
+
"[{name}]",
|
|
17930
|
+
"--names",
|
|
17931
|
+
"supabase,dev",
|
|
17932
|
+
"supabase start",
|
|
17933
|
+
`bunx turbo dev --filter=${app.packageName}`
|
|
17934
|
+
];
|
|
17935
|
+
const childProcess = spawn3(
|
|
17936
|
+
"bunx",
|
|
17937
|
+
["concurrently", ...concurrentlyArgs],
|
|
17938
|
+
{
|
|
17939
|
+
stdio: "inherit",
|
|
17940
|
+
cwd: app.path,
|
|
17941
|
+
shell: isWindows
|
|
17942
|
+
}
|
|
17943
|
+
);
|
|
17944
|
+
const cleanup = () => {
|
|
17945
|
+
if (!childProcess.pid) return;
|
|
17946
|
+
if (isWindows) {
|
|
17947
|
+
try {
|
|
17948
|
+
execSync5(`taskkill /F /T /PID ${childProcess.pid}`, { stdio: "ignore", timeout: 2e3 });
|
|
17949
|
+
} catch {
|
|
17950
|
+
}
|
|
17951
|
+
} else {
|
|
17952
|
+
try {
|
|
17953
|
+
process.kill(childProcess.pid, "SIGTERM");
|
|
17954
|
+
} catch {
|
|
17955
|
+
}
|
|
17956
|
+
}
|
|
17957
|
+
};
|
|
17958
|
+
process.on("SIGINT", () => {
|
|
17959
|
+
cleanup();
|
|
17960
|
+
process.exit(130);
|
|
17961
|
+
});
|
|
17962
|
+
process.on("SIGTERM", () => {
|
|
17963
|
+
cleanup();
|
|
17964
|
+
process.exit(143);
|
|
17965
|
+
});
|
|
17966
|
+
return new Promise((resolve4) => {
|
|
17967
|
+
childProcess.on("exit", (code) => resolve4(code ?? 0));
|
|
17968
|
+
childProcess.on("error", (error2) => {
|
|
17969
|
+
log.error(`Failed to start Supabase local dev: ${error2.message}`);
|
|
17970
|
+
resolve4(1);
|
|
17971
|
+
});
|
|
17972
|
+
});
|
|
17973
|
+
}
|
|
17974
|
+
|
|
17975
|
+
// packages/tooling/src/apps/emu-vercel.ts
|
|
17976
|
+
init_utils();
|
|
17977
|
+
init_cli_output();
|
|
17978
|
+
import {
|
|
17979
|
+
spawn as spawn4,
|
|
17980
|
+
execSync as execSync6
|
|
17981
|
+
} from "node:child_process";
|
|
17982
|
+
import { platform as platform4 } from "node:os";
|
|
17983
|
+
async function startVercel(app, _projectRoot) {
|
|
17984
|
+
log.info(`Starting Vercel dev server for ${app.name}...
|
|
17985
|
+
`);
|
|
17986
|
+
try {
|
|
17987
|
+
execSync6("vercel --version", { stdio: "pipe" });
|
|
17988
|
+
} catch {
|
|
17989
|
+
log.error("Vercel CLI not found. Install it:");
|
|
17990
|
+
log.error(" npm install -g vercel\n");
|
|
17991
|
+
return 1;
|
|
17992
|
+
}
|
|
17993
|
+
const isWindows = platform4() === "win32";
|
|
17994
|
+
const childProcess = spawn4(
|
|
17995
|
+
"vercel",
|
|
17996
|
+
["dev"],
|
|
17997
|
+
{
|
|
17998
|
+
stdio: "inherit",
|
|
17999
|
+
cwd: app.path,
|
|
18000
|
+
shell: isWindows
|
|
18001
|
+
}
|
|
18002
|
+
);
|
|
18003
|
+
const cleanup = () => {
|
|
18004
|
+
if (!childProcess.pid) return;
|
|
18005
|
+
if (isWindows) {
|
|
18006
|
+
try {
|
|
18007
|
+
execSync6(`taskkill /F /T /PID ${childProcess.pid}`, { stdio: "ignore", timeout: 2e3 });
|
|
18008
|
+
} catch {
|
|
18009
|
+
}
|
|
18010
|
+
} else {
|
|
18011
|
+
try {
|
|
18012
|
+
process.kill(childProcess.pid, "SIGTERM");
|
|
18013
|
+
} catch {
|
|
18014
|
+
}
|
|
18015
|
+
}
|
|
18016
|
+
};
|
|
18017
|
+
process.on("SIGINT", () => {
|
|
18018
|
+
cleanup();
|
|
18019
|
+
process.exit(130);
|
|
18020
|
+
});
|
|
18021
|
+
process.on("SIGTERM", () => {
|
|
18022
|
+
cleanup();
|
|
18023
|
+
process.exit(143);
|
|
18024
|
+
});
|
|
18025
|
+
return new Promise((resolve4) => {
|
|
18026
|
+
childProcess.on("exit", (code) => resolve4(code ?? 0));
|
|
18027
|
+
childProcess.on("error", (error2) => {
|
|
18028
|
+
log.error(`Failed to start Vercel dev: ${error2.message}`);
|
|
18029
|
+
resolve4(1);
|
|
18030
|
+
});
|
|
18031
|
+
});
|
|
18032
|
+
}
|
|
18033
|
+
|
|
18034
|
+
// packages/tooling/src/apps/emu.ts
|
|
18035
|
+
async function main3(options) {
|
|
18036
|
+
const args = process.argv.slice(2);
|
|
18037
|
+
const projectRoot = getRepoRoot();
|
|
18038
|
+
if (!projectRoot) {
|
|
18039
|
+
throw new DoNotDevError(
|
|
18040
|
+
"Could not determine repository root",
|
|
18041
|
+
"path-resolution-error"
|
|
18042
|
+
);
|
|
18043
|
+
}
|
|
18044
|
+
const appName = args.find(
|
|
18045
|
+
(arg) => arg !== "emu" && arg !== "--debug" && !arg.startsWith("--")
|
|
18046
|
+
);
|
|
18047
|
+
const app = await selectApp(projectRoot, appName);
|
|
18048
|
+
if (!app) {
|
|
18049
|
+
return 1;
|
|
18050
|
+
}
|
|
18051
|
+
switch (app.platform) {
|
|
18052
|
+
case "firebase": {
|
|
18053
|
+
if (!app.hasFunctions) {
|
|
18054
|
+
log.error(`App "${app.name}" has Firebase config but no functions directory.`);
|
|
18055
|
+
log.error('Use "dndev dev" for apps without backend functions.\n');
|
|
18056
|
+
return 1;
|
|
18057
|
+
}
|
|
18058
|
+
const selectedServices = parseFirebaseServices(args, options);
|
|
18059
|
+
return startFirebase(app, projectRoot, {
|
|
18060
|
+
debug: options?.debug ?? false,
|
|
18061
|
+
selectedServices
|
|
18062
|
+
});
|
|
18063
|
+
}
|
|
18064
|
+
case "supabase":
|
|
18065
|
+
return startSupabase(app, projectRoot);
|
|
18066
|
+
case "vercel":
|
|
18067
|
+
return startVercel(app, projectRoot);
|
|
18068
|
+
default:
|
|
18069
|
+
log.error(`App "${app.name}" does not have a detected backend platform.`);
|
|
18070
|
+
log.error(
|
|
18071
|
+
"Expected: firebase.json (Firebase), supabase/config.toml or @donotdev/supabase (Supabase), or vercel.json (Vercel)."
|
|
18072
|
+
);
|
|
18073
|
+
log.error('Use "dndev dev" for apps without a backend.\n');
|
|
18074
|
+
return 1;
|
|
18075
|
+
}
|
|
18076
|
+
}
|
|
18077
|
+
function parseFirebaseServices(args, options) {
|
|
18078
|
+
const validServices = ["auth", "functions", "firestore", "stripe"];
|
|
18079
|
+
let selectedServices = [];
|
|
18080
|
+
if (options?.services) {
|
|
18081
|
+
selectedServices = options.services.split(",").map((s) => s.trim());
|
|
18082
|
+
} else {
|
|
18083
|
+
const servicesArg = args.find((arg) => arg.startsWith("--services="));
|
|
18084
|
+
if (servicesArg) {
|
|
18085
|
+
const servicesList = servicesArg.split("=")[1];
|
|
18086
|
+
if (servicesList) {
|
|
18087
|
+
selectedServices = servicesList.split(",").map((s) => s.trim());
|
|
18088
|
+
}
|
|
18089
|
+
} else {
|
|
18090
|
+
if (options?.auth || args.includes("--auth"))
|
|
18091
|
+
selectedServices.push("auth");
|
|
18092
|
+
if (args.includes("--functions")) selectedServices.push("functions");
|
|
18093
|
+
if (options?.firestore || args.includes("--firestore"))
|
|
18094
|
+
selectedServices.push("firestore");
|
|
18095
|
+
if (options?.stripe || args.includes("--stripe"))
|
|
18096
|
+
selectedServices.push("stripe");
|
|
18097
|
+
}
|
|
18098
|
+
}
|
|
18099
|
+
return selectedServices.filter((s) => validServices.includes(s));
|
|
18100
|
+
}
|
|
18101
|
+
|
|
18102
|
+
// packages/tooling/src/apps/preview.ts
|
|
18103
|
+
init_utils();
|
|
18104
|
+
init_app_selector();
|
|
17863
18105
|
init_cli_output();
|
|
17864
18106
|
init_errors();
|
|
17865
18107
|
init_pathResolver();
|
|
18108
|
+
import {
|
|
18109
|
+
spawn as spawn5,
|
|
18110
|
+
spawnSync as spawnSync4,
|
|
18111
|
+
execSync as execSync7
|
|
18112
|
+
} from "node:child_process";
|
|
18113
|
+
import { platform as platform5 } from "node:os";
|
|
17866
18114
|
var SIGNAL_EXIT_CODES2 = {
|
|
17867
18115
|
SIGINT: 130,
|
|
17868
18116
|
// 128 + 2
|
|
@@ -17905,8 +18153,8 @@ async function main4() {
|
|
|
17905
18153
|
log.info(`Previewing ${app.name}...
|
|
17906
18154
|
`);
|
|
17907
18155
|
const turboArgs = ["preview", "--filter", app.packageName];
|
|
17908
|
-
const isWindows =
|
|
17909
|
-
const childProcess =
|
|
18156
|
+
const isWindows = platform5() === "win32";
|
|
18157
|
+
const childProcess = spawn5("bunx", ["turbo", ...turboArgs], {
|
|
17910
18158
|
stdio: "inherit",
|
|
17911
18159
|
env: createAppEnv(app.path),
|
|
17912
18160
|
cwd: projectRoot,
|
|
@@ -17917,7 +18165,7 @@ async function main4() {
|
|
|
17917
18165
|
log.debug(`Received ${signal}, cleaning up processes...`);
|
|
17918
18166
|
if (isWindows) {
|
|
17919
18167
|
try {
|
|
17920
|
-
|
|
18168
|
+
execSync7(`taskkill /F /T /PID ${childProcess.pid}`, {
|
|
17921
18169
|
stdio: "ignore",
|
|
17922
18170
|
timeout: 2e3
|
|
17923
18171
|
});
|
|
@@ -17929,7 +18177,7 @@ async function main4() {
|
|
|
17929
18177
|
} catch {
|
|
17930
18178
|
}
|
|
17931
18179
|
try {
|
|
17932
|
-
|
|
18180
|
+
execSync7(`pkill -P ${childProcess.pid}`, {
|
|
17933
18181
|
stdio: "ignore",
|
|
17934
18182
|
timeout: 1e3
|
|
17935
18183
|
});
|
|
@@ -17968,7 +18216,7 @@ async function main4() {
|
|
|
17968
18216
|
|
|
17969
18217
|
// packages/tooling/src/apps/deploy.ts
|
|
17970
18218
|
init_utils();
|
|
17971
|
-
import { execSync as
|
|
18219
|
+
import { execSync as execSync10 } from "node:child_process";
|
|
17972
18220
|
|
|
17973
18221
|
// packages/tooling/src/apps/deploy-frontend.ts
|
|
17974
18222
|
init_utils();
|
|
@@ -18269,15 +18517,10 @@ function getMatrixPath(mode) {
|
|
|
18269
18517
|
}
|
|
18270
18518
|
const executionMode = mode || detectExecutionMode();
|
|
18271
18519
|
if (executionMode === "development") {
|
|
18272
|
-
const
|
|
18273
|
-
|
|
18274
|
-
|
|
18275
|
-
|
|
18276
|
-
"packages/cli/dependencies-matrix.json"
|
|
18277
|
-
);
|
|
18278
|
-
if (pathExists(devPath)) {
|
|
18279
|
-
return devPath;
|
|
18280
|
-
}
|
|
18520
|
+
const templatesRoot = getTemplatesRoot();
|
|
18521
|
+
const devPath = normalizePath(templatesRoot, "..", "dependencies-matrix.json");
|
|
18522
|
+
if (pathExists(devPath)) {
|
|
18523
|
+
return devPath;
|
|
18281
18524
|
}
|
|
18282
18525
|
}
|
|
18283
18526
|
return null;
|
|
@@ -18292,8 +18535,8 @@ function getCliVersion(mode) {
|
|
|
18292
18535
|
}
|
|
18293
18536
|
const executionMode = mode || detectExecutionMode();
|
|
18294
18537
|
if (executionMode === "development") {
|
|
18295
|
-
const
|
|
18296
|
-
const cliPackageJson =
|
|
18538
|
+
const templatesRoot = getTemplatesRoot();
|
|
18539
|
+
const cliPackageJson = normalizePath(templatesRoot, "..", "package.json");
|
|
18297
18540
|
if (pathExists(cliPackageJson)) {
|
|
18298
18541
|
const pkg = readSync(cliPackageJson, { format: "json" });
|
|
18299
18542
|
return String(pkg?.version || "0.0.0");
|
|
@@ -18470,15 +18713,31 @@ async function deployFrontend(appDir, serviceAccountPath, projectId, config) {
|
|
|
18470
18713
|
|
|
18471
18714
|
// packages/tooling/src/apps/deploy-vercel-frontend.ts
|
|
18472
18715
|
init_utils();
|
|
18473
|
-
|
|
18716
|
+
init_cli_output();
|
|
18717
|
+
init_vercel_token();
|
|
18718
|
+
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
18474
18719
|
async function deployVercelFrontend(appDir, _config) {
|
|
18475
18720
|
const s = Y2();
|
|
18476
18721
|
s.start("Deploying frontend to Vercel...");
|
|
18722
|
+
const token = resolveVercelToken(appDir);
|
|
18723
|
+
if (token) {
|
|
18724
|
+
log.debug("Using VERCEL_TOKEN from .env (token-based auth)");
|
|
18725
|
+
}
|
|
18726
|
+
const args = ["vercel", "--prod", "--yes"];
|
|
18727
|
+
if (token) {
|
|
18728
|
+
args.push("--token", token);
|
|
18729
|
+
}
|
|
18477
18730
|
try {
|
|
18478
|
-
|
|
18731
|
+
const result = spawnSync6("bunx", args, {
|
|
18479
18732
|
cwd: appDir,
|
|
18480
|
-
stdio: "
|
|
18733
|
+
stdio: "pipe",
|
|
18734
|
+
encoding: "utf-8"
|
|
18481
18735
|
});
|
|
18736
|
+
if (result.status !== 0) {
|
|
18737
|
+
s.stop("Vercel deployment failed");
|
|
18738
|
+
const errOutput = result.stderr?.trim();
|
|
18739
|
+
throw new Error(errOutput || `Vercel deploy exited with code ${result.status}`);
|
|
18740
|
+
}
|
|
18482
18741
|
s.stop("Frontend deployed to Vercel");
|
|
18483
18742
|
} catch (err) {
|
|
18484
18743
|
s.stop("Vercel deployment failed");
|
|
@@ -18489,7 +18748,7 @@ async function deployVercelFrontend(appDir, _config) {
|
|
|
18489
18748
|
// packages/tooling/src/apps/deploy-functions.ts
|
|
18490
18749
|
init_utils();
|
|
18491
18750
|
var import_yaml = __toESM(require_dist(), 1);
|
|
18492
|
-
import { execSync as
|
|
18751
|
+
import { execSync as execSync8, spawnSync as spawnSync7 } from "node:child_process";
|
|
18493
18752
|
init_pathResolver();
|
|
18494
18753
|
init_cli_tools();
|
|
18495
18754
|
init_typed_file_operations();
|
|
@@ -18658,7 +18917,7 @@ function updateCloudRunIAM(functionNames, projectId, region, serviceAccountPath,
|
|
|
18658
18917
|
let failCount = 0;
|
|
18659
18918
|
for (const funcName of functionNames) {
|
|
18660
18919
|
try {
|
|
18661
|
-
const result =
|
|
18920
|
+
const result = spawnSync7(
|
|
18662
18921
|
"gcloud",
|
|
18663
18922
|
[
|
|
18664
18923
|
"run",
|
|
@@ -18776,7 +19035,7 @@ async function autoSyncSecrets(functionsDir, projectId, config) {
|
|
|
18776
19035
|
let failCount = 0;
|
|
18777
19036
|
for (const { key, value } of secrets) {
|
|
18778
19037
|
try {
|
|
18779
|
-
const result =
|
|
19038
|
+
const result = spawnSync7(
|
|
18780
19039
|
firebaseCmd,
|
|
18781
19040
|
["functions:secrets:set", key, "--project", projectId],
|
|
18782
19041
|
{
|
|
@@ -18858,7 +19117,7 @@ To fix this, run:
|
|
|
18858
19117
|
const s2 = Y2();
|
|
18859
19118
|
s2.start("Building functions...");
|
|
18860
19119
|
try {
|
|
18861
|
-
|
|
19120
|
+
execSync8("bun run build", {
|
|
18862
19121
|
cwd: functionsDir,
|
|
18863
19122
|
stdio: config.verbose ? "inherit" : "pipe"
|
|
18864
19123
|
});
|
|
@@ -18958,29 +19217,10 @@ async function deployRules(appDir, serviceAccountPath, projectId, config, option
|
|
|
18958
19217
|
|
|
18959
19218
|
// packages/tooling/src/apps/deploy-utils.ts
|
|
18960
19219
|
init_utils();
|
|
18961
|
-
import { spawnSync as
|
|
19220
|
+
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
18962
19221
|
init_pathResolver();
|
|
18963
19222
|
init_typed_file_operations();
|
|
18964
|
-
|
|
18965
|
-
// packages/tooling/src/utils/error-handling.ts
|
|
18966
|
-
init_utils();
|
|
18967
|
-
function isError(error2) {
|
|
18968
|
-
return error2 instanceof Error;
|
|
18969
|
-
}
|
|
18970
|
-
function getErrorMessage(error2) {
|
|
18971
|
-
if (isError(error2)) {
|
|
18972
|
-
return error2.message;
|
|
18973
|
-
}
|
|
18974
|
-
if (typeof error2 === "string") {
|
|
18975
|
-
return error2;
|
|
18976
|
-
}
|
|
18977
|
-
if (error2 && typeof error2 === "object" && "message" in error2) {
|
|
18978
|
-
return String(error2.message);
|
|
18979
|
-
}
|
|
18980
|
-
return String(error2);
|
|
18981
|
-
}
|
|
18982
|
-
|
|
18983
|
-
// packages/tooling/src/apps/deploy-utils.ts
|
|
19223
|
+
init_error_handling();
|
|
18984
19224
|
function detectAvailableApps() {
|
|
18985
19225
|
const currentDir = process.cwd();
|
|
18986
19226
|
const appsDir = joinPath(currentDir, "apps");
|
|
@@ -19165,7 +19405,7 @@ How to fix:
|
|
|
19165
19405
|
if (shouldOpen) {
|
|
19166
19406
|
try {
|
|
19167
19407
|
const openCommand = process.platform === "win32" ? "start" : process.platform === "darwin" ? "open" : "xdg-open";
|
|
19168
|
-
|
|
19408
|
+
spawnSync8(openCommand, [consoleUrl], { shell: true });
|
|
19169
19409
|
log.success("Opening Firebase Console...");
|
|
19170
19410
|
} catch {
|
|
19171
19411
|
log.warn("Could not open browser. Please open the URL manually.");
|
|
@@ -19236,7 +19476,7 @@ function detectProvider(appDir) {
|
|
|
19236
19476
|
if (hasFirebase) {
|
|
19237
19477
|
try {
|
|
19238
19478
|
const config = readSync(firebaseJsonPath, { format: "json" });
|
|
19239
|
-
if (config && typeof config === "object"
|
|
19479
|
+
if (config && typeof config === "object") {
|
|
19240
19480
|
const firebaseConfigObj = config;
|
|
19241
19481
|
firebaseConfig = {
|
|
19242
19482
|
projectId: firebaseConfigObj.projectId,
|
|
@@ -19245,8 +19485,6 @@ function detectProvider(appDir) {
|
|
|
19245
19485
|
hasFirestoreRules: !!firebaseConfigObj.firestore?.rules,
|
|
19246
19486
|
hasStorageRules: !!firebaseConfigObj.storage?.rules
|
|
19247
19487
|
};
|
|
19248
|
-
} else {
|
|
19249
|
-
throw new Error("Invalid firebase.json structure");
|
|
19250
19488
|
}
|
|
19251
19489
|
} catch {
|
|
19252
19490
|
firebaseConfig = {
|
|
@@ -19554,7 +19792,7 @@ async function main6(options = {}) {
|
|
|
19554
19792
|
isStaging ? "Building (staging mode)..." : "Building application..."
|
|
19555
19793
|
);
|
|
19556
19794
|
try {
|
|
19557
|
-
|
|
19795
|
+
execSync10(buildCmd, {
|
|
19558
19796
|
cwd: appDir,
|
|
19559
19797
|
stdio: "inherit",
|
|
19560
19798
|
env: {
|
|
@@ -19799,10 +20037,10 @@ function generatePackageJson(templateName, mode, options = {}) {
|
|
|
19799
20037
|
}
|
|
19800
20038
|
if (templateName.includes("functions")) {
|
|
19801
20039
|
result.main = "lib/index.js";
|
|
19802
|
-
result.engines = { node: "
|
|
20040
|
+
result.engines = { node: "22" };
|
|
19803
20041
|
if (options.appName) {
|
|
19804
|
-
const
|
|
19805
|
-
result.description = `${options.appName} ${
|
|
20042
|
+
const platform6 = templateName.includes("vercel") ? "Vercel" : "Firebase";
|
|
20043
|
+
result.description = `${options.appName} ${platform6} Functions`;
|
|
19806
20044
|
}
|
|
19807
20045
|
if (mode === "development") {
|
|
19808
20046
|
const workspacePkgs = [
|
|
@@ -19846,15 +20084,15 @@ init_utils();
|
|
|
19846
20084
|
var MATRIX = [
|
|
19847
20085
|
{ builder: "vite", backend: "none", baseTemplate: "app-vite", overlay: null, deployConfig: null, functionsTemplate: null },
|
|
19848
20086
|
{ builder: "vite", backend: "firebase", baseTemplate: "app-vite", overlay: "overlay-firebase", deployConfig: "firebase", functionsTemplate: "functions-firebase" },
|
|
19849
|
-
{ builder: "vite", backend: "supabase", baseTemplate: "app-vite", overlay: "overlay-supabase", deployConfig: "vercel-supabase", functionsTemplate:
|
|
20087
|
+
{ builder: "vite", backend: "supabase", baseTemplate: "app-vite", overlay: "overlay-supabase", deployConfig: "vercel-supabase", functionsTemplate: "functions-supabase" },
|
|
19850
20088
|
{ builder: "vite", backend: "vercel", baseTemplate: "app-vite", overlay: "overlay-vercel", deployConfig: "vercel-vercel", functionsTemplate: "functions-vercel" },
|
|
19851
20089
|
{ builder: "nextjs", backend: "none", baseTemplate: "app-next", overlay: null, deployConfig: null, functionsTemplate: null },
|
|
19852
20090
|
{ builder: "nextjs", backend: "firebase", baseTemplate: "app-next", overlay: "overlay-firebase", deployConfig: "firebase", functionsTemplate: "functions-firebase" },
|
|
19853
|
-
{ builder: "nextjs", backend: "supabase", baseTemplate: "app-next", overlay: "overlay-supabase", deployConfig: "vercel-supabase", functionsTemplate:
|
|
20091
|
+
{ builder: "nextjs", backend: "supabase", baseTemplate: "app-next", overlay: "overlay-supabase", deployConfig: "vercel-supabase", functionsTemplate: "functions-supabase" },
|
|
19854
20092
|
{ builder: "nextjs", backend: "vercel", baseTemplate: "app-next", overlay: "overlay-vercel", deployConfig: "vercel-vercel", functionsTemplate: "functions-vercel" },
|
|
19855
20093
|
{ builder: "expo", backend: "none", baseTemplate: "app-expo", overlay: null, deployConfig: null, functionsTemplate: null },
|
|
19856
20094
|
{ builder: "expo", backend: "firebase", baseTemplate: "app-expo", overlay: "overlay-firebase", deployConfig: null, functionsTemplate: "functions-firebase" },
|
|
19857
|
-
{ builder: "expo", backend: "supabase", baseTemplate: "app-expo", overlay: "overlay-supabase", deployConfig: null, functionsTemplate:
|
|
20095
|
+
{ builder: "expo", backend: "supabase", baseTemplate: "app-expo", overlay: "overlay-supabase", deployConfig: null, functionsTemplate: "functions-supabase" },
|
|
19858
20096
|
{ builder: "demo", backend: "none", baseTemplate: "app-demo", overlay: null, deployConfig: null, functionsTemplate: null }
|
|
19859
20097
|
];
|
|
19860
20098
|
function comboKey(builder, backend) {
|
|
@@ -20029,7 +20267,7 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
|
|
|
20029
20267
|
if (providersVariant[1] !== appTemplate) continue;
|
|
20030
20268
|
const destPath2 = joinPath(appDir, "src/config/providers.ts");
|
|
20031
20269
|
await ensureDir(getDirname(destPath2));
|
|
20032
|
-
await copy(joinPath(overlayDir, file), destPath2);
|
|
20270
|
+
await copy(joinPath(overlayDir, file), destPath2, { overwrite: true });
|
|
20033
20271
|
if (await isTextFile(destPath2)) await replacePlaceholders(destPath2, replacements);
|
|
20034
20272
|
continue;
|
|
20035
20273
|
}
|
|
@@ -20040,7 +20278,7 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
|
|
|
20040
20278
|
}
|
|
20041
20279
|
const destPath = joinPath(appDir, destFileName);
|
|
20042
20280
|
await ensureDir(getDirname(destPath));
|
|
20043
|
-
await copy(sourcePath, destPath);
|
|
20281
|
+
await copy(sourcePath, destPath, { overwrite: true });
|
|
20044
20282
|
if (await isTextFile(destPath)) {
|
|
20045
20283
|
await replacePlaceholders(destPath, replacements);
|
|
20046
20284
|
}
|
|
@@ -20083,23 +20321,26 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
|
|
|
20083
20321
|
overwrite: true
|
|
20084
20322
|
});
|
|
20085
20323
|
if (row.functionsTemplate) {
|
|
20086
|
-
const functionsRootDir = joinPath(appDir, "functions");
|
|
20087
20324
|
const functionsTemplateName = row.functionsTemplate;
|
|
20088
20325
|
const functionsTemplateExists = pathExists(joinPath(templatesRoot, functionsTemplateName));
|
|
20089
20326
|
if (!functionsTemplateExists) {
|
|
20090
20327
|
log.warn(`Functions template "${functionsTemplateName}" not found \u2014 skipping functions scaffolding.`);
|
|
20091
20328
|
} else {
|
|
20092
|
-
const
|
|
20093
|
-
|
|
20094
|
-
|
|
20095
|
-
|
|
20096
|
-
|
|
20097
|
-
|
|
20098
|
-
|
|
20099
|
-
|
|
20100
|
-
|
|
20101
|
-
|
|
20102
|
-
|
|
20329
|
+
const isSupabaseFunctions = functionsTemplateName === "functions-supabase";
|
|
20330
|
+
const functionsRootDir = isSupabaseFunctions ? appDir : joinPath(appDir, "functions");
|
|
20331
|
+
if (!isSupabaseFunctions) {
|
|
20332
|
+
const functionsPackageJson = generatePackageJson(
|
|
20333
|
+
functionsTemplateName,
|
|
20334
|
+
executionMode,
|
|
20335
|
+
{ appName, platform: row.functionsTemplate.replace("functions-", "") }
|
|
20336
|
+
);
|
|
20337
|
+
const packageJsonPath2 = joinPath(functionsRootDir, "package.json");
|
|
20338
|
+
await ensureDir(functionsRootDir);
|
|
20339
|
+
await write(packageJsonPath2, functionsPackageJson, {
|
|
20340
|
+
format: "json",
|
|
20341
|
+
overwrite: true
|
|
20342
|
+
});
|
|
20343
|
+
}
|
|
20103
20344
|
const templateDir2 = joinPath(templatesRoot, functionsTemplateName);
|
|
20104
20345
|
const templateFiles2 = await glob("**/*", {
|
|
20105
20346
|
cwd: templateDir2,
|
|
@@ -20132,6 +20373,18 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
|
|
|
20132
20373
|
await copy(firebaseJsonSource, joinPath(appDir, "firebase.json"));
|
|
20133
20374
|
const firebaseJsonDest = joinPath(appDir, "firebase.json");
|
|
20134
20375
|
if (await isTextFile(firebaseJsonDest)) await replacePlaceholders(firebaseJsonDest, replacements);
|
|
20376
|
+
if (appTemplate === "nextjs") {
|
|
20377
|
+
const firebaseJson = readSync(firebaseJsonDest, { format: "json" });
|
|
20378
|
+
if (firebaseJson.hosting?.rewrites) {
|
|
20379
|
+
firebaseJson.hosting.rewrites = firebaseJson.hosting.rewrites.filter(
|
|
20380
|
+
(r2) => r2.destination !== "/index.html"
|
|
20381
|
+
);
|
|
20382
|
+
}
|
|
20383
|
+
if (firebaseJson.hosting) {
|
|
20384
|
+
firebaseJson.hosting.public = "out";
|
|
20385
|
+
}
|
|
20386
|
+
await write(firebaseJsonDest, firebaseJson, { format: "json", overwrite: true });
|
|
20387
|
+
}
|
|
20135
20388
|
}
|
|
20136
20389
|
const firebasercSource = joinPath(deploymentTemplateDir, ".firebaserc.example");
|
|
20137
20390
|
if (pathExists(firebasercSource)) {
|
|
@@ -20148,6 +20401,44 @@ async function createApp(appName, appConfig, workspaceRoot, templatesRoot) {
|
|
|
20148
20401
|
}
|
|
20149
20402
|
}
|
|
20150
20403
|
}
|
|
20404
|
+
if (!deployConfig && backend === "firebase" && row.functionsTemplate) {
|
|
20405
|
+
const firebaseJsonPath = joinPath(appDir, "firebase.json");
|
|
20406
|
+
if (!pathExists(firebaseJsonPath)) {
|
|
20407
|
+
const expoFirebaseJson = {
|
|
20408
|
+
functions: [
|
|
20409
|
+
{
|
|
20410
|
+
source: "functions",
|
|
20411
|
+
codebase: "default",
|
|
20412
|
+
ignore: ["node_modules", ".git", "firebase-debug.log", "firebase-debug.*.log", "**/.*", "**/*.test.ts", "**/__tests__/**"],
|
|
20413
|
+
runtime: "nodejs22"
|
|
20414
|
+
}
|
|
20415
|
+
],
|
|
20416
|
+
firestore: { rules: "firestore.rules", indexes: "firestore.indexes.json" },
|
|
20417
|
+
storage: { rules: "storage.rules" },
|
|
20418
|
+
emulators: {
|
|
20419
|
+
auth: { port: 9099 },
|
|
20420
|
+
functions: { port: 5001 },
|
|
20421
|
+
firestore: { port: 8080 },
|
|
20422
|
+
storage: { port: 9199 },
|
|
20423
|
+
ui: { enabled: true, port: 4e3 }
|
|
20424
|
+
}
|
|
20425
|
+
};
|
|
20426
|
+
await write(firebaseJsonPath, expoFirebaseJson, { format: "json", overwrite: true });
|
|
20427
|
+
}
|
|
20428
|
+
const firebasercSource = joinPath(deploymentTemplateDir, ".firebaserc.example");
|
|
20429
|
+
const firebasercDest = joinPath(appDir, ".firebaserc");
|
|
20430
|
+
if (pathExists(firebasercSource) && !pathExists(firebasercDest)) {
|
|
20431
|
+
await copy(firebasercSource, firebasercDest);
|
|
20432
|
+
if (await isTextFile(firebasercDest)) await replacePlaceholders(firebasercDest, replacements);
|
|
20433
|
+
}
|
|
20434
|
+
for (const example of ["firestore.rules.example", "firestore.indexes.json.example", "storage.rules.example"]) {
|
|
20435
|
+
const src = joinPath(deploymentTemplateDir, example);
|
|
20436
|
+
const dest = joinPath(appDir, example.replace(".example", ""));
|
|
20437
|
+
if (pathExists(src) && !pathExists(dest)) {
|
|
20438
|
+
await copy(src, dest);
|
|
20439
|
+
}
|
|
20440
|
+
}
|
|
20441
|
+
}
|
|
20151
20442
|
if (deployConfig === "vercel-vercel") {
|
|
20152
20443
|
const vercelJsonSource = joinPath(deploymentTemplateDir, "vercel.json.example");
|
|
20153
20444
|
if (pathExists(vercelJsonSource)) {
|
|
@@ -20228,23 +20519,25 @@ init_cli_input();
|
|
|
20228
20519
|
init_cli_output();
|
|
20229
20520
|
init_pathResolver();
|
|
20230
20521
|
var SHOW_WIP2 = process.env.SHOW_WIP === "true" || process.argv.includes("--wip");
|
|
20231
|
-
|
|
20232
|
-
|
|
20233
|
-
|
|
20234
|
-
|
|
20235
|
-
|
|
20236
|
-
}
|
|
20237
|
-
|
|
20238
|
-
|
|
20239
|
-
|
|
20240
|
-
|
|
20241
|
-
|
|
20242
|
-
|
|
20243
|
-
|
|
20244
|
-
|
|
20245
|
-
]
|
|
20246
|
-
|
|
20247
|
-
|
|
20522
|
+
async function collectAppConfig(appName) {
|
|
20523
|
+
const answers = await runQuestionnaire(APP_QUESTIONNAIRE, {}, SHOW_WIP2, {
|
|
20524
|
+
selection: askForSelection,
|
|
20525
|
+
confirmation: askForConfirmation,
|
|
20526
|
+
input: askForInput
|
|
20527
|
+
});
|
|
20528
|
+
const framework = answers.framework || "vite";
|
|
20529
|
+
const needsBackend = answers.needsBackend || false;
|
|
20530
|
+
const defaultPlatform = framework === "nextjs" ? "vercel" : "firebase";
|
|
20531
|
+
return {
|
|
20532
|
+
template: framework,
|
|
20533
|
+
needsBackend,
|
|
20534
|
+
backendPlatform: needsBackend ? answers.backendPlatform || defaultPlatform : void 0,
|
|
20535
|
+
needsCRUD: false,
|
|
20536
|
+
selectedEntities: [],
|
|
20537
|
+
userAuth: "none",
|
|
20538
|
+
billing: false,
|
|
20539
|
+
features: []
|
|
20540
|
+
};
|
|
20248
20541
|
}
|
|
20249
20542
|
function calculateRelativePath(from, to) {
|
|
20250
20543
|
try {
|
|
@@ -20286,8 +20579,8 @@ async function main9(options) {
|
|
|
20286
20579
|
try {
|
|
20287
20580
|
Ie("\u{1F680} DoNotDev Project Creator");
|
|
20288
20581
|
try {
|
|
20289
|
-
const { execSync:
|
|
20290
|
-
|
|
20582
|
+
const { execSync: execSync11 } = await import("node:child_process");
|
|
20583
|
+
execSync11("bun --version", { stdio: "ignore" });
|
|
20291
20584
|
} catch {
|
|
20292
20585
|
log.error("bun is required but not installed.");
|
|
20293
20586
|
Me(
|
|
@@ -20357,71 +20650,22 @@ async function main9(options) {
|
|
|
20357
20650
|
let appNames = [];
|
|
20358
20651
|
const appConfigs = {};
|
|
20359
20652
|
let anyAppNeedsBackend = false;
|
|
20360
|
-
|
|
20361
|
-
|
|
20362
|
-
""
|
|
20363
|
-
|
|
20364
|
-
|
|
20365
|
-
|
|
20366
|
-
if (isReservedAppName(trimmedName)) {
|
|
20367
|
-
log.warn(`'${trimmedName}' is reserved for framework demos.`);
|
|
20368
|
-
} else if (!isValidFileName(trimmedName)) {
|
|
20369
|
-
log.warn(
|
|
20370
|
-
`Invalid app name. Use only letters, numbers, dashes (-), and underscores (_).`
|
|
20371
|
-
);
|
|
20372
|
-
} else {
|
|
20373
|
-
appNames.push(trimmedName);
|
|
20374
|
-
const framework = await askForSelection(
|
|
20375
|
-
`Builder for "${trimmedName}"?`,
|
|
20376
|
-
[
|
|
20377
|
-
{
|
|
20378
|
-
title: "Vite \u2014 SPA/SaaS (client-side rendering, fast dev)",
|
|
20379
|
-
value: "vite"
|
|
20380
|
-
},
|
|
20381
|
-
{
|
|
20382
|
-
title: "Next.js \u2014 Static content/SEO (SSR, SSG) \u2014 DoNotDev support: BETA",
|
|
20383
|
-
value: "nextjs"
|
|
20384
|
-
},
|
|
20385
|
-
{
|
|
20386
|
-
title: "Expo \u2014 Mobile app (iOS + Android, single codebase)",
|
|
20387
|
-
value: "expo"
|
|
20388
|
-
}
|
|
20389
|
-
],
|
|
20390
|
-
0
|
|
20391
|
-
);
|
|
20392
|
-
const backendValue = await askForSelection(
|
|
20393
|
-
`Backend for "${trimmedName}"?`,
|
|
20394
|
-
[...BACKEND_CHOICES],
|
|
20395
|
-
getDefaultBackendIndex(framework)
|
|
20396
|
-
);
|
|
20397
|
-
const needsBackend = backendValue !== "none";
|
|
20398
|
-
if (needsBackend) anyAppNeedsBackend = true;
|
|
20399
|
-
appConfigs[trimmedName] = {
|
|
20400
|
-
template: framework,
|
|
20401
|
-
needsBackend,
|
|
20402
|
-
backendPlatform: needsBackend ? backendValue : void 0,
|
|
20403
|
-
needsCRUD: false,
|
|
20404
|
-
selectedEntities: [],
|
|
20405
|
-
userAuth: "none",
|
|
20406
|
-
billing: false,
|
|
20407
|
-
features: []
|
|
20408
|
-
};
|
|
20409
|
-
}
|
|
20410
|
-
}
|
|
20411
|
-
while (appNames.length > 0) {
|
|
20412
|
-
const appName = await askForInput("App name (press Enter to finish)", "");
|
|
20413
|
-
if (!appName || appName.trim() === "") {
|
|
20653
|
+
let isFirstApp = true;
|
|
20654
|
+
while (true) {
|
|
20655
|
+
const prompt = isFirstApp ? "What's your first app name? (press Enter to skip)" : "App name (press Enter to finish)";
|
|
20656
|
+
const appNameInput = await askForInput(prompt, "");
|
|
20657
|
+
if (!appNameInput || appNameInput.trim() === "") {
|
|
20658
|
+
if (isFirstApp) break;
|
|
20414
20659
|
break;
|
|
20415
20660
|
}
|
|
20416
|
-
const trimmedName =
|
|
20661
|
+
const trimmedName = appNameInput.trim();
|
|
20662
|
+
isFirstApp = false;
|
|
20417
20663
|
if (appNames.includes(trimmedName)) {
|
|
20418
20664
|
log.warn(`'${trimmedName}' already exists. Choose a different name.`);
|
|
20419
20665
|
continue;
|
|
20420
20666
|
}
|
|
20421
20667
|
if (isReservedAppName(trimmedName)) {
|
|
20422
|
-
log.warn(
|
|
20423
|
-
`'${trimmedName}' is reserved for framework demos. Choose a different name.`
|
|
20424
|
-
);
|
|
20668
|
+
log.warn(`'${trimmedName}' is reserved for framework demos.`);
|
|
20425
20669
|
continue;
|
|
20426
20670
|
}
|
|
20427
20671
|
if (!isValidFileName(trimmedName)) {
|
|
@@ -20431,37 +20675,10 @@ async function main9(options) {
|
|
|
20431
20675
|
continue;
|
|
20432
20676
|
}
|
|
20433
20677
|
appNames.push(trimmedName);
|
|
20434
|
-
|
|
20435
|
-
|
|
20436
|
-
|
|
20437
|
-
|
|
20438
|
-
title: "Vite \u2014 SPA/SaaS (client-side rendering, fast dev)",
|
|
20439
|
-
value: "vite"
|
|
20440
|
-
},
|
|
20441
|
-
{
|
|
20442
|
-
title: "Next.js \u2014 Static content/SEO (SSR, SSG) \u2014 DoNotDev support: BETA",
|
|
20443
|
-
value: "nextjs"
|
|
20444
|
-
}
|
|
20445
|
-
],
|
|
20446
|
-
0
|
|
20447
|
-
);
|
|
20448
|
-
const backendValue = await askForSelection(
|
|
20449
|
-
`Backend for "${trimmedName}"?`,
|
|
20450
|
-
[...BACKEND_CHOICES],
|
|
20451
|
-
getDefaultBackendIndex(framework)
|
|
20452
|
-
);
|
|
20453
|
-
const needsBackend = backendValue !== "none";
|
|
20454
|
-
if (needsBackend) anyAppNeedsBackend = true;
|
|
20455
|
-
appConfigs[trimmedName] = {
|
|
20456
|
-
template: framework,
|
|
20457
|
-
needsBackend,
|
|
20458
|
-
backendPlatform: needsBackend ? backendValue : void 0,
|
|
20459
|
-
needsCRUD: false,
|
|
20460
|
-
selectedEntities: [],
|
|
20461
|
-
userAuth: "none",
|
|
20462
|
-
billing: false,
|
|
20463
|
-
features: []
|
|
20464
|
-
};
|
|
20678
|
+
Me(`Configuring "${trimmedName}"...`, "\u2699\uFE0F");
|
|
20679
|
+
const config = await collectAppConfig(trimmedName);
|
|
20680
|
+
appConfigs[trimmedName] = config;
|
|
20681
|
+
if (config.needsBackend) anyAppNeedsBackend = true;
|
|
20465
20682
|
}
|
|
20466
20683
|
let installDemoApp = await askForConfirmation(
|
|
20467
20684
|
"Would you like to install the demo app? (component showcase)",
|
|
@@ -20793,7 +21010,7 @@ init_utils();
|
|
|
20793
21010
|
init_cli_output();
|
|
20794
21011
|
init_errors();
|
|
20795
21012
|
init_pathResolver();
|
|
20796
|
-
import { spawnSync as
|
|
21013
|
+
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
20797
21014
|
import { EOL as EOL2 } from "node:os";
|
|
20798
21015
|
async function main10(options = {}) {
|
|
20799
21016
|
const dryRun = options.dryRun ?? false;
|
|
@@ -21270,7 +21487,7 @@ async function runPrettier(rootDir, dryRun, verbose) {
|
|
|
21270
21487
|
log.info("DRY RUN: Would run Prettier");
|
|
21271
21488
|
return stats;
|
|
21272
21489
|
}
|
|
21273
|
-
const result =
|
|
21490
|
+
const result = spawnSync10("bunx", prettierArgs, {
|
|
21274
21491
|
cwd: rootDir,
|
|
21275
21492
|
stdio: "pipe",
|
|
21276
21493
|
shell: true,
|