clawfire 0.6.8 → 0.6.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +1 -1
- package/dist/{dev-server-ESMIOA6C.js → dev-server-6BALG4FC.js} +150 -16
- package/dist/dev.cjs +150 -16
- package/dist/dev.cjs.map +1 -1
- package/dist/dev.js +150 -16
- package/dist/dev.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -269,7 +269,7 @@ async function runDevServer() {
|
|
|
269
269
|
const port = portArg ? parseInt(portArg.split("=")[1], 10) : 3e3;
|
|
270
270
|
const apiPort = apiPortArg ? parseInt(apiPortArg.split("=")[1], 10) : 3456;
|
|
271
271
|
const noHotReload = args.includes("--no-hot-reload");
|
|
272
|
-
const { startDevServer } = await import("./dev-server-
|
|
272
|
+
const { startDevServer } = await import("./dev-server-6BALG4FC.js");
|
|
273
273
|
await startDevServer({
|
|
274
274
|
projectDir,
|
|
275
275
|
port,
|
|
@@ -2956,7 +2956,7 @@ var FirebaseSetup = class {
|
|
|
2956
2956
|
return { success: true, message: `Web app "${displayName}" selected.` };
|
|
2957
2957
|
}
|
|
2958
2958
|
// ─── Deploy ─────────────────────────────────────────────────────────
|
|
2959
|
-
async deployHosting() {
|
|
2959
|
+
async deployHosting(targets = "hosting") {
|
|
2960
2960
|
const firebaseJsonPath = resolve4(this.projectDir, "firebase.json");
|
|
2961
2961
|
if (!existsSync5(firebaseJsonPath)) {
|
|
2962
2962
|
return { success: false, message: "firebase.json not found. Enable hosting first." };
|
|
@@ -2969,12 +2969,12 @@ var FirebaseSetup = class {
|
|
|
2969
2969
|
} catch {
|
|
2970
2970
|
return { success: false, message: "Invalid firebase.json." };
|
|
2971
2971
|
}
|
|
2972
|
+
const timeoutMs = targets.includes("functions") ? 3e5 : 12e4;
|
|
2972
2973
|
try {
|
|
2973
2974
|
const output = await this.execTimeout(
|
|
2974
2975
|
"firebase",
|
|
2975
|
-
["deploy", "--only",
|
|
2976
|
-
|
|
2977
|
-
// 2 min timeout
|
|
2976
|
+
["deploy", "--only", targets, "--json"],
|
|
2977
|
+
timeoutMs
|
|
2978
2978
|
);
|
|
2979
2979
|
let url = "";
|
|
2980
2980
|
try {
|
|
@@ -2997,12 +2997,111 @@ var FirebaseSetup = class {
|
|
|
2997
2997
|
url = `https://${state.projectId}.web.app`;
|
|
2998
2998
|
}
|
|
2999
2999
|
}
|
|
3000
|
-
|
|
3000
|
+
const label = targets.includes("functions") ? "Hosting + Functions" : "Hosting";
|
|
3001
|
+
return { success: true, url: url || void 0, message: `${label} deployed successfully!` };
|
|
3001
3002
|
} catch (err) {
|
|
3002
3003
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
3003
3004
|
return { success: false, message: `Deploy failed: ${msg}` };
|
|
3004
3005
|
}
|
|
3005
3006
|
}
|
|
3007
|
+
// ─── Full Deploy Pipeline ────────────────────────────────────────────
|
|
3008
|
+
/**
|
|
3009
|
+
* Sync environment variables to functions/.env for production.
|
|
3010
|
+
* Copies project root .env vars + injects CLAWFIRE_FIREBASE_CONFIG.
|
|
3011
|
+
*/
|
|
3012
|
+
syncEnvToFunctions(firebaseConfig) {
|
|
3013
|
+
const functionsDir = resolve4(this.projectDir, "functions");
|
|
3014
|
+
if (!existsSync5(functionsDir)) {
|
|
3015
|
+
return { success: false, message: "functions/ directory not found.", count: 0 };
|
|
3016
|
+
}
|
|
3017
|
+
const lines = [];
|
|
3018
|
+
const rootEnvPath = resolve4(this.projectDir, ".env");
|
|
3019
|
+
if (existsSync5(rootEnvPath)) {
|
|
3020
|
+
const content = readFileSync4(rootEnvPath, "utf-8");
|
|
3021
|
+
for (const rawLine of content.split("\n")) {
|
|
3022
|
+
let trimmed = rawLine.trim();
|
|
3023
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
3024
|
+
if (trimmed.startsWith("export ")) {
|
|
3025
|
+
trimmed = trimmed.slice(7);
|
|
3026
|
+
}
|
|
3027
|
+
const eqIdx = trimmed.indexOf("=");
|
|
3028
|
+
if (eqIdx === -1) continue;
|
|
3029
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
3030
|
+
if (key === "NPM_TOKEN" || key === "NODE_ENV") continue;
|
|
3031
|
+
lines.push(trimmed);
|
|
3032
|
+
}
|
|
3033
|
+
}
|
|
3034
|
+
if (firebaseConfig && Object.keys(firebaseConfig).length > 0) {
|
|
3035
|
+
const filtered = lines.filter((l) => !l.startsWith("CLAWFIRE_FIREBASE_CONFIG="));
|
|
3036
|
+
filtered.push(`CLAWFIRE_FIREBASE_CONFIG=${JSON.stringify(firebaseConfig)}`);
|
|
3037
|
+
lines.length = 0;
|
|
3038
|
+
lines.push(...filtered);
|
|
3039
|
+
}
|
|
3040
|
+
const functionsEnvPath = resolve4(functionsDir, ".env");
|
|
3041
|
+
writeFileSync3(functionsEnvPath, lines.join("\n") + "\n", "utf-8");
|
|
3042
|
+
return { success: true, message: `Synced ${lines.length} env vars to functions/.env`, count: lines.length };
|
|
3043
|
+
}
|
|
3044
|
+
/**
|
|
3045
|
+
* Ensure firebase.json has functions configuration.
|
|
3046
|
+
*/
|
|
3047
|
+
ensureFunctionsConfig() {
|
|
3048
|
+
const firebaseJsonPath = resolve4(this.projectDir, "firebase.json");
|
|
3049
|
+
if (!existsSync5(firebaseJsonPath)) {
|
|
3050
|
+
return { success: false, message: "firebase.json not found." };
|
|
3051
|
+
}
|
|
3052
|
+
try {
|
|
3053
|
+
const config = JSON.parse(readFileSync4(firebaseJsonPath, "utf-8"));
|
|
3054
|
+
if (!config.functions) {
|
|
3055
|
+
config.functions = {
|
|
3056
|
+
source: "functions",
|
|
3057
|
+
runtime: "nodejs20",
|
|
3058
|
+
codebase: "clawfire"
|
|
3059
|
+
};
|
|
3060
|
+
writeFileSync3(firebaseJsonPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
3061
|
+
return { success: true, message: "Functions config added to firebase.json." };
|
|
3062
|
+
}
|
|
3063
|
+
return { success: true, message: "Functions config already present." };
|
|
3064
|
+
} catch {
|
|
3065
|
+
return { success: false, message: "Invalid firebase.json." };
|
|
3066
|
+
}
|
|
3067
|
+
}
|
|
3068
|
+
/**
|
|
3069
|
+
* Install dependencies and build functions for deployment.
|
|
3070
|
+
*/
|
|
3071
|
+
async buildFunctions() {
|
|
3072
|
+
const functionsDir = resolve4(this.projectDir, "functions");
|
|
3073
|
+
if (!existsSync5(functionsDir)) {
|
|
3074
|
+
return { success: false, message: "functions/ directory not found." };
|
|
3075
|
+
}
|
|
3076
|
+
const pkgPath = resolve4(functionsDir, "package.json");
|
|
3077
|
+
if (!existsSync5(pkgPath)) {
|
|
3078
|
+
return { success: false, message: "functions/package.json not found." };
|
|
3079
|
+
}
|
|
3080
|
+
const nodeModulesPath = resolve4(functionsDir, "node_modules");
|
|
3081
|
+
if (!existsSync5(nodeModulesPath)) {
|
|
3082
|
+
try {
|
|
3083
|
+
await this.execTimeout("npm", ["install"], 12e4, functionsDir);
|
|
3084
|
+
} catch (err) {
|
|
3085
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
3086
|
+
return { success: false, message: `npm install in functions/ failed: ${msg}` };
|
|
3087
|
+
}
|
|
3088
|
+
}
|
|
3089
|
+
try {
|
|
3090
|
+
const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
|
|
3091
|
+
if (pkg.scripts?.build) {
|
|
3092
|
+
await this.execTimeout("npm", ["run", "build"], 6e4, functionsDir);
|
|
3093
|
+
} else {
|
|
3094
|
+
const tsconfigPath = resolve4(functionsDir, "tsconfig.json");
|
|
3095
|
+
if (existsSync5(tsconfigPath)) {
|
|
3096
|
+
await this.execTimeout("npx", ["tsc"], 6e4, functionsDir);
|
|
3097
|
+
}
|
|
3098
|
+
}
|
|
3099
|
+
return { success: true, message: "Functions built successfully." };
|
|
3100
|
+
} catch (err) {
|
|
3101
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
3102
|
+
return { success: false, message: `Functions build failed: ${msg}` };
|
|
3103
|
+
}
|
|
3104
|
+
}
|
|
3006
3105
|
// ─── Service Enable ────────────────────────────────────────────────
|
|
3007
3106
|
enableService(service) {
|
|
3008
3107
|
const firebaseJsonPath = resolve4(this.projectDir, "firebase.json");
|
|
@@ -3251,9 +3350,9 @@ https://console.developers.google.com/apis/api/firestore.googleapis.com/overview
|
|
|
3251
3350
|
}
|
|
3252
3351
|
}
|
|
3253
3352
|
// ─── Helpers ───────────────────────────────────────────────────────
|
|
3254
|
-
execTimeout(command, args, timeoutMs) {
|
|
3353
|
+
execTimeout(command, args, timeoutMs, cwd) {
|
|
3255
3354
|
return new Promise((resolve6, reject) => {
|
|
3256
|
-
const proc = execFile2(command, args, { cwd: this.projectDir, timeout: timeoutMs }, (err, stdout, stderr) => {
|
|
3355
|
+
const proc = execFile2(command, args, { cwd: cwd || this.projectDir, timeout: timeoutMs }, (err, stdout, stderr) => {
|
|
3257
3356
|
if (err) {
|
|
3258
3357
|
const detail = stderr?.trim() || stdout?.trim() || "";
|
|
3259
3358
|
const enriched = new Error(`${err.message}${detail ? "\n" + detail : ""}`);
|
|
@@ -4416,22 +4515,27 @@ ${liveReloadScript}
|
|
|
4416
4515
|
if (url.pathname === "/__dev/deploy/hosting" && req.method === "POST") {
|
|
4417
4516
|
(async () => {
|
|
4418
4517
|
try {
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4518
|
+
const steps = [];
|
|
4519
|
+
const functionsDir = resolve5(this.options.projectDir, "functions");
|
|
4520
|
+
const hasFunctions = existsSync6(functionsDir);
|
|
4521
|
+
const projectConfig = this.readProjectConfig();
|
|
4522
|
+
const firebaseConfig = {};
|
|
4523
|
+
for (const field of projectConfig.fields) {
|
|
4524
|
+
if (!field.isPlaceholder) {
|
|
4525
|
+
firebaseConfig[field.key] = field.value;
|
|
4426
4526
|
}
|
|
4527
|
+
}
|
|
4528
|
+
if (this.pageCompiler.isActive()) {
|
|
4427
4529
|
const configScript = Object.keys(firebaseConfig).length > 0 ? `
|
|
4428
4530
|
<script>window.__CLAWFIRE_CONFIG__=${JSON.stringify(firebaseConfig)};</script>` : "";
|
|
4429
4531
|
const routerScript = generateProductionRouterScript();
|
|
4430
4532
|
const scriptToInject = configScript + routerScript;
|
|
4431
4533
|
const buildResult = this.pageCompiler.buildForProduction(this.publicDir, scriptToInject);
|
|
4432
4534
|
console.log(` \x1B[32m\u2713\x1B[0m Built ${buildResult.pages.length} pages for production`);
|
|
4535
|
+
steps.push(`${buildResult.pages.length} pages built`);
|
|
4433
4536
|
if (configScript) {
|
|
4434
4537
|
console.log(` \x1B[32m\u2713\x1B[0m Firebase config injected (projectId: ${firebaseConfig.projectId || "?"})`);
|
|
4538
|
+
steps.push("Firebase config injected");
|
|
4435
4539
|
}
|
|
4436
4540
|
if (buildResult.errors.length > 0) {
|
|
4437
4541
|
for (const err of buildResult.errors) {
|
|
@@ -4439,9 +4543,39 @@ ${liveReloadScript}
|
|
|
4439
4543
|
}
|
|
4440
4544
|
}
|
|
4441
4545
|
}
|
|
4442
|
-
|
|
4546
|
+
let deployFunctions = false;
|
|
4547
|
+
if (hasFunctions) {
|
|
4548
|
+
const syncResult = this.firebaseSetup.syncEnvToFunctions(firebaseConfig);
|
|
4549
|
+
if (syncResult.success) {
|
|
4550
|
+
console.log(` \x1B[32m\u2713\x1B[0m ${syncResult.message}`);
|
|
4551
|
+
steps.push(`${syncResult.count} env vars synced`);
|
|
4552
|
+
} else {
|
|
4553
|
+
console.log(` \x1B[33m\u26A0\x1B[0m Env sync: ${syncResult.message}`);
|
|
4554
|
+
}
|
|
4555
|
+
const configResult = this.firebaseSetup.ensureFunctionsConfig();
|
|
4556
|
+
if (configResult.success) {
|
|
4557
|
+
console.log(` \x1B[32m\u2713\x1B[0m ${configResult.message}`);
|
|
4558
|
+
}
|
|
4559
|
+
console.log(" Building functions...");
|
|
4560
|
+
const buildResult = await this.firebaseSetup.buildFunctions();
|
|
4561
|
+
if (buildResult.success) {
|
|
4562
|
+
console.log(` \x1B[32m\u2713\x1B[0m ${buildResult.message}`);
|
|
4563
|
+
steps.push("Functions built");
|
|
4564
|
+
deployFunctions = true;
|
|
4565
|
+
} else {
|
|
4566
|
+
console.log(` \x1B[31m\u2717\x1B[0m ${buildResult.message}`);
|
|
4567
|
+
console.log(" \x1B[33m\u26A0\x1B[0m Deploying hosting only (functions build failed)");
|
|
4568
|
+
steps.push("Functions build failed \u2014 hosting only");
|
|
4569
|
+
}
|
|
4570
|
+
}
|
|
4571
|
+
const targets = deployFunctions ? "hosting,functions" : "hosting";
|
|
4572
|
+
console.log(` Deploying ${targets}...`);
|
|
4573
|
+
const result = await this.firebaseSetup.deployHosting(targets);
|
|
4443
4574
|
clearFirebaseStatusCache();
|
|
4444
|
-
sendJson(
|
|
4575
|
+
sendJson({
|
|
4576
|
+
...result,
|
|
4577
|
+
message: result.message + (steps.length > 0 ? ` (${steps.join(", ")})` : "")
|
|
4578
|
+
});
|
|
4445
4579
|
} catch (err) {
|
|
4446
4580
|
sendJson({ success: false, message: err instanceof Error ? err.message : "Failed" }, 500);
|
|
4447
4581
|
}
|
package/dist/dev.cjs
CHANGED
|
@@ -3368,7 +3368,7 @@ var FirebaseSetup = class {
|
|
|
3368
3368
|
return { success: true, message: `Web app "${displayName}" selected.` };
|
|
3369
3369
|
}
|
|
3370
3370
|
// ─── Deploy ─────────────────────────────────────────────────────────
|
|
3371
|
-
async deployHosting() {
|
|
3371
|
+
async deployHosting(targets = "hosting") {
|
|
3372
3372
|
const firebaseJsonPath = (0, import_node_path4.resolve)(this.projectDir, "firebase.json");
|
|
3373
3373
|
if (!(0, import_node_fs4.existsSync)(firebaseJsonPath)) {
|
|
3374
3374
|
return { success: false, message: "firebase.json not found. Enable hosting first." };
|
|
@@ -3381,12 +3381,12 @@ var FirebaseSetup = class {
|
|
|
3381
3381
|
} catch {
|
|
3382
3382
|
return { success: false, message: "Invalid firebase.json." };
|
|
3383
3383
|
}
|
|
3384
|
+
const timeoutMs = targets.includes("functions") ? 3e5 : 12e4;
|
|
3384
3385
|
try {
|
|
3385
3386
|
const output = await this.execTimeout(
|
|
3386
3387
|
"firebase",
|
|
3387
|
-
["deploy", "--only",
|
|
3388
|
-
|
|
3389
|
-
// 2 min timeout
|
|
3388
|
+
["deploy", "--only", targets, "--json"],
|
|
3389
|
+
timeoutMs
|
|
3390
3390
|
);
|
|
3391
3391
|
let url = "";
|
|
3392
3392
|
try {
|
|
@@ -3409,12 +3409,111 @@ var FirebaseSetup = class {
|
|
|
3409
3409
|
url = `https://${state.projectId}.web.app`;
|
|
3410
3410
|
}
|
|
3411
3411
|
}
|
|
3412
|
-
|
|
3412
|
+
const label = targets.includes("functions") ? "Hosting + Functions" : "Hosting";
|
|
3413
|
+
return { success: true, url: url || void 0, message: `${label} deployed successfully!` };
|
|
3413
3414
|
} catch (err) {
|
|
3414
3415
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
3415
3416
|
return { success: false, message: `Deploy failed: ${msg}` };
|
|
3416
3417
|
}
|
|
3417
3418
|
}
|
|
3419
|
+
// ─── Full Deploy Pipeline ────────────────────────────────────────────
|
|
3420
|
+
/**
|
|
3421
|
+
* Sync environment variables to functions/.env for production.
|
|
3422
|
+
* Copies project root .env vars + injects CLAWFIRE_FIREBASE_CONFIG.
|
|
3423
|
+
*/
|
|
3424
|
+
syncEnvToFunctions(firebaseConfig) {
|
|
3425
|
+
const functionsDir = (0, import_node_path4.resolve)(this.projectDir, "functions");
|
|
3426
|
+
if (!(0, import_node_fs4.existsSync)(functionsDir)) {
|
|
3427
|
+
return { success: false, message: "functions/ directory not found.", count: 0 };
|
|
3428
|
+
}
|
|
3429
|
+
const lines = [];
|
|
3430
|
+
const rootEnvPath = (0, import_node_path4.resolve)(this.projectDir, ".env");
|
|
3431
|
+
if ((0, import_node_fs4.existsSync)(rootEnvPath)) {
|
|
3432
|
+
const content = (0, import_node_fs4.readFileSync)(rootEnvPath, "utf-8");
|
|
3433
|
+
for (const rawLine of content.split("\n")) {
|
|
3434
|
+
let trimmed = rawLine.trim();
|
|
3435
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
3436
|
+
if (trimmed.startsWith("export ")) {
|
|
3437
|
+
trimmed = trimmed.slice(7);
|
|
3438
|
+
}
|
|
3439
|
+
const eqIdx = trimmed.indexOf("=");
|
|
3440
|
+
if (eqIdx === -1) continue;
|
|
3441
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
3442
|
+
if (key === "NPM_TOKEN" || key === "NODE_ENV") continue;
|
|
3443
|
+
lines.push(trimmed);
|
|
3444
|
+
}
|
|
3445
|
+
}
|
|
3446
|
+
if (firebaseConfig && Object.keys(firebaseConfig).length > 0) {
|
|
3447
|
+
const filtered = lines.filter((l) => !l.startsWith("CLAWFIRE_FIREBASE_CONFIG="));
|
|
3448
|
+
filtered.push(`CLAWFIRE_FIREBASE_CONFIG=${JSON.stringify(firebaseConfig)}`);
|
|
3449
|
+
lines.length = 0;
|
|
3450
|
+
lines.push(...filtered);
|
|
3451
|
+
}
|
|
3452
|
+
const functionsEnvPath = (0, import_node_path4.resolve)(functionsDir, ".env");
|
|
3453
|
+
(0, import_node_fs4.writeFileSync)(functionsEnvPath, lines.join("\n") + "\n", "utf-8");
|
|
3454
|
+
return { success: true, message: `Synced ${lines.length} env vars to functions/.env`, count: lines.length };
|
|
3455
|
+
}
|
|
3456
|
+
/**
|
|
3457
|
+
* Ensure firebase.json has functions configuration.
|
|
3458
|
+
*/
|
|
3459
|
+
ensureFunctionsConfig() {
|
|
3460
|
+
const firebaseJsonPath = (0, import_node_path4.resolve)(this.projectDir, "firebase.json");
|
|
3461
|
+
if (!(0, import_node_fs4.existsSync)(firebaseJsonPath)) {
|
|
3462
|
+
return { success: false, message: "firebase.json not found." };
|
|
3463
|
+
}
|
|
3464
|
+
try {
|
|
3465
|
+
const config = JSON.parse((0, import_node_fs4.readFileSync)(firebaseJsonPath, "utf-8"));
|
|
3466
|
+
if (!config.functions) {
|
|
3467
|
+
config.functions = {
|
|
3468
|
+
source: "functions",
|
|
3469
|
+
runtime: "nodejs20",
|
|
3470
|
+
codebase: "clawfire"
|
|
3471
|
+
};
|
|
3472
|
+
(0, import_node_fs4.writeFileSync)(firebaseJsonPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
3473
|
+
return { success: true, message: "Functions config added to firebase.json." };
|
|
3474
|
+
}
|
|
3475
|
+
return { success: true, message: "Functions config already present." };
|
|
3476
|
+
} catch {
|
|
3477
|
+
return { success: false, message: "Invalid firebase.json." };
|
|
3478
|
+
}
|
|
3479
|
+
}
|
|
3480
|
+
/**
|
|
3481
|
+
* Install dependencies and build functions for deployment.
|
|
3482
|
+
*/
|
|
3483
|
+
async buildFunctions() {
|
|
3484
|
+
const functionsDir = (0, import_node_path4.resolve)(this.projectDir, "functions");
|
|
3485
|
+
if (!(0, import_node_fs4.existsSync)(functionsDir)) {
|
|
3486
|
+
return { success: false, message: "functions/ directory not found." };
|
|
3487
|
+
}
|
|
3488
|
+
const pkgPath = (0, import_node_path4.resolve)(functionsDir, "package.json");
|
|
3489
|
+
if (!(0, import_node_fs4.existsSync)(pkgPath)) {
|
|
3490
|
+
return { success: false, message: "functions/package.json not found." };
|
|
3491
|
+
}
|
|
3492
|
+
const nodeModulesPath = (0, import_node_path4.resolve)(functionsDir, "node_modules");
|
|
3493
|
+
if (!(0, import_node_fs4.existsSync)(nodeModulesPath)) {
|
|
3494
|
+
try {
|
|
3495
|
+
await this.execTimeout("npm", ["install"], 12e4, functionsDir);
|
|
3496
|
+
} catch (err) {
|
|
3497
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
3498
|
+
return { success: false, message: `npm install in functions/ failed: ${msg}` };
|
|
3499
|
+
}
|
|
3500
|
+
}
|
|
3501
|
+
try {
|
|
3502
|
+
const pkg = JSON.parse((0, import_node_fs4.readFileSync)(pkgPath, "utf-8"));
|
|
3503
|
+
if (pkg.scripts?.build) {
|
|
3504
|
+
await this.execTimeout("npm", ["run", "build"], 6e4, functionsDir);
|
|
3505
|
+
} else {
|
|
3506
|
+
const tsconfigPath = (0, import_node_path4.resolve)(functionsDir, "tsconfig.json");
|
|
3507
|
+
if ((0, import_node_fs4.existsSync)(tsconfigPath)) {
|
|
3508
|
+
await this.execTimeout("npx", ["tsc"], 6e4, functionsDir);
|
|
3509
|
+
}
|
|
3510
|
+
}
|
|
3511
|
+
return { success: true, message: "Functions built successfully." };
|
|
3512
|
+
} catch (err) {
|
|
3513
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
3514
|
+
return { success: false, message: `Functions build failed: ${msg}` };
|
|
3515
|
+
}
|
|
3516
|
+
}
|
|
3418
3517
|
// ─── Service Enable ────────────────────────────────────────────────
|
|
3419
3518
|
enableService(service) {
|
|
3420
3519
|
const firebaseJsonPath = (0, import_node_path4.resolve)(this.projectDir, "firebase.json");
|
|
@@ -3663,9 +3762,9 @@ https://console.developers.google.com/apis/api/firestore.googleapis.com/overview
|
|
|
3663
3762
|
}
|
|
3664
3763
|
}
|
|
3665
3764
|
// ─── Helpers ───────────────────────────────────────────────────────
|
|
3666
|
-
execTimeout(command, args, timeoutMs) {
|
|
3765
|
+
execTimeout(command, args, timeoutMs, cwd) {
|
|
3667
3766
|
return new Promise((resolve7, reject) => {
|
|
3668
|
-
const proc = (0, import_node_child_process2.execFile)(command, args, { cwd: this.projectDir, timeout: timeoutMs }, (err, stdout, stderr) => {
|
|
3767
|
+
const proc = (0, import_node_child_process2.execFile)(command, args, { cwd: cwd || this.projectDir, timeout: timeoutMs }, (err, stdout, stderr) => {
|
|
3669
3768
|
if (err) {
|
|
3670
3769
|
const detail = stderr?.trim() || stdout?.trim() || "";
|
|
3671
3770
|
const enriched = new Error(`${err.message}${detail ? "\n" + detail : ""}`);
|
|
@@ -4828,22 +4927,27 @@ ${liveReloadScript}
|
|
|
4828
4927
|
if (url.pathname === "/__dev/deploy/hosting" && req.method === "POST") {
|
|
4829
4928
|
(async () => {
|
|
4830
4929
|
try {
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
4930
|
+
const steps = [];
|
|
4931
|
+
const functionsDir = (0, import_node_path5.resolve)(this.options.projectDir, "functions");
|
|
4932
|
+
const hasFunctions = (0, import_node_fs5.existsSync)(functionsDir);
|
|
4933
|
+
const projectConfig = this.readProjectConfig();
|
|
4934
|
+
const firebaseConfig = {};
|
|
4935
|
+
for (const field of projectConfig.fields) {
|
|
4936
|
+
if (!field.isPlaceholder) {
|
|
4937
|
+
firebaseConfig[field.key] = field.value;
|
|
4838
4938
|
}
|
|
4939
|
+
}
|
|
4940
|
+
if (this.pageCompiler.isActive()) {
|
|
4839
4941
|
const configScript = Object.keys(firebaseConfig).length > 0 ? `
|
|
4840
4942
|
<script>window.__CLAWFIRE_CONFIG__=${JSON.stringify(firebaseConfig)};</script>` : "";
|
|
4841
4943
|
const routerScript = generateProductionRouterScript();
|
|
4842
4944
|
const scriptToInject = configScript + routerScript;
|
|
4843
4945
|
const buildResult = this.pageCompiler.buildForProduction(this.publicDir, scriptToInject);
|
|
4844
4946
|
console.log(` \x1B[32m\u2713\x1B[0m Built ${buildResult.pages.length} pages for production`);
|
|
4947
|
+
steps.push(`${buildResult.pages.length} pages built`);
|
|
4845
4948
|
if (configScript) {
|
|
4846
4949
|
console.log(` \x1B[32m\u2713\x1B[0m Firebase config injected (projectId: ${firebaseConfig.projectId || "?"})`);
|
|
4950
|
+
steps.push("Firebase config injected");
|
|
4847
4951
|
}
|
|
4848
4952
|
if (buildResult.errors.length > 0) {
|
|
4849
4953
|
for (const err of buildResult.errors) {
|
|
@@ -4851,9 +4955,39 @@ ${liveReloadScript}
|
|
|
4851
4955
|
}
|
|
4852
4956
|
}
|
|
4853
4957
|
}
|
|
4854
|
-
|
|
4958
|
+
let deployFunctions = false;
|
|
4959
|
+
if (hasFunctions) {
|
|
4960
|
+
const syncResult = this.firebaseSetup.syncEnvToFunctions(firebaseConfig);
|
|
4961
|
+
if (syncResult.success) {
|
|
4962
|
+
console.log(` \x1B[32m\u2713\x1B[0m ${syncResult.message}`);
|
|
4963
|
+
steps.push(`${syncResult.count} env vars synced`);
|
|
4964
|
+
} else {
|
|
4965
|
+
console.log(` \x1B[33m\u26A0\x1B[0m Env sync: ${syncResult.message}`);
|
|
4966
|
+
}
|
|
4967
|
+
const configResult = this.firebaseSetup.ensureFunctionsConfig();
|
|
4968
|
+
if (configResult.success) {
|
|
4969
|
+
console.log(` \x1B[32m\u2713\x1B[0m ${configResult.message}`);
|
|
4970
|
+
}
|
|
4971
|
+
console.log(" Building functions...");
|
|
4972
|
+
const buildResult = await this.firebaseSetup.buildFunctions();
|
|
4973
|
+
if (buildResult.success) {
|
|
4974
|
+
console.log(` \x1B[32m\u2713\x1B[0m ${buildResult.message}`);
|
|
4975
|
+
steps.push("Functions built");
|
|
4976
|
+
deployFunctions = true;
|
|
4977
|
+
} else {
|
|
4978
|
+
console.log(` \x1B[31m\u2717\x1B[0m ${buildResult.message}`);
|
|
4979
|
+
console.log(" \x1B[33m\u26A0\x1B[0m Deploying hosting only (functions build failed)");
|
|
4980
|
+
steps.push("Functions build failed \u2014 hosting only");
|
|
4981
|
+
}
|
|
4982
|
+
}
|
|
4983
|
+
const targets = deployFunctions ? "hosting,functions" : "hosting";
|
|
4984
|
+
console.log(` Deploying ${targets}...`);
|
|
4985
|
+
const result = await this.firebaseSetup.deployHosting(targets);
|
|
4855
4986
|
clearFirebaseStatusCache();
|
|
4856
|
-
sendJson(
|
|
4987
|
+
sendJson({
|
|
4988
|
+
...result,
|
|
4989
|
+
message: result.message + (steps.length > 0 ? ` (${steps.join(", ")})` : "")
|
|
4990
|
+
});
|
|
4857
4991
|
} catch (err) {
|
|
4858
4992
|
sendJson({ success: false, message: err instanceof Error ? err.message : "Failed" }, 500);
|
|
4859
4993
|
}
|