clawfire 0.6.5 → 0.6.7
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/admin.cjs +1 -0
- package/dist/admin.cjs.map +1 -1
- package/dist/admin.d.cts +1 -0
- package/dist/admin.d.ts +1 -0
- package/dist/admin.js +1 -0
- package/dist/admin.js.map +1 -1
- package/dist/cli.js +3 -3
- package/dist/{dev-server-LCKIGM6U.js → dev-server-5SXODXYN.js} +281 -62
- package/dist/dev.cjs +262 -43
- package/dist/dev.cjs.map +1 -1
- package/dist/dev.js +281 -62
- package/dist/dev.js.map +1 -1
- package/dist/functions.cjs +1 -0
- package/dist/functions.cjs.map +1 -1
- package/dist/functions.js +1 -0
- package/dist/functions.js.map +1 -1
- package/dist/{hosting-7WVFHAYJ.js → hosting-GHMSBL2N.js} +1 -0
- package/package.json +1 -1
package/dist/dev.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// src/dev/dev-server.ts
|
|
2
2
|
import http from "http";
|
|
3
3
|
import { resolve as resolve6, relative as relative3, extname as extname3 } from "path";
|
|
4
|
-
import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as
|
|
4
|
+
import { existsSync as existsSync7, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
5
5
|
import { pathToFileURL } from "url";
|
|
6
6
|
|
|
7
7
|
// src/core/schema.ts
|
|
@@ -1019,8 +1019,8 @@ var FileWatcher = class extends EventEmitter {
|
|
|
1019
1019
|
};
|
|
1020
1020
|
|
|
1021
1021
|
// src/dev/page-compiler.ts
|
|
1022
|
-
import { resolve as resolve2, join as join3, dirname, basename } from "path";
|
|
1023
|
-
import { existsSync as existsSync3, readFileSync } from "fs";
|
|
1022
|
+
import { resolve as resolve2, join as join3, relative as relative2, dirname, basename } from "path";
|
|
1023
|
+
import { existsSync as existsSync3, readFileSync, readdirSync as readdirSync3, statSync as statSync3, writeFileSync, mkdirSync } from "fs";
|
|
1024
1024
|
var MAX_COMPONENT_DEPTH = 10;
|
|
1025
1025
|
var META_REGEX = /<!--\s*@(\w+):\s*(.+?)\s*-->/g;
|
|
1026
1026
|
var COMPONENT_REGEX = /<c-([a-z][a-z0-9-]*)\s*\/>/g;
|
|
@@ -1115,6 +1115,62 @@ var PageCompiler = class {
|
|
|
1115
1115
|
path: pathname
|
|
1116
1116
|
};
|
|
1117
1117
|
}
|
|
1118
|
+
/**
|
|
1119
|
+
* Build all pages into static HTML for production deployment.
|
|
1120
|
+
* Walks app/pages/ recursively, compiles each page, and writes to outputDir.
|
|
1121
|
+
*
|
|
1122
|
+
* - Skips _layout.html (wrapper-only, not standalone)
|
|
1123
|
+
* - _404.html → 404.html (Firebase auto-serves for 404s)
|
|
1124
|
+
* - Injects optional script (e.g. production router) before </body>
|
|
1125
|
+
*/
|
|
1126
|
+
buildForProduction(outputDir, scriptToInject) {
|
|
1127
|
+
const pages = [];
|
|
1128
|
+
const errors = [];
|
|
1129
|
+
if (!this.isActive()) {
|
|
1130
|
+
return { pages, errors };
|
|
1131
|
+
}
|
|
1132
|
+
const walk = (dir) => {
|
|
1133
|
+
const entries = readdirSync3(dir);
|
|
1134
|
+
for (const entry of entries) {
|
|
1135
|
+
const fullPath = join3(dir, entry);
|
|
1136
|
+
const stat = statSync3(fullPath);
|
|
1137
|
+
if (stat.isDirectory()) {
|
|
1138
|
+
walk(fullPath);
|
|
1139
|
+
continue;
|
|
1140
|
+
}
|
|
1141
|
+
if (!entry.endsWith(".html")) continue;
|
|
1142
|
+
if (entry === "_layout.html") continue;
|
|
1143
|
+
try {
|
|
1144
|
+
const compiled = this.compile(fullPath);
|
|
1145
|
+
let html = compiled.html;
|
|
1146
|
+
if (scriptToInject) {
|
|
1147
|
+
if (html.includes("</body>")) {
|
|
1148
|
+
html = html.replace("</body>", scriptToInject + "\n</body>");
|
|
1149
|
+
} else {
|
|
1150
|
+
html += scriptToInject;
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
const relPath = relative2(this.pagesDir, fullPath);
|
|
1154
|
+
let outputPath;
|
|
1155
|
+
if (entry === "_404.html") {
|
|
1156
|
+
const parentRel = relative2(this.pagesDir, dir);
|
|
1157
|
+
outputPath = parentRel ? join3(outputDir, parentRel, "404.html") : join3(outputDir, "404.html");
|
|
1158
|
+
} else {
|
|
1159
|
+
outputPath = join3(outputDir, relPath);
|
|
1160
|
+
}
|
|
1161
|
+
const outputDirPath = dirname(outputPath);
|
|
1162
|
+
mkdirSync(outputDirPath, { recursive: true });
|
|
1163
|
+
writeFileSync(outputPath, html, "utf-8");
|
|
1164
|
+
pages.push(relPath);
|
|
1165
|
+
} catch (err) {
|
|
1166
|
+
const relPath = relative2(this.pagesDir, fullPath);
|
|
1167
|
+
errors.push(`${relPath}: ${err instanceof Error ? err.message : "Unknown error"}`);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
};
|
|
1171
|
+
walk(this.pagesDir);
|
|
1172
|
+
return { pages, errors };
|
|
1173
|
+
}
|
|
1118
1174
|
// ─── Internal Methods ────────────────────────────────────────────
|
|
1119
1175
|
/**
|
|
1120
1176
|
* Extract <!-- @key: value --> metadata from HTML.
|
|
@@ -1193,7 +1249,7 @@ ${html}
|
|
|
1193
1249
|
};
|
|
1194
1250
|
|
|
1195
1251
|
// src/dev/env-manager.ts
|
|
1196
|
-
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync4 } from "fs";
|
|
1252
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync4 } from "fs";
|
|
1197
1253
|
import { resolve as resolve3 } from "path";
|
|
1198
1254
|
var KEY_PATTERN = /^[A-Z_][A-Z0-9_]*$/i;
|
|
1199
1255
|
var PLACEHOLDER_PATTERNS = [
|
|
@@ -1267,7 +1323,7 @@ var EnvManager = class {
|
|
|
1267
1323
|
lines.push(`${key}=${value}`);
|
|
1268
1324
|
}
|
|
1269
1325
|
}
|
|
1270
|
-
|
|
1326
|
+
writeFileSync2(this.envPath, lines.join("\n"), "utf-8");
|
|
1271
1327
|
if (description !== void 0) {
|
|
1272
1328
|
const descriptions = this.readDescriptions();
|
|
1273
1329
|
descriptions[key] = description;
|
|
@@ -1285,7 +1341,7 @@ var EnvManager = class {
|
|
|
1285
1341
|
if (eqIdx === -1) return true;
|
|
1286
1342
|
return trimmed.slice(0, eqIdx).trim() !== key;
|
|
1287
1343
|
});
|
|
1288
|
-
|
|
1344
|
+
writeFileSync2(this.envPath, filtered.join("\n"), "utf-8");
|
|
1289
1345
|
const descriptions = this.readDescriptions();
|
|
1290
1346
|
if (key in descriptions) {
|
|
1291
1347
|
delete descriptions[key];
|
|
@@ -1302,7 +1358,7 @@ var EnvManager = class {
|
|
|
1302
1358
|
}
|
|
1303
1359
|
}
|
|
1304
1360
|
writeDescriptions(descriptions) {
|
|
1305
|
-
|
|
1361
|
+
writeFileSync2(
|
|
1306
1362
|
this.descriptionsPath,
|
|
1307
1363
|
JSON.stringify(descriptions, null, 2) + "\n",
|
|
1308
1364
|
"utf-8"
|
|
@@ -2230,8 +2286,9 @@ function generateDashboardHtml(options) {
|
|
|
2230
2286
|
}
|
|
2231
2287
|
|
|
2232
2288
|
btn.disabled = true;
|
|
2233
|
-
btn.textContent = 'Setting...';
|
|
2234
|
-
status.
|
|
2289
|
+
btn.textContent = 'Setting up...';
|
|
2290
|
+
status.textContent = 'Selecting project, detecting web app, auto-filling config...';
|
|
2291
|
+
status.style.cssText = 'display:block;margin-top:8px;font-size:13px;padding:8px 12px;border-radius:6px;background:#0a0a1c;border:1px solid #3b82f6;color:#93c5fd;';
|
|
2235
2292
|
|
|
2236
2293
|
fetch(API + '/__dev/setup/select-project', {
|
|
2237
2294
|
method: 'POST',
|
|
@@ -2241,8 +2298,11 @@ function generateDashboardHtml(options) {
|
|
|
2241
2298
|
.then(function(r) { return r.json(); })
|
|
2242
2299
|
.then(function(data) {
|
|
2243
2300
|
if (data.success) {
|
|
2244
|
-
|
|
2245
|
-
status.
|
|
2301
|
+
var msg = data.steps ? data.steps.join('\\n') : data.message;
|
|
2302
|
+
status.textContent = msg;
|
|
2303
|
+
status.style.whiteSpace = 'pre-line';
|
|
2304
|
+
status.style.cssText = 'display:block;margin-top:8px;font-size:13px;padding:8px 12px;border-radius:6px;background:#0a1a0a;border:1px solid #22c55e;color:#22c55e;white-space:pre-line;';
|
|
2305
|
+
btn.textContent = 'Done';
|
|
2246
2306
|
setTimeout(refreshSetupStatus, 1000);
|
|
2247
2307
|
} else {
|
|
2248
2308
|
status.textContent = data.message;
|
|
@@ -2951,7 +3011,7 @@ function generateDashboardHtml(options) {
|
|
|
2951
3011
|
|
|
2952
3012
|
// src/dev/firebase-setup.ts
|
|
2953
3013
|
import { execFile as execFile2, spawn } from "child_process";
|
|
2954
|
-
import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as
|
|
3014
|
+
import { existsSync as existsSync6, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
2955
3015
|
import { resolve as resolve5, join as join4 } from "path";
|
|
2956
3016
|
import { tmpdir, platform, homedir } from "os";
|
|
2957
3017
|
var FirebaseSetup = class {
|
|
@@ -2974,7 +3034,7 @@ var FirebaseSetup = class {
|
|
|
2974
3034
|
saveState(partial) {
|
|
2975
3035
|
const current = this.loadState();
|
|
2976
3036
|
const merged = { ...current, ...partial, lastUpdated: (/* @__PURE__ */ new Date()).toISOString() };
|
|
2977
|
-
|
|
3037
|
+
writeFileSync3(this.stateFilePath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
2978
3038
|
}
|
|
2979
3039
|
// ─── Status Check ──────────────────────────────────────────────────
|
|
2980
3040
|
async getStatus() {
|
|
@@ -3076,7 +3136,7 @@ var FirebaseSetup = class {
|
|
|
3076
3136
|
try {
|
|
3077
3137
|
if (os === "darwin") {
|
|
3078
3138
|
const scriptPath = join4(tmpdir(), "clawfire-firebase-login.command");
|
|
3079
|
-
|
|
3139
|
+
writeFileSync3(scriptPath, [
|
|
3080
3140
|
"#!/bin/bash",
|
|
3081
3141
|
`cd "${this.projectDir}"`,
|
|
3082
3142
|
cmd,
|
|
@@ -3098,7 +3158,7 @@ var FirebaseSetup = class {
|
|
|
3098
3158
|
child.unref();
|
|
3099
3159
|
} else {
|
|
3100
3160
|
const scriptPath = join4(tmpdir(), "clawfire-firebase-login.sh");
|
|
3101
|
-
|
|
3161
|
+
writeFileSync3(scriptPath, [
|
|
3102
3162
|
"#!/bin/bash",
|
|
3103
3163
|
`cd "${this.projectDir}"`,
|
|
3104
3164
|
cmd,
|
|
@@ -3207,7 +3267,7 @@ var FirebaseSetup = class {
|
|
|
3207
3267
|
rc.projects = {};
|
|
3208
3268
|
}
|
|
3209
3269
|
rc.projects.default = projectId;
|
|
3210
|
-
|
|
3270
|
+
writeFileSync3(firebasercPath, JSON.stringify(rc, null, 2) + "\n", "utf-8");
|
|
3211
3271
|
return { success: true, message: `Active project set to "${projectId}".` };
|
|
3212
3272
|
} catch {
|
|
3213
3273
|
try {
|
|
@@ -3215,7 +3275,7 @@ var FirebaseSetup = class {
|
|
|
3215
3275
|
const rc = {
|
|
3216
3276
|
projects: { default: projectId }
|
|
3217
3277
|
};
|
|
3218
|
-
|
|
3278
|
+
writeFileSync3(firebasercPath, JSON.stringify(rc, null, 2) + "\n", "utf-8");
|
|
3219
3279
|
return { success: true, message: `Active project set to "${projectId}" (via .firebaserc).` };
|
|
3220
3280
|
} catch (writeErr) {
|
|
3221
3281
|
const msg = writeErr instanceof Error ? writeErr.message : "Unknown error";
|
|
@@ -3334,7 +3394,11 @@ var FirebaseSetup = class {
|
|
|
3334
3394
|
config.hosting = {
|
|
3335
3395
|
public: "public",
|
|
3336
3396
|
ignore: ["firebase.json", "**/.*", "**/node_modules/**"],
|
|
3337
|
-
|
|
3397
|
+
cleanUrls: true,
|
|
3398
|
+
rewrites: [
|
|
3399
|
+
{ source: "/api/**", function: "api" },
|
|
3400
|
+
{ source: "**", destination: "/index.html" }
|
|
3401
|
+
]
|
|
3338
3402
|
};
|
|
3339
3403
|
}
|
|
3340
3404
|
break;
|
|
@@ -3348,14 +3412,14 @@ var FirebaseSetup = class {
|
|
|
3348
3412
|
}
|
|
3349
3413
|
const rulesPath = resolve5(this.projectDir, "firestore.rules");
|
|
3350
3414
|
if (!existsSync6(rulesPath)) {
|
|
3351
|
-
|
|
3415
|
+
writeFileSync3(
|
|
3352
3416
|
rulesPath,
|
|
3353
3417
|
"rules_version = '2';\nservice cloud.firestore {\n match /databases/{database}/documents {\n match /{document=**} {\n allow read, write: if request.auth != null;\n }\n }\n}\n"
|
|
3354
3418
|
);
|
|
3355
3419
|
}
|
|
3356
3420
|
const indexesPath = resolve5(this.projectDir, "firestore.indexes.json");
|
|
3357
3421
|
if (!existsSync6(indexesPath)) {
|
|
3358
|
-
|
|
3422
|
+
writeFileSync3(indexesPath, JSON.stringify({ indexes: [], fieldOverrides: [] }, null, 2) + "\n");
|
|
3359
3423
|
}
|
|
3360
3424
|
break;
|
|
3361
3425
|
}
|
|
@@ -3365,7 +3429,7 @@ var FirebaseSetup = class {
|
|
|
3365
3429
|
}
|
|
3366
3430
|
const storageRulesPath = resolve5(this.projectDir, "storage.rules");
|
|
3367
3431
|
if (!existsSync6(storageRulesPath)) {
|
|
3368
|
-
|
|
3432
|
+
writeFileSync3(
|
|
3369
3433
|
storageRulesPath,
|
|
3370
3434
|
"rules_version = '2';\nservice firebase.storage {\n match /b/{bucket}/o {\n match /{allPaths=**} {\n allow read, write: if request.auth != null;\n }\n }\n}\n"
|
|
3371
3435
|
);
|
|
@@ -3373,7 +3437,7 @@ var FirebaseSetup = class {
|
|
|
3373
3437
|
break;
|
|
3374
3438
|
}
|
|
3375
3439
|
}
|
|
3376
|
-
|
|
3440
|
+
writeFileSync3(firebaseJsonPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
3377
3441
|
return { success: true, message: `${service} enabled in firebase.json.` };
|
|
3378
3442
|
}
|
|
3379
3443
|
// ─── Firestore Database Automation ──────────────────────────────────
|
|
@@ -3493,41 +3557,48 @@ https://console.developers.google.com/apis/api/firestore.googleapis.com/overview
|
|
|
3493
3557
|
* Handles "ALREADY_EXISTS" gracefully — returns success.
|
|
3494
3558
|
*/
|
|
3495
3559
|
async createFirestoreDatabase(location = "nam5") {
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
)
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
if (msg.includes("ALREADY_EXISTS") || msg.includes("already exists")) {
|
|
3506
|
-
return { success: true, message: "Firestore database already exists." };
|
|
3507
|
-
}
|
|
3508
|
-
if (msg.includes("403") || msg.includes("has not been used") || msg.includes("is disabled")) {
|
|
3509
|
-
const enableResult = await this.enableFirestoreApi();
|
|
3510
|
-
if (!enableResult.success) {
|
|
3511
|
-
return enableResult;
|
|
3560
|
+
const dbArgs = ["firestore:databases:create", "(default)", "--location", location, "--json"];
|
|
3561
|
+
const tryCreate = async () => {
|
|
3562
|
+
try {
|
|
3563
|
+
await this.execTimeout("firebase", dbArgs, 6e4);
|
|
3564
|
+
return { ok: true, alreadyExists: false, needsApi: false, msg: "" };
|
|
3565
|
+
} catch (err) {
|
|
3566
|
+
const msg = err instanceof Error ? err.message : "Unknown error";
|
|
3567
|
+
if (msg.includes("ALREADY_EXISTS") || msg.includes("already exists")) {
|
|
3568
|
+
return { ok: true, alreadyExists: true, needsApi: false, msg };
|
|
3512
3569
|
}
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
await this.execTimeout(
|
|
3516
|
-
"firebase",
|
|
3517
|
-
["firestore:databases:create", "(default)", "--location", location, "--json"],
|
|
3518
|
-
6e4
|
|
3519
|
-
);
|
|
3520
|
-
return { success: true, message: `Firestore API enabled and database created (location: ${location}).` };
|
|
3521
|
-
} catch (retryErr) {
|
|
3522
|
-
const retryMsg = retryErr instanceof Error ? retryErr.message : "Unknown error";
|
|
3523
|
-
if (retryMsg.includes("ALREADY_EXISTS") || retryMsg.includes("already exists")) {
|
|
3524
|
-
return { success: true, message: "Firestore database already exists." };
|
|
3525
|
-
}
|
|
3526
|
-
return { success: false, message: `Failed to create Firestore database after enabling API: ${retryMsg}` };
|
|
3570
|
+
if (msg.includes("403") || msg.includes("has not been used") || msg.includes("is disabled")) {
|
|
3571
|
+
return { ok: false, alreadyExists: false, needsApi: true, msg };
|
|
3527
3572
|
}
|
|
3573
|
+
return { ok: false, alreadyExists: false, needsApi: false, msg };
|
|
3574
|
+
}
|
|
3575
|
+
};
|
|
3576
|
+
const first = await tryCreate();
|
|
3577
|
+
if (first.ok) {
|
|
3578
|
+
return { success: true, message: first.alreadyExists ? "Firestore database already exists." : `Firestore database created (location: ${location}).` };
|
|
3579
|
+
}
|
|
3580
|
+
if (!first.needsApi) {
|
|
3581
|
+
return { success: false, message: `Failed to create Firestore database: ${first.msg}` };
|
|
3582
|
+
}
|
|
3583
|
+
const enableResult = await this.enableFirestoreApi();
|
|
3584
|
+
if (!enableResult.success) {
|
|
3585
|
+
return enableResult;
|
|
3586
|
+
}
|
|
3587
|
+
const waits = [5e3, 5e3, 1e4, 1e4, 15e3];
|
|
3588
|
+
for (let i = 0; i < waits.length; i++) {
|
|
3589
|
+
await new Promise((r) => setTimeout(r, waits[i]));
|
|
3590
|
+
const retry = await tryCreate();
|
|
3591
|
+
if (retry.ok) {
|
|
3592
|
+
return { success: true, message: `Firestore API enabled and database created (location: ${location}).` };
|
|
3593
|
+
}
|
|
3594
|
+
if (!retry.needsApi) {
|
|
3595
|
+
return { success: false, message: `Failed to create Firestore database: ${retry.msg}` };
|
|
3528
3596
|
}
|
|
3529
|
-
return { success: false, message: `Failed to create Firestore database: ${msg}` };
|
|
3530
3597
|
}
|
|
3598
|
+
return {
|
|
3599
|
+
success: false,
|
|
3600
|
+
message: "Firestore API was enabled but database creation timed out waiting for propagation. Please wait a minute and try again."
|
|
3601
|
+
};
|
|
3531
3602
|
}
|
|
3532
3603
|
/**
|
|
3533
3604
|
* Deploy open Firestore security rules for dev testing.
|
|
@@ -3537,7 +3608,7 @@ https://console.developers.google.com/apis/api/firestore.googleapis.com/overview
|
|
|
3537
3608
|
const rulesPath = resolve5(this.projectDir, "firestore.rules");
|
|
3538
3609
|
try {
|
|
3539
3610
|
if (openForDev) {
|
|
3540
|
-
|
|
3611
|
+
writeFileSync3(
|
|
3541
3612
|
rulesPath,
|
|
3542
3613
|
"rules_version = '2';\nservice cloud.firestore {\n match /databases/{database}/documents {\n match /{document=**} {\n allow read, write: if true;\n }\n }\n}\n"
|
|
3543
3614
|
);
|
|
@@ -3803,6 +3874,92 @@ function generateRouterScript() {
|
|
|
3803
3874
|
})();
|
|
3804
3875
|
</script>`;
|
|
3805
3876
|
}
|
|
3877
|
+
function generateProductionRouterScript() {
|
|
3878
|
+
return `
|
|
3879
|
+
<script data-clawfire-router>
|
|
3880
|
+
(function() {
|
|
3881
|
+
function updateActiveNav() {
|
|
3882
|
+
var path = location.pathname;
|
|
3883
|
+
var links = document.querySelectorAll('#nav-links a[href]');
|
|
3884
|
+
for (var i = 0; i < links.length; i++) {
|
|
3885
|
+
var href = links[i].getAttribute('href');
|
|
3886
|
+
if (!href || href.startsWith('http')) continue;
|
|
3887
|
+
var isActive = (path === '/' && href === '/') || (href !== '/' && path.startsWith(href));
|
|
3888
|
+
links[i].setAttribute('data-active', isActive ? 'true' : 'false');
|
|
3889
|
+
}
|
|
3890
|
+
}
|
|
3891
|
+
|
|
3892
|
+
function navigate(url) {
|
|
3893
|
+
var target = new URL(url, location.href);
|
|
3894
|
+
if (target.origin !== location.origin) return false;
|
|
3895
|
+
if (target.pathname === location.pathname && target.hash) return false;
|
|
3896
|
+
|
|
3897
|
+
fetch(target.pathname)
|
|
3898
|
+
.then(function(res) {
|
|
3899
|
+
if (!res.ok) throw new Error('Page not found');
|
|
3900
|
+
return res.text();
|
|
3901
|
+
})
|
|
3902
|
+
.then(function(html) {
|
|
3903
|
+
// Parse the fetched full HTML and extract #clawfire-page content
|
|
3904
|
+
var parser = new DOMParser();
|
|
3905
|
+
var doc = parser.parseFromString(html, 'text/html');
|
|
3906
|
+
var newPage = doc.getElementById('clawfire-page');
|
|
3907
|
+
if (!newPage) throw new Error('No #clawfire-page found');
|
|
3908
|
+
|
|
3909
|
+
var container = document.getElementById('clawfire-page');
|
|
3910
|
+
if (container) {
|
|
3911
|
+
container.innerHTML = newPage.innerHTML;
|
|
3912
|
+
// Execute scripts in new content
|
|
3913
|
+
var scripts = container.querySelectorAll('script');
|
|
3914
|
+
for (var i = 0; i < scripts.length; i++) {
|
|
3915
|
+
var newScript = document.createElement('script');
|
|
3916
|
+
if (scripts[i].src) {
|
|
3917
|
+
newScript.src = scripts[i].src;
|
|
3918
|
+
} else {
|
|
3919
|
+
newScript.textContent = scripts[i].textContent;
|
|
3920
|
+
}
|
|
3921
|
+
scripts[i].parentNode.replaceChild(newScript, scripts[i]);
|
|
3922
|
+
}
|
|
3923
|
+
}
|
|
3924
|
+
// Update title from fetched document
|
|
3925
|
+
var newTitle = doc.querySelector('title');
|
|
3926
|
+
if (newTitle) document.title = newTitle.textContent || '';
|
|
3927
|
+
// Update URL
|
|
3928
|
+
history.pushState(null, '', target.pathname);
|
|
3929
|
+
updateActiveNav();
|
|
3930
|
+
document.dispatchEvent(new CustomEvent('clawfire:navigate', { detail: { path: target.pathname } }));
|
|
3931
|
+
window.scrollTo(0, 0);
|
|
3932
|
+
})
|
|
3933
|
+
.catch(function() {
|
|
3934
|
+
// Fallback: full page navigation
|
|
3935
|
+
location.href = url;
|
|
3936
|
+
});
|
|
3937
|
+
|
|
3938
|
+
return true;
|
|
3939
|
+
}
|
|
3940
|
+
|
|
3941
|
+
document.addEventListener('click', function(e) {
|
|
3942
|
+
var anchor = e.target.closest ? e.target.closest('a[href]') : null;
|
|
3943
|
+
if (!anchor) return;
|
|
3944
|
+
var href = anchor.getAttribute('href');
|
|
3945
|
+
if (!href) return;
|
|
3946
|
+
if (href.startsWith('http') || href.startsWith('//')) return;
|
|
3947
|
+
if (anchor.target === '_blank') return;
|
|
3948
|
+
if (e.ctrlKey || e.metaKey || e.shiftKey || e.altKey) return;
|
|
3949
|
+
if (anchor.hasAttribute('download')) return;
|
|
3950
|
+
|
|
3951
|
+
e.preventDefault();
|
|
3952
|
+
navigate(href);
|
|
3953
|
+
});
|
|
3954
|
+
|
|
3955
|
+
window.addEventListener('popstate', function() {
|
|
3956
|
+
navigate(location.pathname);
|
|
3957
|
+
});
|
|
3958
|
+
|
|
3959
|
+
updateActiveNav();
|
|
3960
|
+
})();
|
|
3961
|
+
</script>`;
|
|
3962
|
+
}
|
|
3806
3963
|
var DevServer = class {
|
|
3807
3964
|
frontendServer = null;
|
|
3808
3965
|
apiServer = null;
|
|
@@ -4547,10 +4704,57 @@ ${liveReloadScript}
|
|
|
4547
4704
|
sendJson({ success: false, message: "projectId is required" }, 400);
|
|
4548
4705
|
return;
|
|
4549
4706
|
}
|
|
4550
|
-
|
|
4707
|
+
(async () => {
|
|
4708
|
+
const selectResult = await this.firebaseSetup.selectProject(data.projectId);
|
|
4709
|
+
if (!selectResult.success) {
|
|
4710
|
+
sendJson(selectResult);
|
|
4711
|
+
return;
|
|
4712
|
+
}
|
|
4713
|
+
const steps = [selectResult.message];
|
|
4714
|
+
try {
|
|
4715
|
+
const { apps } = await this.firebaseSetup.listWebApps();
|
|
4716
|
+
let webAppId = "";
|
|
4717
|
+
if (apps.length > 0) {
|
|
4718
|
+
webAppId = apps[0].appId;
|
|
4719
|
+
this.firebaseSetup.selectWebApp(apps[0].appId, apps[0].displayName);
|
|
4720
|
+
steps.push(`Web app "${apps[0].displayName}" selected.`);
|
|
4721
|
+
} else {
|
|
4722
|
+
const createResult = await this.firebaseSetup.createWebApp(data.projectId);
|
|
4723
|
+
if (createResult.success && createResult.appId) {
|
|
4724
|
+
webAppId = createResult.appId;
|
|
4725
|
+
steps.push(`Web app "${data.projectId}" created.`);
|
|
4726
|
+
} else {
|
|
4727
|
+
steps.push(`Web app creation skipped: ${createResult.message}`);
|
|
4728
|
+
}
|
|
4729
|
+
}
|
|
4730
|
+
if (webAppId) {
|
|
4731
|
+
try {
|
|
4732
|
+
const sdkConfig = await fetchFirebaseSdkConfig(this.options.projectDir, webAppId);
|
|
4733
|
+
const fields = {};
|
|
4734
|
+
for (const [key, value] of Object.entries(sdkConfig)) {
|
|
4735
|
+
if (value && typeof value === "string") {
|
|
4736
|
+
fields[key] = value;
|
|
4737
|
+
}
|
|
4738
|
+
}
|
|
4739
|
+
if (Object.keys(fields).length > 0) {
|
|
4740
|
+
for (const [key, value] of Object.entries(fields)) {
|
|
4741
|
+
try {
|
|
4742
|
+
this.updateProjectConfig(key, value);
|
|
4743
|
+
} catch {
|
|
4744
|
+
}
|
|
4745
|
+
}
|
|
4746
|
+
steps.push("Config auto-filled in clawfire.config.ts.");
|
|
4747
|
+
}
|
|
4748
|
+
} catch (configErr) {
|
|
4749
|
+
steps.push(`Config auto-fill skipped: ${configErr instanceof Error ? configErr.message : "unknown error"}`);
|
|
4750
|
+
}
|
|
4751
|
+
}
|
|
4752
|
+
} catch (autoFillErr) {
|
|
4753
|
+
steps.push(`Auto-setup partial: ${autoFillErr instanceof Error ? autoFillErr.message : "unknown error"}`);
|
|
4754
|
+
}
|
|
4551
4755
|
clearFirebaseStatusCache();
|
|
4552
|
-
sendJson(
|
|
4553
|
-
}).catch((err) => sendJson({ success: false, message: err instanceof Error ? err.message : "Failed" }, 500));
|
|
4756
|
+
sendJson({ success: true, message: steps.join(" "), steps });
|
|
4757
|
+
})().catch((err) => sendJson({ success: false, message: err instanceof Error ? err.message : "Failed" }, 500));
|
|
4554
4758
|
} catch {
|
|
4555
4759
|
sendJson({ success: false, message: "Invalid JSON body" }, 400);
|
|
4556
4760
|
}
|
|
@@ -4584,10 +4788,25 @@ ${liveReloadScript}
|
|
|
4584
4788
|
return;
|
|
4585
4789
|
}
|
|
4586
4790
|
if (url.pathname === "/__dev/deploy/hosting" && req.method === "POST") {
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4791
|
+
(async () => {
|
|
4792
|
+
try {
|
|
4793
|
+
if (this.pageCompiler.isActive()) {
|
|
4794
|
+
const routerScript = generateProductionRouterScript();
|
|
4795
|
+
const buildResult = this.pageCompiler.buildForProduction(this.publicDir, routerScript);
|
|
4796
|
+
console.log(` \x1B[32m\u2713\x1B[0m Built ${buildResult.pages.length} pages for production`);
|
|
4797
|
+
if (buildResult.errors.length > 0) {
|
|
4798
|
+
for (const err of buildResult.errors) {
|
|
4799
|
+
console.log(` \x1B[31m\u2717\x1B[0m ${err}`);
|
|
4800
|
+
}
|
|
4801
|
+
}
|
|
4802
|
+
}
|
|
4803
|
+
const result = await this.firebaseSetup.deployHosting();
|
|
4804
|
+
clearFirebaseStatusCache();
|
|
4805
|
+
sendJson(result);
|
|
4806
|
+
} catch (err) {
|
|
4807
|
+
sendJson({ success: false, message: err instanceof Error ? err.message : "Failed" }, 500);
|
|
4808
|
+
}
|
|
4809
|
+
})();
|
|
4591
4810
|
return;
|
|
4592
4811
|
}
|
|
4593
4812
|
if (url.pathname === "/__dev/enable-service" && req.method === "POST") {
|
|
@@ -4734,7 +4953,7 @@ ${liveReloadScript}
|
|
|
4734
4953
|
throw new Error(`Key "${key}" not found in config`);
|
|
4735
4954
|
}
|
|
4736
4955
|
content = content.replace(pattern, `$1"${value.replace(/"/g, '\\"')}"`);
|
|
4737
|
-
|
|
4956
|
+
writeFileSync4(configPath, content, "utf-8");
|
|
4738
4957
|
}
|
|
4739
4958
|
escapeRegex(s) {
|
|
4740
4959
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|