clawfire 0.6.7 → 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-5SXODXYN.js → dev-server-6BALG4FC.js} +157 -10
- package/dist/dev.cjs +157 -10
- package/dist/dev.cjs.map +1 -1
- package/dist/dev.js +157 -10
- package/dist/dev.js.map +1 -1
- package/package.json +1 -1
package/dist/dev.js
CHANGED
|
@@ -3330,7 +3330,7 @@ var FirebaseSetup = class {
|
|
|
3330
3330
|
return { success: true, message: `Web app "${displayName}" selected.` };
|
|
3331
3331
|
}
|
|
3332
3332
|
// ─── Deploy ─────────────────────────────────────────────────────────
|
|
3333
|
-
async deployHosting() {
|
|
3333
|
+
async deployHosting(targets = "hosting") {
|
|
3334
3334
|
const firebaseJsonPath = resolve5(this.projectDir, "firebase.json");
|
|
3335
3335
|
if (!existsSync6(firebaseJsonPath)) {
|
|
3336
3336
|
return { success: false, message: "firebase.json not found. Enable hosting first." };
|
|
@@ -3343,12 +3343,12 @@ var FirebaseSetup = class {
|
|
|
3343
3343
|
} catch {
|
|
3344
3344
|
return { success: false, message: "Invalid firebase.json." };
|
|
3345
3345
|
}
|
|
3346
|
+
const timeoutMs = targets.includes("functions") ? 3e5 : 12e4;
|
|
3346
3347
|
try {
|
|
3347
3348
|
const output = await this.execTimeout(
|
|
3348
3349
|
"firebase",
|
|
3349
|
-
["deploy", "--only",
|
|
3350
|
-
|
|
3351
|
-
// 2 min timeout
|
|
3350
|
+
["deploy", "--only", targets, "--json"],
|
|
3351
|
+
timeoutMs
|
|
3352
3352
|
);
|
|
3353
3353
|
let url = "";
|
|
3354
3354
|
try {
|
|
@@ -3371,12 +3371,111 @@ var FirebaseSetup = class {
|
|
|
3371
3371
|
url = `https://${state.projectId}.web.app`;
|
|
3372
3372
|
}
|
|
3373
3373
|
}
|
|
3374
|
-
|
|
3374
|
+
const label = targets.includes("functions") ? "Hosting + Functions" : "Hosting";
|
|
3375
|
+
return { success: true, url: url || void 0, message: `${label} deployed successfully!` };
|
|
3375
3376
|
} catch (err) {
|
|
3376
3377
|
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
3377
3378
|
return { success: false, message: `Deploy failed: ${msg}` };
|
|
3378
3379
|
}
|
|
3379
3380
|
}
|
|
3381
|
+
// ─── Full Deploy Pipeline ────────────────────────────────────────────
|
|
3382
|
+
/**
|
|
3383
|
+
* Sync environment variables to functions/.env for production.
|
|
3384
|
+
* Copies project root .env vars + injects CLAWFIRE_FIREBASE_CONFIG.
|
|
3385
|
+
*/
|
|
3386
|
+
syncEnvToFunctions(firebaseConfig) {
|
|
3387
|
+
const functionsDir = resolve5(this.projectDir, "functions");
|
|
3388
|
+
if (!existsSync6(functionsDir)) {
|
|
3389
|
+
return { success: false, message: "functions/ directory not found.", count: 0 };
|
|
3390
|
+
}
|
|
3391
|
+
const lines = [];
|
|
3392
|
+
const rootEnvPath = resolve5(this.projectDir, ".env");
|
|
3393
|
+
if (existsSync6(rootEnvPath)) {
|
|
3394
|
+
const content = readFileSync4(rootEnvPath, "utf-8");
|
|
3395
|
+
for (const rawLine of content.split("\n")) {
|
|
3396
|
+
let trimmed = rawLine.trim();
|
|
3397
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
3398
|
+
if (trimmed.startsWith("export ")) {
|
|
3399
|
+
trimmed = trimmed.slice(7);
|
|
3400
|
+
}
|
|
3401
|
+
const eqIdx = trimmed.indexOf("=");
|
|
3402
|
+
if (eqIdx === -1) continue;
|
|
3403
|
+
const key = trimmed.slice(0, eqIdx).trim();
|
|
3404
|
+
if (key === "NPM_TOKEN" || key === "NODE_ENV") continue;
|
|
3405
|
+
lines.push(trimmed);
|
|
3406
|
+
}
|
|
3407
|
+
}
|
|
3408
|
+
if (firebaseConfig && Object.keys(firebaseConfig).length > 0) {
|
|
3409
|
+
const filtered = lines.filter((l) => !l.startsWith("CLAWFIRE_FIREBASE_CONFIG="));
|
|
3410
|
+
filtered.push(`CLAWFIRE_FIREBASE_CONFIG=${JSON.stringify(firebaseConfig)}`);
|
|
3411
|
+
lines.length = 0;
|
|
3412
|
+
lines.push(...filtered);
|
|
3413
|
+
}
|
|
3414
|
+
const functionsEnvPath = resolve5(functionsDir, ".env");
|
|
3415
|
+
writeFileSync3(functionsEnvPath, lines.join("\n") + "\n", "utf-8");
|
|
3416
|
+
return { success: true, message: `Synced ${lines.length} env vars to functions/.env`, count: lines.length };
|
|
3417
|
+
}
|
|
3418
|
+
/**
|
|
3419
|
+
* Ensure firebase.json has functions configuration.
|
|
3420
|
+
*/
|
|
3421
|
+
ensureFunctionsConfig() {
|
|
3422
|
+
const firebaseJsonPath = resolve5(this.projectDir, "firebase.json");
|
|
3423
|
+
if (!existsSync6(firebaseJsonPath)) {
|
|
3424
|
+
return { success: false, message: "firebase.json not found." };
|
|
3425
|
+
}
|
|
3426
|
+
try {
|
|
3427
|
+
const config = JSON.parse(readFileSync4(firebaseJsonPath, "utf-8"));
|
|
3428
|
+
if (!config.functions) {
|
|
3429
|
+
config.functions = {
|
|
3430
|
+
source: "functions",
|
|
3431
|
+
runtime: "nodejs20",
|
|
3432
|
+
codebase: "clawfire"
|
|
3433
|
+
};
|
|
3434
|
+
writeFileSync3(firebaseJsonPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
3435
|
+
return { success: true, message: "Functions config added to firebase.json." };
|
|
3436
|
+
}
|
|
3437
|
+
return { success: true, message: "Functions config already present." };
|
|
3438
|
+
} catch {
|
|
3439
|
+
return { success: false, message: "Invalid firebase.json." };
|
|
3440
|
+
}
|
|
3441
|
+
}
|
|
3442
|
+
/**
|
|
3443
|
+
* Install dependencies and build functions for deployment.
|
|
3444
|
+
*/
|
|
3445
|
+
async buildFunctions() {
|
|
3446
|
+
const functionsDir = resolve5(this.projectDir, "functions");
|
|
3447
|
+
if (!existsSync6(functionsDir)) {
|
|
3448
|
+
return { success: false, message: "functions/ directory not found." };
|
|
3449
|
+
}
|
|
3450
|
+
const pkgPath = resolve5(functionsDir, "package.json");
|
|
3451
|
+
if (!existsSync6(pkgPath)) {
|
|
3452
|
+
return { success: false, message: "functions/package.json not found." };
|
|
3453
|
+
}
|
|
3454
|
+
const nodeModulesPath = resolve5(functionsDir, "node_modules");
|
|
3455
|
+
if (!existsSync6(nodeModulesPath)) {
|
|
3456
|
+
try {
|
|
3457
|
+
await this.execTimeout("npm", ["install"], 12e4, functionsDir);
|
|
3458
|
+
} catch (err) {
|
|
3459
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
3460
|
+
return { success: false, message: `npm install in functions/ failed: ${msg}` };
|
|
3461
|
+
}
|
|
3462
|
+
}
|
|
3463
|
+
try {
|
|
3464
|
+
const pkg = JSON.parse(readFileSync4(pkgPath, "utf-8"));
|
|
3465
|
+
if (pkg.scripts?.build) {
|
|
3466
|
+
await this.execTimeout("npm", ["run", "build"], 6e4, functionsDir);
|
|
3467
|
+
} else {
|
|
3468
|
+
const tsconfigPath = resolve5(functionsDir, "tsconfig.json");
|
|
3469
|
+
if (existsSync6(tsconfigPath)) {
|
|
3470
|
+
await this.execTimeout("npx", ["tsc"], 6e4, functionsDir);
|
|
3471
|
+
}
|
|
3472
|
+
}
|
|
3473
|
+
return { success: true, message: "Functions built successfully." };
|
|
3474
|
+
} catch (err) {
|
|
3475
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
3476
|
+
return { success: false, message: `Functions build failed: ${msg}` };
|
|
3477
|
+
}
|
|
3478
|
+
}
|
|
3380
3479
|
// ─── Service Enable ────────────────────────────────────────────────
|
|
3381
3480
|
enableService(service) {
|
|
3382
3481
|
const firebaseJsonPath = resolve5(this.projectDir, "firebase.json");
|
|
@@ -3625,9 +3724,9 @@ https://console.developers.google.com/apis/api/firestore.googleapis.com/overview
|
|
|
3625
3724
|
}
|
|
3626
3725
|
}
|
|
3627
3726
|
// ─── Helpers ───────────────────────────────────────────────────────
|
|
3628
|
-
execTimeout(command, args, timeoutMs) {
|
|
3727
|
+
execTimeout(command, args, timeoutMs, cwd) {
|
|
3629
3728
|
return new Promise((resolve7, reject) => {
|
|
3630
|
-
const proc = execFile2(command, args, { cwd: this.projectDir, timeout: timeoutMs }, (err, stdout, stderr) => {
|
|
3729
|
+
const proc = execFile2(command, args, { cwd: cwd || this.projectDir, timeout: timeoutMs }, (err, stdout, stderr) => {
|
|
3631
3730
|
if (err) {
|
|
3632
3731
|
const detail = stderr?.trim() || stdout?.trim() || "";
|
|
3633
3732
|
const enriched = new Error(`${err.message}${detail ? "\n" + detail : ""}`);
|
|
@@ -4790,19 +4889,67 @@ ${liveReloadScript}
|
|
|
4790
4889
|
if (url.pathname === "/__dev/deploy/hosting" && req.method === "POST") {
|
|
4791
4890
|
(async () => {
|
|
4792
4891
|
try {
|
|
4892
|
+
const steps = [];
|
|
4893
|
+
const functionsDir = resolve6(this.options.projectDir, "functions");
|
|
4894
|
+
const hasFunctions = existsSync7(functionsDir);
|
|
4895
|
+
const projectConfig = this.readProjectConfig();
|
|
4896
|
+
const firebaseConfig = {};
|
|
4897
|
+
for (const field of projectConfig.fields) {
|
|
4898
|
+
if (!field.isPlaceholder) {
|
|
4899
|
+
firebaseConfig[field.key] = field.value;
|
|
4900
|
+
}
|
|
4901
|
+
}
|
|
4793
4902
|
if (this.pageCompiler.isActive()) {
|
|
4903
|
+
const configScript = Object.keys(firebaseConfig).length > 0 ? `
|
|
4904
|
+
<script>window.__CLAWFIRE_CONFIG__=${JSON.stringify(firebaseConfig)};</script>` : "";
|
|
4794
4905
|
const routerScript = generateProductionRouterScript();
|
|
4795
|
-
const
|
|
4906
|
+
const scriptToInject = configScript + routerScript;
|
|
4907
|
+
const buildResult = this.pageCompiler.buildForProduction(this.publicDir, scriptToInject);
|
|
4796
4908
|
console.log(` \x1B[32m\u2713\x1B[0m Built ${buildResult.pages.length} pages for production`);
|
|
4909
|
+
steps.push(`${buildResult.pages.length} pages built`);
|
|
4910
|
+
if (configScript) {
|
|
4911
|
+
console.log(` \x1B[32m\u2713\x1B[0m Firebase config injected (projectId: ${firebaseConfig.projectId || "?"})`);
|
|
4912
|
+
steps.push("Firebase config injected");
|
|
4913
|
+
}
|
|
4797
4914
|
if (buildResult.errors.length > 0) {
|
|
4798
4915
|
for (const err of buildResult.errors) {
|
|
4799
4916
|
console.log(` \x1B[31m\u2717\x1B[0m ${err}`);
|
|
4800
4917
|
}
|
|
4801
4918
|
}
|
|
4802
4919
|
}
|
|
4803
|
-
|
|
4920
|
+
let deployFunctions = false;
|
|
4921
|
+
if (hasFunctions) {
|
|
4922
|
+
const syncResult = this.firebaseSetup.syncEnvToFunctions(firebaseConfig);
|
|
4923
|
+
if (syncResult.success) {
|
|
4924
|
+
console.log(` \x1B[32m\u2713\x1B[0m ${syncResult.message}`);
|
|
4925
|
+
steps.push(`${syncResult.count} env vars synced`);
|
|
4926
|
+
} else {
|
|
4927
|
+
console.log(` \x1B[33m\u26A0\x1B[0m Env sync: ${syncResult.message}`);
|
|
4928
|
+
}
|
|
4929
|
+
const configResult = this.firebaseSetup.ensureFunctionsConfig();
|
|
4930
|
+
if (configResult.success) {
|
|
4931
|
+
console.log(` \x1B[32m\u2713\x1B[0m ${configResult.message}`);
|
|
4932
|
+
}
|
|
4933
|
+
console.log(" Building functions...");
|
|
4934
|
+
const buildResult = await this.firebaseSetup.buildFunctions();
|
|
4935
|
+
if (buildResult.success) {
|
|
4936
|
+
console.log(` \x1B[32m\u2713\x1B[0m ${buildResult.message}`);
|
|
4937
|
+
steps.push("Functions built");
|
|
4938
|
+
deployFunctions = true;
|
|
4939
|
+
} else {
|
|
4940
|
+
console.log(` \x1B[31m\u2717\x1B[0m ${buildResult.message}`);
|
|
4941
|
+
console.log(" \x1B[33m\u26A0\x1B[0m Deploying hosting only (functions build failed)");
|
|
4942
|
+
steps.push("Functions build failed \u2014 hosting only");
|
|
4943
|
+
}
|
|
4944
|
+
}
|
|
4945
|
+
const targets = deployFunctions ? "hosting,functions" : "hosting";
|
|
4946
|
+
console.log(` Deploying ${targets}...`);
|
|
4947
|
+
const result = await this.firebaseSetup.deployHosting(targets);
|
|
4804
4948
|
clearFirebaseStatusCache();
|
|
4805
|
-
sendJson(
|
|
4949
|
+
sendJson({
|
|
4950
|
+
...result,
|
|
4951
|
+
message: result.message + (steps.length > 0 ? ` (${steps.join(", ")})` : "")
|
|
4952
|
+
});
|
|
4806
4953
|
} catch (err) {
|
|
4807
4954
|
sendJson({ success: false, message: err instanceof Error ? err.message : "Failed" }, 500);
|
|
4808
4955
|
}
|